1 /*
2 * Copyright (C) 2000, Matias Atria
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <math.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28
29 #include "mdvi.h"
30 #include "private.h"
31 #include "color.h"
32
33 typedef int (*DviCommand) __PROTO((DviContext *, int));
34
35 #define DVICMDDEF(x) static int x __PROTO((DviContext *, int))
36
37 DVICMDDEF(set_char);
38 DVICMDDEF(set_rule);
39 DVICMDDEF(no_op);
40 DVICMDDEF(push);
41 DVICMDDEF(pop);
42 DVICMDDEF(move_right);
43 DVICMDDEF(move_down);
44 DVICMDDEF(move_w);
45 DVICMDDEF(move_x);
46 DVICMDDEF(move_y);
47 DVICMDDEF(move_z);
48 DVICMDDEF(sel_font);
49 DVICMDDEF(sel_fontn);
50 DVICMDDEF(special);
51 DVICMDDEF(def_font);
52 DVICMDDEF(undefined);
53 DVICMDDEF(unexpected);
54
55 static const DviCommand dvi_commands[] = {
56 set_char, set_char, set_char, set_char,
57 set_char, set_char, set_char, set_char,
58 set_char, set_char, set_char, set_char,
59 set_char, set_char, set_char, set_char,
60 set_char, set_char, set_char, set_char,
61 set_char, set_char, set_char, set_char,
62 set_char, set_char, set_char, set_char,
63 set_char, set_char, set_char, set_char,
64 set_char, set_char, set_char, set_char,
65 set_char, set_char, set_char, set_char,
66 set_char, set_char, set_char, set_char,
67 set_char, set_char, set_char, set_char,
68 set_char, set_char, set_char, set_char,
69 set_char, set_char, set_char, set_char,
70 set_char, set_char, set_char, set_char,
71 set_char, set_char, set_char, set_char,
72 set_char, set_char, set_char, set_char,
73 set_char, set_char, set_char, set_char,
74 set_char, set_char, set_char, set_char,
75 set_char, set_char, set_char, set_char,
76 set_char, set_char, set_char, set_char,
77 set_char, set_char, set_char, set_char,
78 set_char, set_char, set_char, set_char,
79 set_char, set_char, set_char, set_char,
80 set_char, set_char, set_char, set_char,
81 set_char, set_char, set_char, set_char,
82 set_char, set_char, set_char, set_char,
83 set_char, set_char, set_char, set_char,
84 set_char, set_char, set_char, set_char,
85 set_char, set_char, set_char, set_char,
86 set_char, set_char, set_char, set_char,
87 set_char, set_char, set_char, set_char, /* 0 - 127 */
88 set_char, set_char, set_char, set_char, /* 128 - 131 */
89 set_rule, /* 132 */
90 set_char, set_char, set_char, set_char, /* 133 - 136 */
91 set_rule, /* 137 */
92 no_op, /* 138 */
93 unexpected, /* 139 (BOP) */
94 unexpected, /* 140 (EOP) */
95 push, /* 141 */
96 pop, /* 142 */
97 move_right, move_right, move_right, move_right, /* 143 - 146 */
98 move_w, move_w, move_w, move_w, move_w, /* 147 - 151 */
99 move_x, move_x, move_x, move_x, move_x, /* 152 - 156 */
100 move_down, move_down, move_down, move_down, /* 157 - 160 */
101 move_y, move_y, move_y, move_y, move_y, /* 161 - 165 */
102 move_z, move_z, move_z, move_z, move_z, /* 166 - 170 */
103 sel_font, sel_font, sel_font, sel_font,
104 sel_font, sel_font, sel_font, sel_font,
105 sel_font, sel_font, sel_font, sel_font,
106 sel_font, sel_font, sel_font, sel_font,
107 sel_font, sel_font, sel_font, sel_font,
108 sel_font, sel_font, sel_font, sel_font,
109 sel_font, sel_font, sel_font, sel_font,
110 sel_font, sel_font, sel_font, sel_font,
111 sel_font, sel_font, sel_font, sel_font,
112 sel_font, sel_font, sel_font, sel_font,
113 sel_font, sel_font, sel_font, sel_font,
114 sel_font, sel_font, sel_font, sel_font,
115 sel_font, sel_font, sel_font, sel_font,
116 sel_font, sel_font, sel_font, sel_font,
117 sel_font, sel_font, sel_font, sel_font,
118 sel_font, sel_font, sel_font, sel_font, /* 171 - 234 */
119 sel_fontn, sel_fontn, sel_fontn, sel_fontn, /* 235 - 238 */
120 special, special, special, special, /* 239 - 242 */
121 def_font, def_font, def_font, def_font, /* 243 - 246 */
122 unexpected, /* 247 (PRE) */
123 unexpected, /* 248 (POST) */
124 unexpected, /* 249 (POST_POST) */
125 undefined, undefined, undefined,
126 undefined, undefined, undefined /* 250 - 255 */
127 };
128
129 #define DVI_BUFLEN 4096
130
131 static int mdvi_run_macro(DviContext *dvi, Uchar *macro, size_t len);
132
dummy_draw_glyph(DviContext * dvi,DviFontChar * ch,int x,int y)133 static void dummy_draw_glyph(DviContext *dvi, DviFontChar *ch, int x, int y)
134 {
135 }
136
dummy_draw_rule(DviContext * dvi,int x,int y,Uint w,Uint h,int f)137 static void dummy_draw_rule(DviContext *dvi, int x, int y, Uint w, Uint h, int f)
138 {
139 }
140
dummy_alloc_colors(void * a,Ulong * b,int c,Ulong d,Ulong e,double f,int g)141 static int dummy_alloc_colors(void *a, Ulong *b, int c, Ulong d, Ulong e, double f, int g)
142 {
143 return -1;
144 }
145
dummy_create_image(void * a,Uint b,Uint c,Uint d)146 static void *dummy_create_image(void *a, Uint b, Uint c, Uint d)
147 {
148 return NULL;
149 }
150
dummy_free_image(void * a)151 static void dummy_free_image(void *a)
152 {
153 }
154
dummy_dev_destroy(void * a)155 static void dummy_dev_destroy(void *a)
156 {
157 }
158
dummy_dev_putpixel(void * a,int x,int y,Ulong c)159 static void dummy_dev_putpixel(void *a, int x, int y, Ulong c)
160 {
161 }
162
dummy_dev_refresh(DviContext * a,void * b)163 static void dummy_dev_refresh(DviContext *a, void *b)
164 {
165 }
166
dummy_dev_set_color(void * a,Ulong b,Ulong c)167 static void dummy_dev_set_color(void *a, Ulong b, Ulong c)
168 {
169 }
170
171 /* functions to report errors */
172 __attribute__((__format__ (__printf__, 2, 3)))
dvierr(DviContext * dvi,const char * format,...)173 static void dvierr(DviContext *dvi, const char *format, ...)
174 {
175 va_list ap;
176
177 va_start(ap, format);
178 fprintf(stderr, "%s[%d]: Error: ",
179 dvi->filename, dvi->currpage);
180 vfprintf(stderr, format, ap);
181 va_end(ap);
182 }
183
184 __attribute__((__format__ (__printf__, 2, 3)))
dviwarn(DviContext * dvi,const char * format,...)185 static void dviwarn(DviContext *dvi, const char *format, ...)
186 {
187 va_list ap;
188
189 fprintf(stderr, "%s[%d]: Warning: ",
190 dvi->filename, dvi->currpage);
191 va_start(ap, format);
192 vfprintf(stderr, format, ap);
193 va_end(ap);
194 }
195
196 #define NEEDBYTES(d,n) \
197 ((d)->buffer.pos + (n) > (d)->buffer.length)
198
get_bytes(DviContext * dvi,size_t n)199 static int get_bytes(DviContext *dvi, size_t n)
200 {
201 /*
202 * caller wants to read `n' bytes from dvi->buffer + dvi->pos.
203 * Make sure there is enough data to satisfy the request
204 */
205 if(NEEDBYTES(dvi, n)) {
206 size_t required;
207 int newlen;
208
209 if(dvi->buffer.frozen || dvi->in == NULL || feof(dvi->in)) {
210 /* this is EOF */
211 dviwarn(dvi, _("unexpected EOF\n"));
212 return -1;
213 }
214 /* get more data */
215 if(dvi->buffer.data == NULL) {
216 /* first allocation */
217 dvi->buffer.size = Max(DVI_BUFLEN, n);
218 dvi->buffer.data = (Uchar *)mdvi_malloc(dvi->buffer.size);
219 dvi->buffer.length = 0;
220 dvi->buffer.frozen = 0;
221 } else if(dvi->buffer.pos < dvi->buffer.length) {
222 /* move whatever we want to keep */
223 dvi->buffer.length -= dvi->buffer.pos;
224 memmove(dvi->buffer.data,
225 dvi->buffer.data + dvi->buffer.pos,
226 dvi->buffer.length);
227 } else {
228 /* we can discard all the data in this buffer */
229 dvi->buffer.length = 0;
230 }
231
232 required = n - dvi->buffer.length;
233 if(required > dvi->buffer.size - dvi->buffer.length) {
234 /* need to allocate more memory */
235 dvi->buffer.size = dvi->buffer.length + required + 128;
236 dvi->buffer.data = (Uchar *)xresize(dvi->buffer.data,
237 char, dvi->buffer.size);
238 }
239 /* now read into the buffer */
240 newlen = fread(dvi->buffer.data + dvi->buffer.length,
241 1, dvi->buffer.size - dvi->buffer.length, dvi->in);
242 if(newlen == -1) {
243 mdvi_error("%s: %s\n", dvi->filename, strerror(errno));
244 return -1;
245 }
246 dvi->buffer.length += newlen;
247 dvi->buffer.pos = 0;
248 }
249 return 0;
250 }
251
252 /* only relative forward seeks are supported by this function */
dskip(DviContext * dvi,long offset)253 static int dskip(DviContext *dvi, long offset)
254 {
255 ASSERT(offset > 0);
256
257 if(NEEDBYTES(dvi, offset) && get_bytes(dvi, offset) == -1)
258 return -1;
259 dvi->buffer.pos += offset;
260 return 0;
261 }
262
263 /* DVI I/O functions (note: here `n' must be <= 4) */
dsgetn(DviContext * dvi,size_t n)264 static long dsgetn(DviContext *dvi, size_t n)
265 {
266 long val;
267
268 if(NEEDBYTES(dvi, n) && get_bytes(dvi, n) == -1)
269 return -1;
270 val = msgetn(dvi->buffer.data + dvi->buffer.pos, n);
271 dvi->buffer.pos += n;
272 return val;
273 }
274
dread(DviContext * dvi,char * buffer,size_t len)275 static int dread(DviContext *dvi, char *buffer, size_t len)
276 {
277 if(NEEDBYTES(dvi, len) && get_bytes(dvi, len) == -1)
278 return -1;
279 memcpy(buffer, dvi->buffer.data + dvi->buffer.pos, len);
280 dvi->buffer.pos += len;
281 return 0;
282 }
283
dugetn(DviContext * dvi,size_t n)284 static long dugetn(DviContext *dvi, size_t n)
285 {
286 long val;
287
288 if(NEEDBYTES(dvi, n) && get_bytes(dvi, n) == -1)
289 return -1;
290 val = mugetn(dvi->buffer.data + dvi->buffer.pos, n);
291 dvi->buffer.pos += n;
292 return val;
293 }
294
dtell(DviContext * dvi)295 static long dtell(DviContext *dvi)
296 {
297 return dvi->depth ?
298 dvi->buffer.pos :
299 ftell(dvi->in) - dvi->buffer.length + dvi->buffer.pos;
300 }
301
dreset(DviContext * dvi)302 static void dreset(DviContext *dvi)
303 {
304 if(!dvi->buffer.frozen && dvi->buffer.data)
305 mdvi_free(dvi->buffer.data);
306 dvi->buffer.data = NULL;
307 dvi->buffer.size = 0;
308 dvi->buffer.length = 0;
309 dvi->buffer.pos = 0;
310 }
311
312 #define dsget1(d) dsgetn((d), 1)
313 #define dsget2(d) dsgetn((d), 2)
314 #define dsget3(d) dsgetn((d), 3)
315 #define dsget4(d) dsgetn((d), 4)
316 #define duget1(d) dugetn((d), 1)
317 #define duget2(d) dugetn((d), 2)
318 #define duget3(d) dugetn((d), 3)
319 #define duget4(d) dugetn((d), 4)
320
321 #ifndef NODEBUG
322 __attribute__((__format__ (__printf__, 4, 5)))
dviprint(DviContext * dvi,const char * command,int sub,const char * fmt,...)323 static void dviprint(DviContext *dvi, const char *command, int sub, const char *fmt, ...)
324 {
325 int i;
326 va_list ap;
327
328 printf("%s: ", dvi->filename);
329 for(i = 0; i < dvi->depth; i++)
330 printf(" ");
331 printf("%4lu: %s", dtell(dvi), command);
332 if(sub >= 0) printf("%d", sub);
333 if(*fmt) printf(": ");
334 va_start(ap, fmt);
335 vprintf(fmt, ap);
336 va_end(ap);
337 }
338 #define SHOWCMD(x) \
339 if(_mdvi_debug_mask & DBG_OPCODE) do { dviprint x; } while(0)
340 #else
341 #define SHOWCMD(x) do { } while(0)
342 #endif
343
mdvi_find_tex_page(DviContext * dvi,int tex_page)344 int mdvi_find_tex_page(DviContext *dvi, int tex_page)
345 {
346 int i;
347
348 for(i = 0; i < dvi->npages; i++)
349 if(dvi->pagemap[i][1] == tex_page)
350 return i;
351 return -1;
352 }
353
354 /* page sorting functions */
sort_up(const void * p1,const void * p2)355 static int sort_up(const void *p1, const void *p2)
356 {
357 return ((long *)p1)[1] - ((long *)p2)[1];
358 }
sort_down(const void * p1,const void * p2)359 static int sort_down(const void *p1, const void *p2)
360 {
361 return ((long *)p2)[1] - ((long *)p1)[1];
362 }
sort_random(const void * p1,const void * p2)363 static int sort_random(const void *p1, const void *p2)
364 {
365 return (rand() % 1) ? -1 : 1;
366 }
sort_dvi_up(const void * p1,const void * p2)367 static int sort_dvi_up(const void *p1, const void *p2)
368 {
369 return ((long *)p1)[0] - ((long *)p2)[0];
370 }
sort_dvi_down(const void * p1,const void * p2)371 static int sort_dvi_down(const void *p1, const void *p2)
372 {
373 return ((long *)p1)[0] - ((long *)p2)[0];
374 }
375
mdvi_sort_pages(DviContext * dvi,DviPageSort type)376 void mdvi_sort_pages(DviContext *dvi, DviPageSort type)
377 {
378 int (*sortfunc) __PROTO((const void *, const void *));
379
380 switch(type) {
381 case MDVI_PAGE_SORT_UP:
382 sortfunc = sort_up;
383 break;
384 case MDVI_PAGE_SORT_DOWN:
385 sortfunc = sort_down;
386 break;
387 case MDVI_PAGE_SORT_RANDOM:
388 sortfunc = sort_random;
389 break;
390 case MDVI_PAGE_SORT_DVI_UP:
391 sortfunc = sort_dvi_up;
392 break;
393 case MDVI_PAGE_SORT_DVI_DOWN:
394 sortfunc = sort_dvi_down;
395 break;
396 case MDVI_PAGE_SORT_NONE:
397 default:
398 sortfunc = NULL;
399 break;
400 }
401
402 if(sortfunc)
403 qsort(dvi->pagemap, dvi->npages, sizeof(PageNum), sortfunc);
404 }
405
define_font(DviContext * dvi,int op)406 static DviFontRef *define_font(DviContext *dvi, int op)
407 {
408 Int32 arg;
409 Int32 scale;
410 Int32 dsize;
411 Int32 checksum;
412 int hdpi;
413 int vdpi;
414 int n;
415 char *name;
416 DviFontRef *ref;
417
418 arg = dugetn(dvi, op - DVI_FNT_DEF1 + 1);
419 checksum = duget4(dvi);
420 scale = duget4(dvi);
421 dsize = duget4(dvi);
422 hdpi = FROUND(dvi->params.mag * dvi->params.dpi * scale / dsize);
423 vdpi = FROUND(dvi->params.mag * dvi->params.vdpi * scale / dsize);
424 n = duget1(dvi) + duget1(dvi);
425 name = mdvi_malloc(n + 1);
426 dread(dvi, name, n);
427 name[n] = 0;
428 DEBUG((DBG_FONTS, "requesting font %d = `%s' at %.1fpt (%dx%d dpi)\n",
429 arg, name, (double)scale / (dvi->params.tfm_conv * 0x100000),
430 hdpi, vdpi));
431 ref = font_reference(&dvi->params, arg, name, checksum, hdpi, vdpi, scale);
432 if(ref == NULL) {
433 mdvi_error(_("could not load font `%s'\n"), name);
434 mdvi_free(name);
435 return NULL;
436 }
437 mdvi_free(name);
438 return ref;
439 }
440
opendvi(const char * name)441 static char *opendvi(const char *name)
442 {
443 int len;
444 char *file;
445
446 len = strlen(name);
447 /* if file ends with .dvi and it exists, that's it */
448 if(len >= 4 && STREQ(name+len-4, ".dvi")) {
449 DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", name));
450 if(access(name, R_OK) == 0)
451 return mdvi_strdup(name);
452 }
453
454 /* try appending .dvi */
455 file = mdvi_malloc(len + 5);
456 strcpy(file, name);
457 strcpy(file+len, ".dvi");
458 DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", file));
459 if(access(file, R_OK) == 0)
460 return file;
461 /* try the given name */
462 file[len] = 0;
463 DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", file));
464 if(access(file, R_OK) == 0)
465 return file;
466 mdvi_free(file);
467 return NULL;
468 }
469
mdvi_reload(DviContext * dvi,DviParams * np)470 int mdvi_reload(DviContext *dvi, DviParams *np)
471 {
472 DviContext *newdvi;
473 DviParams *pars;
474
475 /* close our file */
476 if(dvi->in) {
477 fclose(dvi->in);
478 dvi->in = NULL;
479 }
480
481 pars = np ? np : &dvi->params;
482 DEBUG((DBG_DVI, "%s: reloading\n", dvi->filename));
483
484 /* load it again */
485 newdvi = mdvi_init_context(pars, dvi->pagesel, dvi->filename);
486 if(newdvi == NULL) {
487 mdvi_warning(_("could not reload `%s'\n"), dvi->filename);
488 return -1;
489 }
490
491 /* drop all our font references */
492 font_drop_chain(dvi->fonts);
493 /* destroy our font map */
494 if(dvi->fontmap)
495 mdvi_free(dvi->fontmap);
496 dvi->currfont = NULL;
497
498 /* and use the ones we just loaded */
499 dvi->fonts = newdvi->fonts;
500 dvi->fontmap = newdvi->fontmap;
501 dvi->nfonts = newdvi->nfonts;
502
503 /* copy the new information */
504 dvi->params = newdvi->params;
505 dvi->num = newdvi->num;
506 dvi->den = newdvi->den;
507 dvi->dvimag = newdvi->dvimag;
508 dvi->dviconv = newdvi->dviconv;
509 dvi->dvivconv = newdvi->dvivconv;
510 dvi->modtime = newdvi->modtime;
511
512 if(dvi->fileid) mdvi_free(dvi->fileid);
513 dvi->fileid = newdvi->fileid;
514
515 dvi->dvi_page_w = newdvi->dvi_page_w;
516 dvi->dvi_page_h = newdvi->dvi_page_h;
517
518 mdvi_free(dvi->pagemap);
519 dvi->pagemap = newdvi->pagemap;
520 dvi->npages = newdvi->npages;
521 if(dvi->currpage > dvi->npages-1)
522 dvi->currpage = 0;
523
524 mdvi_free(dvi->stack);
525 dvi->stack = newdvi->stack;
526 dvi->stacksize = newdvi->stacksize;
527
528 /* remove fonts that are not being used anymore */
529 font_free_unused(&dvi->device);
530
531 mdvi_free(newdvi->filename);
532 mdvi_free(newdvi);
533
534 DEBUG((DBG_DVI, "%s: reload successful\n", dvi->filename));
535 if(dvi->device.refresh)
536 dvi->device.refresh(dvi, dvi->device.device_data);
537
538 return 0;
539 }
540
541 /* function to change parameters ia DVI context
542 * The DVI context is modified ONLY if this function is successful */
mdvi_configure(DviContext * dvi,DviParamCode option,...)543 int mdvi_configure(DviContext *dvi, DviParamCode option, ...)
544 {
545 va_list ap;
546 int reset_all;
547 int reset_font;
548 DviParams np;
549
550 va_start(ap, option);
551
552 reset_font = 0;
553 reset_all = 0;
554 np = dvi->params; /* structure copy */
555 while(option != MDVI_PARAM_LAST) {
556 switch(option) {
557 case MDVI_SET_DPI:
558 np.dpi = np.vdpi = va_arg(ap, Uint);
559 reset_all = 1;
560 break;
561 case MDVI_SET_XDPI:
562 np.dpi = va_arg(ap, Uint);
563 reset_all = 1;
564 break;
565 case MDVI_SET_YDPI:
566 np.vdpi = va_arg(ap, Uint);
567 break;
568 case MDVI_SET_SHRINK:
569 np.hshrink = np.vshrink = va_arg(ap, Uint);
570 reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
571 break;
572 case MDVI_SET_XSHRINK:
573 np.hshrink = va_arg(ap, Uint);
574 reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
575 break;
576 case MDVI_SET_YSHRINK:
577 np.vshrink = va_arg(ap, Uint);
578 reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
579 break;
580 case MDVI_SET_ORIENTATION:
581 np.orientation = va_arg(ap, DviOrientation);
582 reset_font = MDVI_FONTSEL_GLYPH;
583 break;
584 case MDVI_SET_GAMMA:
585 np.gamma = va_arg(ap, double);
586 reset_font = MDVI_FONTSEL_GREY;
587 break;
588 case MDVI_SET_DENSITY:
589 np.density = va_arg(ap, Uint);
590 reset_font = MDVI_FONTSEL_BITMAP;
591 break;
592 case MDVI_SET_MAGNIFICATION:
593 np.mag = va_arg(ap, double);
594 reset_all = 1;
595 break;
596 case MDVI_SET_DRIFT:
597 np.hdrift = np.vdrift = va_arg(ap, int);
598 break;
599 case MDVI_SET_HDRIFT:
600 np.hdrift = va_arg(ap, int);
601 break;
602 case MDVI_SET_VDRIFT:
603 np.vdrift = va_arg(ap, int);
604 break;
605 case MDVI_SET_FOREGROUND:
606 np.fg = va_arg(ap, Ulong);
607 reset_font = MDVI_FONTSEL_GREY;
608 break;
609 case MDVI_SET_BACKGROUND:
610 np.bg = va_arg(ap, Ulong);
611 reset_font = MDVI_FONTSEL_GREY;
612 break;
613 default:
614 break;
615 }
616 option = va_arg(ap, DviParamCode);
617 }
618 va_end(ap);
619
620 /* check that all values make sense */
621 if(np.dpi <= 0 || np.vdpi <= 0)
622 return -1;
623 if(np.mag <= 0.0)
624 return -1;
625 if(np.density < 0)
626 return -1;
627 if(np.hshrink < 1 || np.vshrink < 1)
628 return -1;
629 if(np.hdrift < 0 || np.vdrift < 0)
630 return -1;
631 if(np.fg == np.bg)
632 return -1;
633
634 /*
635 * If the dpi or the magnification change, we basically have to reload
636 * the DVI file again from scratch.
637 */
638
639 if(reset_all)
640 return (mdvi_reload(dvi, &np) == 0);
641
642 if(np.hshrink != dvi->params.hshrink) {
643 np.conv = dvi->dviconv;
644 if(np.hshrink)
645 np.conv /= np.hshrink;
646 }
647 if(np.vshrink != dvi->params.vshrink) {
648 np.vconv = dvi->dvivconv;
649 if(np.vshrink)
650 np.vconv /= np.vshrink;
651 }
652
653 if(reset_font) {
654 font_reset_chain_glyphs(&dvi->device, dvi->fonts, reset_font);
655 }
656 dvi->params = np;
657 if((reset_font & MDVI_FONTSEL_GLYPH) && dvi->device.refresh) {
658 dvi->device.refresh(dvi, dvi->device.device_data);
659 return 0;
660 }
661
662 return 1;
663 }
664 /*
665 * Read the initial data from the DVI file. If something is wrong with the
666 * file, we just spit out an error message and refuse to load the file,
667 * without giving any details. This makes sense because DVI files are ok
668 * 99.99% of the time, and dvitype(1) can be used to check the other 0.01%.
669 */
mdvi_init_context(DviParams * par,DviPageSpec * spec,const char * file)670 DviContext *mdvi_init_context(DviParams *par, DviPageSpec *spec, const char *file)
671 {
672 FILE *p;
673 Int32 arg;
674 int op;
675 long offset;
676 int n;
677 DviContext *dvi;
678 char *filename;
679 int pagecount;
680
681 /*
682 * 1. Open the file and initialize the DVI context
683 */
684
685 filename = opendvi(file);
686 if(filename == NULL) {
687 perror(file);
688 return NULL;
689 }
690 p = fopen(filename, "rb");
691 if(p == NULL) {
692 perror(file);
693 mdvi_free(filename);
694 return NULL;
695 }
696 dvi = xalloc(DviContext);
697 memzero(dvi, sizeof(DviContext));
698 dvi->pagemap = NULL;
699 dvi->filename = filename;
700 dvi->stack = NULL;
701 dvi->modtime = get_mtime(fileno(p));
702 dvi->buffer.data = NULL;
703 dvi->pagesel = spec;
704 dvi->in = p; /* now we can use the dget*() functions */
705
706 /*
707 * 2. Read the preamble, extract scaling information, and
708 * setup the DVI parameters.
709 */
710
711 if(fuget1(p) != DVI_PRE)
712 goto bad_dvi;
713 if((arg = fuget1(p)) != DVI_ID) {
714 mdvi_error(_("%s: unsupported DVI format (version %u)\n"),
715 file, arg);
716 goto error; /* jump to the end of this routine,
717 * where we handle errors */
718 }
719 /* get dimensions */
720 dvi->num = fuget4(p);
721 dvi->den = fuget4(p);
722 dvi->dvimag = fuget4(p);
723
724 /* check that these numbers make sense */
725 if(!dvi->num || !dvi->den || !dvi->dvimag)
726 goto bad_dvi;
727
728 dvi->params.mag =
729 (par->mag > 0 ? par->mag : (double)dvi->dvimag / 1000.0);
730 dvi->params.hdrift = par->hdrift;
731 dvi->params.vdrift = par->vdrift;
732 dvi->params.dpi = par->dpi ? par->dpi : MDVI_DPI;
733 dvi->params.vdpi = par->vdpi ? par->vdpi : par->dpi;
734 dvi->params.hshrink = par->hshrink;
735 dvi->params.vshrink = par->vshrink;
736 dvi->params.density = par->density;
737 dvi->params.gamma = par->gamma;
738 dvi->params.conv = (double)dvi->num / dvi->den;
739 dvi->params.conv *= (dvi->params.dpi / 254000.0) * dvi->params.mag;
740 dvi->params.vconv = (double)dvi->num / dvi->den;
741 dvi->params.vconv *= (dvi->params.vdpi / 254000.0) * dvi->params.mag;
742 dvi->params.tfm_conv = (25400000.0 / dvi->num) *
743 ((double)dvi->den / 473628672) / 16.0;
744 dvi->params.flags = par->flags;
745 dvi->params.orientation = par->orientation;
746 dvi->params.fg = par->fg;
747 dvi->params.bg = par->bg;
748
749 /* initialize colors */
750 dvi->curr_fg = par->fg;
751 dvi->curr_bg = par->bg;
752 dvi->color_stack = NULL;
753 dvi->color_top = 0;
754 dvi->color_size = 0;
755
756 /* pixel conversion factors */
757 dvi->dviconv = dvi->params.conv;
758 dvi->dvivconv = dvi->params.vconv;
759 if(dvi->params.hshrink)
760 dvi->params.conv /= dvi->params.hshrink;
761 if(dvi->params.vshrink)
762 dvi->params.vconv /= dvi->params.vshrink;
763
764 /* get the comment from the preamble */
765 n = fuget1(p);
766 dvi->fileid = mdvi_malloc(n + 1);
767 fread(dvi->fileid, 1, n, p);
768 dvi->fileid[n] = 0;
769 DEBUG((DBG_DVI, "%s: %s\n", filename, dvi->fileid));
770
771 /*
772 * 3. Read postamble, extract page information (number of
773 * pages, dimensions) and stack depth.
774 */
775
776 /* jump to the end of the file */
777 if(fseek(p, (long)-1, SEEK_END) == -1)
778 goto error;
779 for(n = 0; (op = fuget1(p)) == DVI_TRAILER; n++)
780 if(fseek(p, (long)-2, SEEK_CUR) < 0)
781 break;
782 if(op != arg || n < 4)
783 goto bad_dvi;
784 /* get the pointer to postamble */
785 fseek(p, (long)-5, SEEK_CUR);
786 arg = fuget4(p);
787 /* jump to it */
788 fseek(p, (long)arg, SEEK_SET);
789 if(fuget1(p) != DVI_POST)
790 goto bad_dvi;
791 offset = fuget4(p);
792 if(dvi->num != fuget4(p) || dvi->den != fuget4(p) ||
793 dvi->dvimag != fuget4(p))
794 goto bad_dvi;
795 dvi->dvi_page_h = fuget4(p);
796 dvi->dvi_page_w = fuget4(p);
797 dvi->stacksize = fuget2(p);
798 dvi->npages = fuget2(p);
799 DEBUG((DBG_DVI, "%s: from postamble: stack depth %d, %d page%s\n",
800 filename, dvi->stacksize, dvi->npages, dvi->npages > 1 ? "s" : ""));
801
802 /*
803 * 4. Process font definitions.
804 */
805
806 /* process font definitions */
807 dvi->nfonts = 0;
808 dvi->fontmap = NULL;
809 /*
810 * CAREFUL: here we need to use the dvi->buffer, but it might leave the
811 * the file cursor in the wrong position after reading fonts (because of
812 * buffering). It's ok, though, because after the font definitions we read
813 * the page offsets, and we fseek() to the relevant part of the file with
814 * SEEK_SET. Nothing is read after the page offsets.
815 */
816 while((op = duget1(dvi)) != DVI_POST_POST) {
817 DviFontRef *ref;
818
819 if(op == DVI_NOOP)
820 continue;
821 else if(op < DVI_FNT_DEF1 || op > DVI_FNT_DEF4)
822 goto error;
823 ref = define_font(dvi, op);
824 if(ref == NULL)
825 goto error;
826 ref->next = dvi->fonts;
827 dvi->fonts = ref;
828 dvi->nfonts++;
829 }
830 /* we don't need the buffer anymore */
831 dreset(dvi);
832
833 if(op != DVI_POST_POST)
834 goto bad_dvi;
835 font_finish_definitions(dvi);
836 DEBUG((DBG_DVI, "%s: %d font%s required by this job\n",
837 filename, dvi->nfonts, dvi->nfonts > 1 ? "s" : ""));
838 dvi->findref = font_find_mapped;
839
840 /*
841 * 5. Build the page map.
842 */
843
844 dvi->pagemap = xnalloc(PageNum, dvi->npages);
845 memzero(dvi->pagemap, sizeof(PageNum) * dvi->npages);
846
847 n = dvi->npages - 1;
848 pagecount = n;
849 while(offset != -1) {
850 int i;
851 PageNum page;
852
853 fseek(p, offset, SEEK_SET);
854 op = fuget1(p);
855 if(op != DVI_BOP || n < 0)
856 goto bad_dvi;
857 for(i = 1; i <= 10; i++)
858 page[i] = fsget4(p);
859 page[0] = offset;
860 offset = fsget4(p);
861 /* check if the page is selected */
862 if(spec && mdvi_page_selected(spec, page, n) == 0) {
863 DEBUG((DBG_DVI, "Page %d (%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld) ignored by request\n",
864 n, page[1], page[2], page[3], page[4], page[5],
865 page[6], page[7], page[8], page[9], page[10]));
866 } else {
867 memcpy(&dvi->pagemap[pagecount], page, sizeof(PageNum));
868 pagecount--;
869 }
870 n--;
871 }
872 pagecount++;
873 if(pagecount >= dvi->npages) {
874 mdvi_error(_("no pages selected\n"));
875 goto error;
876 }
877 if(pagecount) {
878 DEBUG((DBG_DVI, "%d of %d pages selected\n",
879 dvi->npages - pagecount, dvi->npages));
880 dvi->npages -= pagecount;
881 memmove(dvi->pagemap, &dvi->pagemap[pagecount],
882 dvi->npages * sizeof(PageNum));
883 }
884
885 /*
886 * 6. Setup stack, initialize device functions
887 */
888
889 dvi->curr_layer = 0;
890 dvi->stack = xnalloc(DviState, dvi->stacksize + 8);
891
892 dvi->device.draw_glyph = dummy_draw_glyph;
893 dvi->device.draw_rule = dummy_draw_rule;
894 dvi->device.alloc_colors = dummy_alloc_colors;
895 dvi->device.create_image = dummy_create_image;
896 dvi->device.free_image = dummy_free_image;
897 dvi->device.dev_destroy = dummy_dev_destroy;
898 dvi->device.put_pixel = dummy_dev_putpixel;
899 dvi->device.refresh = dummy_dev_refresh;
900 dvi->device.set_color = dummy_dev_set_color;
901 dvi->device.device_data = NULL;
902
903 DEBUG((DBG_DVI, "%s read successfully\n", filename));
904 return dvi;
905
906 bad_dvi:
907 mdvi_error(_("%s: File corrupted, or not a DVI file\n"), file);
908 error:
909 /* if we came from the font definitions, this will be non-trivial */
910 dreset(dvi);
911 mdvi_destroy_context(dvi);
912 return NULL;
913 }
914
mdvi_destroy_context(DviContext * dvi)915 void mdvi_destroy_context(DviContext *dvi)
916 {
917 if(dvi->device.dev_destroy)
918 dvi->device.dev_destroy(dvi->device.device_data);
919 /* release all fonts */
920 if(dvi->fonts) {
921 font_drop_chain(dvi->fonts);
922 font_free_unused(&dvi->device);
923 }
924 if(dvi->fontmap)
925 mdvi_free(dvi->fontmap);
926 if(dvi->filename)
927 mdvi_free(dvi->filename);
928 if(dvi->stack)
929 mdvi_free(dvi->stack);
930 if(dvi->pagemap)
931 mdvi_free(dvi->pagemap);
932 if(dvi->fileid)
933 mdvi_free(dvi->fileid);
934 if(dvi->in)
935 fclose(dvi->in);
936 if(dvi->buffer.data && !dvi->buffer.frozen)
937 mdvi_free(dvi->buffer.data);
938 if(dvi->color_stack)
939 mdvi_free(dvi->color_stack);
940
941 mdvi_free(dvi);
942 }
943
mdvi_setpage(DviContext * dvi,int pageno)944 void mdvi_setpage(DviContext *dvi, int pageno)
945 {
946 if(pageno < 0)
947 pageno = 0;
948 if(pageno > dvi->npages-1)
949 pageno = dvi->npages - 1;
950 dvi->currpage = pageno;
951 }
952
mdvi_run_macro(DviContext * dvi,Uchar * macro,size_t len)953 static int mdvi_run_macro(DviContext *dvi, Uchar *macro, size_t len)
954 {
955 DviFontRef *curr, *fonts;
956 DviBuffer saved_buffer;
957 FILE *saved_file;
958 int opcode;
959 int oldtop;
960
961 dvi->depth++;
962 push(dvi, DVI_PUSH);
963 dvi->pos.w = 0;
964 dvi->pos.x = 0;
965 dvi->pos.y = 0;
966 dvi->pos.z = 0;
967
968 /* save our state */
969 curr = dvi->currfont;
970 fonts = dvi->fonts;
971 saved_buffer = dvi->buffer;
972 saved_file = dvi->in;
973 dvi->currfont = curr->ref->subfonts;
974 dvi->fonts = curr->ref->subfonts;
975 dvi->buffer.data = macro;
976 dvi->buffer.pos = 0;
977 dvi->buffer.length = len;
978 dvi->buffer.frozen = 1;
979 dvi->in = NULL;
980 oldtop = dvi->stacktop;
981
982 /* execute commands */
983 while((opcode = duget1(dvi)) != DVI_EOP) {
984 if(dvi_commands[opcode](dvi, opcode) < 0)
985 break;
986 }
987 if(opcode != DVI_EOP)
988 dviwarn(dvi, _("%s: vf macro had errors\n"),
989 curr->ref->fontname);
990 if(dvi->stacktop != oldtop)
991 dviwarn(dvi, _("%s: stack not empty after vf macro\n"),
992 curr->ref->fontname);
993
994 /* restore things */
995 pop(dvi, DVI_POP);
996 dvi->currfont = curr;
997 dvi->fonts = fonts;
998 dvi->buffer = saved_buffer;
999 dvi->in = saved_file;
1000 dvi->depth--;
1001
1002 return (opcode != DVI_EOP ? -1 : 0);
1003 }
1004
mdvi_dopage(DviContext * dvi,int pageno)1005 int mdvi_dopage(DviContext *dvi, int pageno)
1006 {
1007 int op;
1008 int ppi;
1009 int reloaded = 0;
1010
1011 again:
1012 if(dvi->in == NULL) {
1013 /* try reopening the file */
1014 dvi->in = fopen(dvi->filename, "rb");
1015 if(dvi->in == NULL) {
1016 mdvi_warning(_("%s: could not reopen file (%s)\n"),
1017 dvi->filename,
1018 strerror(errno));
1019 return -1;
1020 }
1021 DEBUG((DBG_FILES, "reopen(%s) -> Ok\n", dvi->filename));
1022 }
1023
1024 /* check if we need to reload the file */
1025 if(!reloaded && get_mtime(fileno(dvi->in)) > dvi->modtime) {
1026 mdvi_reload(dvi, &dvi->params);
1027 /* we have to reopen the file, again */
1028 reloaded = 1;
1029 goto again;
1030 }
1031
1032 if(pageno < 0 || pageno > dvi->npages-1) {
1033 mdvi_error(_("%s: page %d out of range\n"),
1034 dvi->filename, pageno);
1035 return -1;
1036 }
1037
1038 fseek(dvi->in, (long)dvi->pagemap[pageno][0], SEEK_SET);
1039 if((op = fuget1(dvi->in)) != DVI_BOP) {
1040 mdvi_error(_("%s: bad offset at page %d\n"),
1041 dvi->filename, pageno+1);
1042 return -1;
1043 }
1044
1045 /* skip bop */
1046 fseek(dvi->in, (long)44, SEEK_CUR);
1047
1048 /* reset state */
1049 dvi->currfont = NULL;
1050 memzero(&dvi->pos, sizeof(DviState));
1051 dvi->stacktop = 0;
1052 dvi->currpage = pageno;
1053 dvi->curr_layer = 0;
1054
1055 if(dvi->buffer.data && !dvi->buffer.frozen)
1056 mdvi_free(dvi->buffer.data);
1057
1058 /* reset our buffer */
1059 dvi->buffer.data = NULL;
1060 dvi->buffer.length = 0;
1061 dvi->buffer.pos = 0;
1062 dvi->buffer.frozen = 0;
1063
1064 #if 0 /* make colors survive page breaks */
1065 /* reset color stack */
1066 mdvi_reset_color(dvi);
1067 #endif
1068
1069 /* set max horizontal and vertical drift (from dvips) */
1070 if(dvi->params.hdrift < 0) {
1071 ppi = dvi->params.dpi / dvi->params.hshrink; /* shrunk pixels per inch */
1072 if(ppi < 600)
1073 dvi->params.hdrift = ppi / 100;
1074 else if(ppi < 1200)
1075 dvi->params.hdrift = ppi / 200;
1076 else
1077 dvi->params.hdrift = ppi / 400;
1078 }
1079 if(dvi->params.vdrift < 0) {
1080 ppi = dvi->params.vdpi / dvi->params.vshrink; /* shrunk pixels per inch */
1081 if(ppi < 600)
1082 dvi->params.vdrift = ppi / 100;
1083 else if(ppi < 1200)
1084 dvi->params.vdrift = ppi / 200;
1085 else
1086 dvi->params.vdrift = ppi / 400;
1087 }
1088
1089 dvi->params.thinsp = FROUND(0.025 * dvi->params.dpi / dvi->params.conv);
1090 dvi->params.vsmallsp = FROUND(0.025 * dvi->params.vdpi / dvi->params.vconv);
1091
1092 /* execute all the commands in the page */
1093 while((op = duget1(dvi)) != DVI_EOP) {
1094 if(dvi_commands[op](dvi, op) < 0)
1095 break;
1096 }
1097
1098 fflush(stdout);
1099 fflush(stderr);
1100 if(op != DVI_EOP)
1101 return -1;
1102 if(dvi->stacktop)
1103 dviwarn(dvi, _("stack not empty at end of page\n"));
1104 return 0;
1105 }
1106
move_vertical(DviContext * dvi,int amount)1107 static int inline move_vertical(DviContext *dvi, int amount)
1108 {
1109 int rvv;
1110
1111 dvi->pos.v += amount;
1112 rvv = vpixel_round(dvi, dvi->pos.v);
1113 if(!dvi->params.vdrift)
1114 return rvv;
1115 if(amount > dvi->params.vsmallsp || amount <= -dvi->params.vsmallsp)
1116 return rvv;
1117 else {
1118 int newvv;
1119
1120 newvv = dvi->pos.vv + vpixel_round(dvi, amount);
1121 if(rvv - newvv > dvi->params.vdrift)
1122 return rvv - dvi->params.vdrift;
1123 else if(newvv - rvv > dvi->params.vdrift)
1124 return rvv + dvi->params.vdrift;
1125 else
1126 return newvv;
1127 }
1128 }
1129
move_horizontal(DviContext * dvi,int amount)1130 static int inline move_horizontal(DviContext *dvi, int amount)
1131 {
1132 int rhh;
1133
1134 dvi->pos.h += amount;
1135 rhh = pixel_round(dvi, dvi->pos.h);
1136 if(!dvi->params.hdrift)
1137 return rhh;
1138 else if(amount > dvi->params.thinsp || amount <= -6 * dvi->params.thinsp)
1139 return rhh;
1140 else {
1141 int newhh;
1142
1143 newhh = dvi->pos.hh + pixel_round(dvi, amount);
1144 if(rhh - newhh > dvi->params.hdrift)
1145 return rhh - dvi->params.hdrift;
1146 else if(newhh - rhh > dvi->params.hdrift)
1147 return rhh + dvi->params.hdrift;
1148 else
1149 return newhh;
1150 }
1151 }
1152
fix_after_horizontal(DviContext * dvi)1153 static void inline fix_after_horizontal(DviContext *dvi)
1154 {
1155 int rhh;
1156
1157 rhh = pixel_round(dvi, dvi->pos.h);
1158 if(!dvi->params.hdrift)
1159 dvi->pos.hh = rhh;
1160 else if(rhh - dvi->pos.hh > dvi->params.hdrift)
1161 dvi->pos.hh = rhh - dvi->params.hdrift;
1162 else if(dvi->pos.hh - rhh > dvi->params.hdrift)
1163 dvi->pos.hh = rhh + dvi->params.hdrift;
1164 }
1165
1166 /* commands */
1167
1168 #define DBGSUM(a,b,c) \
1169 (a), (b) > 0 ? '+' : '-', \
1170 (b) > 0 ? (b) : -(b), (c)
1171
draw_shrink_rule(DviContext * dvi,int x,int y,Uint w,Uint h,int f)1172 static void draw_shrink_rule (DviContext *dvi, int x, int y, Uint w, Uint h, int f)
1173 {
1174 Ulong fg, bg;
1175
1176 fg = dvi->curr_fg;
1177 bg = dvi->curr_bg;
1178
1179 mdvi_push_color (dvi, fg, bg);
1180 dvi->device.draw_rule(dvi, x, y, w, h, f);
1181 mdvi_pop_color (dvi);
1182
1183 return;
1184 }
1185
1186 /*
1187 * The only commands that actually draw something are:
1188 * set_char, set_rule
1189 */
1190
draw_box(DviContext * dvi,DviFontChar * ch)1191 static void draw_box(DviContext *dvi, DviFontChar *ch)
1192 {
1193 DviGlyph *glyph = NULL;
1194 int x, y, w, h;
1195
1196 if(!MDVI_GLYPH_UNSET(ch->shrunk.data))
1197 glyph = &ch->shrunk;
1198 else if(!MDVI_GLYPH_UNSET(ch->grey.data))
1199 glyph = &ch->grey;
1200 else if(!MDVI_GLYPH_UNSET(ch->glyph.data))
1201 glyph = &ch->glyph;
1202 if(glyph == NULL)
1203 return;
1204 x = glyph->x;
1205 y = glyph->y;
1206 w = glyph->w;
1207 h = glyph->h;
1208 /* this is bad -- we have to undo the orientation */
1209 switch(dvi->params.orientation) {
1210 case MDVI_ORIENT_TBLR:
1211 break;
1212 case MDVI_ORIENT_TBRL:
1213 x = w - x;
1214 break;
1215 case MDVI_ORIENT_BTLR:
1216 y = h - y;
1217 break;
1218 case MDVI_ORIENT_BTRL:
1219 x = w - x;
1220 y = h - y;
1221 break;
1222 case MDVI_ORIENT_RP90:
1223 SWAPINT(w, h);
1224 SWAPINT(x, y);
1225 x = w - x;
1226 break;
1227 case MDVI_ORIENT_RM90:
1228 SWAPINT(w, h);
1229 SWAPINT(x, y);
1230 y = h - y;
1231 break;
1232 case MDVI_ORIENT_IRP90:
1233 SWAPINT(w, h);
1234 SWAPINT(x, y);
1235 break;
1236 case MDVI_ORIENT_IRM90:
1237 SWAPINT(w, h);
1238 SWAPINT(x, y);
1239 x = w - x;
1240 y = h - y;
1241 break;
1242 }
1243
1244 draw_shrink_rule(dvi, dvi->pos.hh - x, dvi->pos.vv - y, w, h, 1);
1245 }
1246
set_char(DviContext * dvi,int opcode)1247 int set_char(DviContext *dvi, int opcode)
1248 {
1249 int num;
1250 int h;
1251 int hh;
1252 DviFontChar *ch;
1253 DviFont *font;
1254
1255 if(opcode < 128)
1256 num = opcode;
1257 else
1258 num = dugetn(dvi, opcode - DVI_SET1 + 1);
1259 if(dvi->currfont == NULL) {
1260 dvierr(dvi, _("no default font set yet\n"));
1261 return -1;
1262 }
1263 font = dvi->currfont->ref;
1264 ch = font_get_glyph(dvi, font, num);
1265 if(ch == NULL || ch->missing) {
1266 /* try to display something anyway */
1267 ch = FONTCHAR(font, num);
1268 if(!glyph_present(ch)) {
1269 dviwarn(dvi,
1270 _("requested character %d does not exist in `%s'\n"),
1271 num, font->fontname);
1272 return 0;
1273 }
1274 draw_box(dvi, ch);
1275 } else if(dvi->curr_layer <= dvi->params.layer) {
1276 if(ISVIRTUAL(font))
1277 mdvi_run_macro(dvi, (Uchar *)font->private +
1278 ch->offset, ch->width);
1279 else if(ch->width && ch->height)
1280 dvi->device.draw_glyph(dvi, ch,
1281 dvi->pos.hh, dvi->pos.vv);
1282 }
1283 if(opcode >= DVI_PUT1 && opcode <= DVI_PUT4) {
1284 SHOWCMD((dvi, "putchar", opcode - DVI_PUT1 + 1,
1285 "char %d (%s)\n",
1286 num, dvi->currfont->ref->fontname));
1287 } else {
1288 h = dvi->pos.h + ch->tfmwidth;
1289 hh = dvi->pos.hh + pixel_round(dvi, ch->tfmwidth);
1290 SHOWCMD((dvi, "setchar", num, "(%d,%d) h:=%d%c%ld=%d, hh:=%d (%s)\n",
1291 dvi->pos.hh, dvi->pos.vv,
1292 DBGSUM(dvi->pos.h, (long) ch->tfmwidth, h), hh,
1293 font->fontname));
1294 dvi->pos.h = h;
1295 dvi->pos.hh = hh;
1296 fix_after_horizontal(dvi);
1297 }
1298
1299 return 0;
1300 }
1301
set_rule(DviContext * dvi,int opcode)1302 int set_rule(DviContext *dvi, int opcode)
1303 {
1304 Int32 a, b;
1305 int h, w;
1306
1307 a = dsget4(dvi);
1308 b = dsget4(dvi); w = rule_round(dvi, b);
1309 if(a > 0 && b > 0) {
1310 h = vrule_round(dvi, a);
1311 SHOWCMD((dvi, opcode == DVI_SET_RULE ? "setrule" : "putrule", -1,
1312 "width %ld, height %ld (%dx%d pixels)\n",
1313 (long) b, (long) a, w, h));
1314 /* the `draw' functions expect the origin to be at the top left
1315 * corner of the rule, not the bottom left, as in DVI files */
1316 if(dvi->curr_layer <= dvi->params.layer) {
1317 draw_shrink_rule(dvi,
1318 dvi->pos.hh, dvi->pos.vv - h + 1, w, h, 1);
1319 }
1320 } else {
1321 SHOWCMD((dvi, opcode == DVI_SET_RULE ? "setrule" : "putrule", -1,
1322 "(moving left only, by %ld)\n", (long) b));
1323 }
1324
1325 if(opcode == DVI_SET_RULE) {
1326 dvi->pos.h += b;
1327 dvi->pos.hh += w;
1328 fix_after_horizontal(dvi);
1329 }
1330 return 0;
1331 }
1332
no_op(DviContext * dvi,int opcode)1333 int no_op(DviContext *dvi, int opcode)
1334 {
1335 SHOWCMD((dvi, "noop", -1, "\n"));
1336 return 0;
1337 }
1338
push(DviContext * dvi,int opcode)1339 int push(DviContext *dvi, int opcode)
1340 {
1341 if(dvi->stacktop == dvi->stacksize) {
1342 if(!dvi->depth)
1343 dviwarn(dvi, _("enlarging stack\n"));
1344 dvi->stacksize += 8;
1345 dvi->stack = xresize(dvi->stack,
1346 DviState, dvi->stacksize);
1347 }
1348 memcpy(&dvi->stack[dvi->stacktop], &dvi->pos, sizeof(DviState));
1349 SHOWCMD((dvi, "push", -1,
1350 "level %d: (h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)\n",
1351 dvi->stacktop,
1352 dvi->pos.h, dvi->pos.v, dvi->pos.w, dvi->pos.x,
1353 dvi->pos.y, dvi->pos.z, dvi->pos.hh, dvi->pos.vv));
1354 dvi->stacktop++;
1355 return 0;
1356 }
1357
pop(DviContext * dvi,int opcode)1358 int pop(DviContext *dvi, int opcode)
1359 {
1360 if(dvi->stacktop == 0) {
1361 dvierr(dvi, _("stack underflow\n"));
1362 return -1;
1363 }
1364 memcpy(&dvi->pos, &dvi->stack[dvi->stacktop-1], sizeof(DviState));
1365 SHOWCMD((dvi, "pop", -1,
1366 "level %d: (h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)\n",
1367 dvi->stacktop,
1368 dvi->pos.h, dvi->pos.v, dvi->pos.w, dvi->pos.x,
1369 dvi->pos.y, dvi->pos.z, dvi->pos.hh, dvi->pos.vv));
1370 dvi->stacktop--;
1371 return 0;
1372 }
1373
move_right(DviContext * dvi,int opcode)1374 int move_right(DviContext *dvi, int opcode)
1375 {
1376 Int32 arg;
1377 int h, hh;
1378
1379 arg = dsgetn(dvi, opcode - DVI_RIGHT1 + 1);
1380 h = dvi->pos.h;
1381 hh = move_horizontal(dvi, arg);
1382 SHOWCMD((dvi, "right", opcode - DVI_RIGHT1 + 1,
1383 "%ld h:=%d%c%ld=%d, hh:=%d\n",
1384 (long) arg, DBGSUM(h, (long) arg, dvi->pos.h), hh));
1385 dvi->pos.hh = hh;
1386 return 0;
1387 }
1388
move_down(DviContext * dvi,int opcode)1389 int move_down(DviContext *dvi, int opcode)
1390 {
1391 Int32 arg;
1392 int v, vv;
1393
1394 arg = dsgetn(dvi, opcode - DVI_DOWN1 + 1);
1395 v = dvi->pos.v;
1396 vv = move_vertical(dvi, arg);
1397 SHOWCMD((dvi, "down", opcode - DVI_DOWN1 + 1,
1398 "%ld v:=%d%c%ld=%d, vv:=%d\n",
1399 (long) arg, DBGSUM(v, (long) arg, dvi->pos.v), vv));
1400 dvi->pos.vv = vv;
1401 return 0;
1402 }
1403
move_w(DviContext * dvi,int opcode)1404 int move_w(DviContext *dvi, int opcode)
1405 {
1406 int h, hh;
1407
1408 if(opcode != DVI_W0)
1409 dvi->pos.w = dsgetn(dvi, opcode - DVI_W0);
1410 h = dvi->pos.h;
1411 hh = move_horizontal(dvi, dvi->pos.w);
1412 SHOWCMD((dvi, "w", opcode - DVI_W0,
1413 "%d h:=%d%c%d=%d, hh:=%d\n",
1414 dvi->pos.w, DBGSUM(h, dvi->pos.w, dvi->pos.h), hh));
1415 dvi->pos.hh = hh;
1416 return 0;
1417 }
1418
move_x(DviContext * dvi,int opcode)1419 int move_x(DviContext *dvi, int opcode)
1420 {
1421 int h, hh;
1422
1423 if(opcode != DVI_X0)
1424 dvi->pos.x = dsgetn(dvi, opcode - DVI_X0);
1425 h = dvi->pos.h;
1426 hh = move_horizontal(dvi, dvi->pos.x);
1427 SHOWCMD((dvi, "x", opcode - DVI_X0,
1428 "%d h:=%d%c%d=%d, hh:=%d\n",
1429 dvi->pos.x, DBGSUM(h, dvi->pos.x, dvi->pos.h), hh));
1430 dvi->pos.hh = hh;
1431 return 0;
1432 }
1433
move_y(DviContext * dvi,int opcode)1434 int move_y(DviContext *dvi, int opcode)
1435 {
1436 int v, vv;
1437
1438 if(opcode != DVI_Y0)
1439 dvi->pos.y = dsgetn(dvi, opcode - DVI_Y0);
1440 v = dvi->pos.v;
1441 vv = move_vertical(dvi, dvi->pos.y);
1442 SHOWCMD((dvi, "y", opcode - DVI_Y0,
1443 "%d h:=%d%c%d=%d, hh:=%d\n",
1444 dvi->pos.y, DBGSUM(v, dvi->pos.y, dvi->pos.v), vv));
1445 dvi->pos.vv = vv;
1446 return 0;
1447 }
1448
move_z(DviContext * dvi,int opcode)1449 int move_z(DviContext *dvi, int opcode)
1450 {
1451 int v, vv;
1452
1453 if(opcode != DVI_Z0)
1454 dvi->pos.z = dsgetn(dvi, opcode - DVI_Z0);
1455 v = dvi->pos.v;
1456 vv = move_vertical(dvi, dvi->pos.z);
1457 SHOWCMD((dvi, "z", opcode - DVI_Z0,
1458 "%d h:=%d%c%d=%d, hh:=%d\n",
1459 dvi->pos.z, DBGSUM(v, dvi->pos.z, dvi->pos.v), vv));
1460 dvi->pos.vv = vv;
1461 return 0;
1462 }
1463
sel_font(DviContext * dvi,int opcode)1464 int sel_font(DviContext *dvi, int opcode)
1465 {
1466 DviFontRef *ref;
1467 int ndx;
1468
1469 ndx = opcode - DVI_FNT_NUM0;
1470 if(dvi->depth)
1471 ref = font_find_flat(dvi, ndx);
1472 else
1473 ref = dvi->findref(dvi, ndx);
1474 if(ref == NULL) {
1475 dvierr(dvi, _("font %d is not defined\n"),
1476 opcode - DVI_FNT_NUM0);
1477 return -1;
1478 }
1479 SHOWCMD((dvi, "fntnum", opcode - DVI_FNT_NUM0,
1480 "current font is %s\n",
1481 ref->ref->fontname));
1482 dvi->currfont = ref;
1483 return 0;
1484 }
1485
sel_fontn(DviContext * dvi,int opcode)1486 int sel_fontn(DviContext *dvi, int opcode)
1487 {
1488 Int32 arg;
1489 DviFontRef *ref;
1490
1491 arg = dugetn(dvi, opcode - DVI_FNT1 + 1);
1492 if(dvi->depth)
1493 ref = font_find_flat(dvi, arg);
1494 else
1495 ref = dvi->findref(dvi, arg);
1496 if(ref == NULL) {
1497 dvierr(dvi, _("font %ld is not defined\n"), (long) arg);
1498 return -1;
1499 }
1500 SHOWCMD((dvi, "fnt", opcode - DVI_FNT1 + 1,
1501 "current font is %s (id %ld)\n",
1502 ref->ref->fontname, (long) arg));
1503 dvi->currfont = ref;
1504 return 0;
1505 }
1506
special(DviContext * dvi,int opcode)1507 int special(DviContext *dvi, int opcode)
1508 {
1509 char *s;
1510 Int32 arg;
1511
1512 arg = dugetn(dvi, opcode - DVI_XXX1 + 1);
1513 if (arg <= 0) {
1514 dvierr(dvi, _("malformed special length\n"));
1515 return -1;
1516 }
1517 s = mdvi_malloc(arg + 1);
1518 dread(dvi, s, arg);
1519 s[arg] = 0;
1520 mdvi_do_special(dvi, s);
1521 SHOWCMD((dvi, "XXXX", opcode - DVI_XXX1 + 1,
1522 "[%s]", s));
1523 mdvi_free(s);
1524 return 0;
1525 }
1526
def_font(DviContext * dvi,int opcode)1527 int def_font(DviContext *dvi, int opcode)
1528 {
1529 DviFontRef *ref;
1530 Int32 arg;
1531
1532 arg = dugetn(dvi, opcode - DVI_FNT_DEF1 + 1);
1533 if(dvi->depth)
1534 ref = font_find_flat(dvi, arg);
1535 else
1536 ref = dvi->findref(dvi, arg);
1537 /* skip the rest */
1538 dskip(dvi, 12);
1539 dskip(dvi, duget1(dvi) + duget1(dvi));
1540 if(ref == NULL) {
1541 dvierr(dvi, _("font %ld is not defined in postamble\n"), (long) arg);
1542 return -1;
1543 }
1544 SHOWCMD((dvi, "fntdef", opcode - DVI_FNT_DEF1 + 1,
1545 "%ld -> %s (%d links)\n",
1546 (long) ref->fontid, ref->ref->fontname,
1547 ref->ref->links));
1548 return 0;
1549 }
1550
unexpected(DviContext * dvi,int opcode)1551 int unexpected(DviContext *dvi, int opcode)
1552 {
1553 dvierr(dvi, _("unexpected opcode %d\n"), opcode);
1554 return -1;
1555 }
1556
undefined(DviContext * dvi,int opcode)1557 int undefined(DviContext *dvi, int opcode)
1558 {
1559 dvierr(dvi, _("undefined opcode %d\n"), opcode);
1560 return -1;
1561 }
1562
1563