2 * Copyright (C) 2000, Matias Atria
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 typedef int (*DviCommand) __PROTO((DviContext *, int));
35 #define DVICMDDEF(x) static int x __PROTO((DviContext *, int))
42 DVICMDDEF(move_right);
53 DVICMDDEF(unexpected);
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 */
90 set_char, set_char, set_char, set_char, /* 133 - 136 */
93 unexpected, /* 139 (BOP) */
94 unexpected, /* 140 (EOP) */
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 */
129 #define DVI_BUFLEN 4096
131 static int mdvi_run_macro(DviContext *dvi, Uchar *macro, size_t len);
133 static void dummy_draw_glyph(DviContext *dvi, DviFontChar *ch, int x, int y)
137 static void dummy_draw_rule(DviContext *dvi, int x, int y, Uint w, Uint h, int f)
141 static int dummy_alloc_colors(void *a, Ulong *b, int c, Ulong d, Ulong e, double f, int g)
146 static void *dummy_create_image(void *a, Uint b, Uint c, Uint d)
151 static void dummy_free_image(void *a)
155 static void dummy_dev_destroy(void *a)
159 static void dummy_dev_putpixel(void *a, int x, int y, Ulong c)
163 static void dummy_dev_refresh(DviContext *a, void *b)
167 static void dummy_dev_set_color(void *a, Ulong b, Ulong c)
171 /* functions to report errors */
172 static void dvierr(DviContext *dvi, const char *format, ...)
176 va_start(ap, format);
177 fprintf(stderr, "%s[%d]: Error: ",
178 dvi->filename, dvi->currpage);
179 vfprintf(stderr, format, ap);
183 static void dviwarn(DviContext *dvi, const char *format, ...)
187 fprintf(stderr, "%s[%d]: Warning: ",
188 dvi->filename, dvi->currpage);
189 va_start(ap, format);
190 vfprintf(stderr, format, ap);
194 #define NEEDBYTES(d,n) \
195 ((d)->buffer.pos + (n) > (d)->buffer.length)
197 static int get_bytes(DviContext *dvi, size_t n)
200 * caller wants to read `n' bytes from dvi->buffer + dvi->pos.
201 * Make sure there is enough data to satisfy the request
203 if(NEEDBYTES(dvi, n)) {
207 if(dvi->buffer.frozen || dvi->in == NULL || feof(dvi->in)) {
209 dviwarn(dvi, _("unexpected EOF\n"));
213 if(dvi->buffer.data == NULL) {
214 /* first allocation */
215 dvi->buffer.size = Max(DVI_BUFLEN, n);
216 dvi->buffer.data = (Uchar *)mdvi_malloc(dvi->buffer.size);
217 dvi->buffer.length = 0;
218 dvi->buffer.frozen = 0;
219 } else if(dvi->buffer.pos < dvi->buffer.length) {
220 /* move whatever we want to keep */
221 dvi->buffer.length -= dvi->buffer.pos;
222 memmove(dvi->buffer.data,
223 dvi->buffer.data + dvi->buffer.pos,
226 /* we can discard all the data in this buffer */
227 dvi->buffer.length = 0;
230 required = n - dvi->buffer.length;
231 if(required > dvi->buffer.size - dvi->buffer.length) {
232 /* need to allocate more memory */
233 dvi->buffer.size = dvi->buffer.length + required + 128;
234 dvi->buffer.data = (Uchar *)xresize(dvi->buffer.data,
235 char, dvi->buffer.size);
237 /* now read into the buffer */
238 newlen = fread(dvi->buffer.data + dvi->buffer.length,
239 1, dvi->buffer.size - dvi->buffer.length, dvi->in);
241 mdvi_error("%s: %s\n", dvi->filename, strerror(errno));
244 dvi->buffer.length += newlen;
250 /* only relative forward seeks are supported by this function */
251 static int dskip(DviContext *dvi, long offset)
255 if(NEEDBYTES(dvi, offset) && get_bytes(dvi, offset) == -1)
257 dvi->buffer.pos += offset;
261 /* DVI I/O functions (note: here `n' must be <= 4) */
262 static long dsgetn(DviContext *dvi, size_t n)
266 if(NEEDBYTES(dvi, n) && get_bytes(dvi, n) == -1)
268 val = msgetn(dvi->buffer.data + dvi->buffer.pos, n);
269 dvi->buffer.pos += n;
273 static int dread(DviContext *dvi, char *buffer, size_t len)
275 if(NEEDBYTES(dvi, len) && get_bytes(dvi, len) == -1)
277 memcpy(buffer, dvi->buffer.data + dvi->buffer.pos, len);
278 dvi->buffer.pos += len;
282 static long dugetn(DviContext *dvi, size_t n)
286 if(NEEDBYTES(dvi, n) && get_bytes(dvi, n) == -1)
288 val = mugetn(dvi->buffer.data + dvi->buffer.pos, n);
289 dvi->buffer.pos += n;
293 static long dtell(DviContext *dvi)
297 ftell(dvi->in) - dvi->buffer.length + dvi->buffer.pos;
300 static void dreset(DviContext *dvi)
302 if(!dvi->buffer.frozen && dvi->buffer.data)
303 mdvi_free(dvi->buffer.data);
304 dvi->buffer.data = NULL;
305 dvi->buffer.size = 0;
306 dvi->buffer.length = 0;
310 #define dsget1(d) dsgetn((d), 1)
311 #define dsget2(d) dsgetn((d), 2)
312 #define dsget3(d) dsgetn((d), 3)
313 #define dsget4(d) dsgetn((d), 4)
314 #define duget1(d) dugetn((d), 1)
315 #define duget2(d) dugetn((d), 2)
316 #define duget3(d) dugetn((d), 3)
317 #define duget4(d) dugetn((d), 4)
320 static void dviprint(DviContext *dvi, const char *command, int sub, const char *fmt, ...)
325 printf("%s: ", dvi->filename);
326 for(i = 0; i < dvi->depth; i++)
328 printf("%4lu: %s", dtell(dvi), command);
329 if(sub >= 0) printf("%d", sub);
330 if(*fmt) printf(": ");
336 if(_mdvi_debug_mask & DBG_OPCODE) do { dviprint x; } while(0)
338 #define SHOWCMD(x) do { } while(0)
341 int mdvi_find_tex_page(DviContext *dvi, int tex_page)
345 for(i = 0; i < dvi->npages; i++)
346 if(dvi->pagemap[i][1] == tex_page)
351 /* page sorting functions */
352 static int sort_up(const void *p1, const void *p2)
354 return ((long *)p1)[1] - ((long *)p2)[1];
356 static int sort_down(const void *p1, const void *p2)
358 return ((long *)p2)[1] - ((long *)p1)[1];
360 static int sort_random(const void *p1, const void *p2)
362 return (random() % 1) ? -1 : 1;
364 static int sort_dvi_up(const void *p1, const void *p2)
366 return ((long *)p1)[0] - ((long *)p2)[0];
368 static int sort_dvi_down(const void *p1, const void *p2)
370 return ((long *)p1)[0] - ((long *)p2)[0];
373 void mdvi_sort_pages(DviContext *dvi, DviPageSort type)
375 int (*sortfunc) __PROTO((const void *, const void *));
378 case MDVI_PAGE_SORT_UP:
381 case MDVI_PAGE_SORT_DOWN:
382 sortfunc = sort_down;
384 case MDVI_PAGE_SORT_RANDOM:
385 sortfunc = sort_random;
387 case MDVI_PAGE_SORT_DVI_UP:
388 sortfunc = sort_dvi_up;
390 case MDVI_PAGE_SORT_DVI_DOWN:
391 sortfunc = sort_dvi_down;
393 case MDVI_PAGE_SORT_NONE:
400 qsort(dvi->pagemap, dvi->npages, sizeof(PageNum), sortfunc);
403 static DviFontRef *define_font(DviContext *dvi, int op)
415 arg = dugetn(dvi, op - DVI_FNT_DEF1 + 1);
416 checksum = duget4(dvi);
419 hdpi = FROUND(dvi->params.mag * dvi->params.dpi * scale / dsize);
420 vdpi = FROUND(dvi->params.mag * dvi->params.vdpi * scale / dsize);
421 n = duget1(dvi) + duget1(dvi);
422 name = mdvi_malloc(n + 1);
425 DEBUG((DBG_FONTS, "requesting font %d = `%s' at %.1fpt (%dx%d dpi)\n",
426 arg, name, (double)scale / (dvi->params.tfm_conv * 0x100000),
428 ref = font_reference(&dvi->params, arg, name, checksum, hdpi, vdpi, scale);
430 mdvi_error(_("could not load font `%s'\n"), name);
438 static char *opendvi(const char *name)
444 /* if file ends with .dvi and it exists, that's it */
445 if(len >= 4 && STREQ(name+len-4, ".dvi")) {
446 DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", name));
447 if(access(name, R_OK) == 0)
448 return mdvi_strdup(name);
451 /* try appending .dvi */
452 file = mdvi_malloc(len + 5);
454 strcpy(file+len, ".dvi");
455 DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", file));
456 if(access(file, R_OK) == 0)
458 /* try the given name */
460 DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", file));
461 if(access(file, R_OK) == 0)
467 int mdvi_reload(DviContext *dvi, DviParams *np)
478 pars = np ? np : &dvi->params;
479 DEBUG((DBG_DVI, "%s: reloading\n", dvi->filename));
482 newdvi = mdvi_init_context(pars, dvi->pagesel, dvi->filename);
484 mdvi_warning(_("could not reload `%s'\n"), dvi->filename);
488 /* drop all our font references */
489 font_drop_chain(dvi->fonts);
490 /* destroy our font map */
492 mdvi_free(dvi->fontmap);
493 dvi->currfont = NULL;
495 /* and use the ones we just loaded */
496 dvi->fonts = newdvi->fonts;
497 dvi->fontmap = newdvi->fontmap;
498 dvi->nfonts = newdvi->nfonts;
500 /* copy the new information */
501 dvi->params = newdvi->params;
502 dvi->num = newdvi->num;
503 dvi->den = newdvi->den;
504 dvi->dvimag = newdvi->dvimag;
505 dvi->dviconv = newdvi->dviconv;
506 dvi->dvivconv = newdvi->dvivconv;
507 dvi->modtime = newdvi->modtime;
509 if(dvi->fileid) mdvi_free(dvi->fileid);
510 dvi->fileid = newdvi->fileid;
512 dvi->dvi_page_w = newdvi->dvi_page_w;
513 dvi->dvi_page_h = newdvi->dvi_page_h;
515 mdvi_free(dvi->pagemap);
516 dvi->pagemap = newdvi->pagemap;
517 dvi->npages = newdvi->npages;
518 if(dvi->currpage > dvi->npages-1)
521 mdvi_free(dvi->stack);
522 dvi->stack = newdvi->stack;
523 dvi->stacksize = newdvi->stacksize;
525 /* remove fonts that are not being used anymore */
526 font_free_unused(&dvi->device);
528 mdvi_free(newdvi->filename);
531 DEBUG((DBG_DVI, "%s: reload successful\n", dvi->filename));
532 if(dvi->device.refresh)
533 dvi->device.refresh(dvi, dvi->device.device_data);
538 /* function to change parameters ia DVI context
539 * The DVI context is modified ONLY if this function is successful */
540 int mdvi_configure(DviContext *dvi, DviParamCode option, ...)
547 va_start(ap, option);
551 np = dvi->params; /* structure copy */
552 while(option != MDVI_PARAM_LAST) {
555 np.dpi = np.vdpi = va_arg(ap, Uint);
559 np.dpi = va_arg(ap, Uint);
563 np.vdpi = va_arg(ap, Uint);
565 case MDVI_SET_SHRINK:
566 np.hshrink = np.vshrink = va_arg(ap, Uint);
567 reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
569 case MDVI_SET_XSHRINK:
570 np.hshrink = va_arg(ap, Uint);
571 reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
573 case MDVI_SET_YSHRINK:
574 np.vshrink = va_arg(ap, Uint);
575 reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
577 case MDVI_SET_ORIENTATION:
578 np.orientation = va_arg(ap, DviOrientation);
579 reset_font = MDVI_FONTSEL_GLYPH;
582 np.gamma = va_arg(ap, double);
583 reset_font = MDVI_FONTSEL_GREY;
585 case MDVI_SET_DENSITY:
586 np.density = va_arg(ap, Uint);
587 reset_font = MDVI_FONTSEL_BITMAP;
589 case MDVI_SET_MAGNIFICATION:
590 np.mag = va_arg(ap, double);
594 np.hdrift = np.vdrift = va_arg(ap, int);
596 case MDVI_SET_HDRIFT:
597 np.hdrift = va_arg(ap, int);
599 case MDVI_SET_VDRIFT:
600 np.vdrift = va_arg(ap, int);
602 case MDVI_SET_FOREGROUND:
603 np.fg = va_arg(ap, Ulong);
604 reset_font = MDVI_FONTSEL_GREY;
606 case MDVI_SET_BACKGROUND:
607 np.bg = va_arg(ap, Ulong);
608 reset_font = MDVI_FONTSEL_GREY;
613 option = va_arg(ap, DviParamCode);
617 /* check that all values make sense */
618 if(np.dpi <= 0 || np.vdpi <= 0)
624 if(np.hshrink < 1 || np.vshrink < 1)
626 if(np.hdrift < 0 || np.vdrift < 0)
632 * If the dpi or the magnification change, we basically have to reload
633 * the DVI file again from scratch.
637 return (mdvi_reload(dvi, &np) == 0);
639 if(np.hshrink != dvi->params.hshrink) {
640 np.conv = dvi->dviconv;
642 np.conv /= np.hshrink;
644 if(np.vshrink != dvi->params.vshrink) {
645 np.vconv = dvi->dvivconv;
647 np.vconv /= np.vshrink;
651 font_reset_chain_glyphs(&dvi->device, dvi->fonts, reset_font);
654 if((reset_font & MDVI_FONTSEL_GLYPH) && dvi->device.refresh) {
655 dvi->device.refresh(dvi, dvi->device.device_data);
662 * Read the initial data from the DVI file. If something is wrong with the
663 * file, we just spit out an error message and refuse to load the file,
664 * without giving any details. This makes sense because DVI files are ok
665 * 99.99% of the time, and dvitype(1) can be used to check the other 0.01%.
667 DviContext *mdvi_init_context(DviParams *par, DviPageSpec *spec, const char *file)
679 * 1. Open the file and initialize the DVI context
682 filename = opendvi(file);
683 if(filename == NULL) {
687 p = fopen(filename, "r");
693 dvi = xalloc(DviContext);
694 memzero(dvi, sizeof(DviContext));
696 dvi->filename = filename;
698 dvi->modtime = get_mtime(fileno(p));
699 dvi->buffer.data = NULL;
701 dvi->in = p; /* now we can use the dget*() functions */
704 * 2. Read the preamble, extract scaling information, and
705 * setup the DVI parameters.
708 if(fuget1(p) != DVI_PRE)
710 if((arg = fuget1(p)) != DVI_ID) {
711 mdvi_error(_("%s: unsupported DVI format (version %u)\n"),
713 goto error; /* jump to the end of this routine,
714 * where we handle errors */
717 dvi->num = fuget4(p);
718 dvi->den = fuget4(p);
719 dvi->dvimag = fuget4(p);
721 /* check that these numbers make sense */
722 if(!dvi->num || !dvi->den || !dvi->dvimag)
726 (par->mag > 0 ? par->mag : (double)dvi->dvimag / 1000.0);
727 dvi->params.hdrift = par->hdrift;
728 dvi->params.vdrift = par->vdrift;
729 dvi->params.dpi = par->dpi ? par->dpi : MDVI_DPI;
730 dvi->params.vdpi = par->vdpi ? par->vdpi : par->dpi;
731 dvi->params.hshrink = par->hshrink;
732 dvi->params.vshrink = par->vshrink;
733 dvi->params.density = par->density;
734 dvi->params.gamma = par->gamma;
735 dvi->params.conv = (double)dvi->num / dvi->den;
736 dvi->params.conv *= (dvi->params.dpi / 254000.0) * dvi->params.mag;
737 dvi->params.vconv = (double)dvi->num / dvi->den;
738 dvi->params.vconv *= (dvi->params.vdpi / 254000.0) * dvi->params.mag;
739 dvi->params.tfm_conv = (25400000.0 / dvi->num) *
740 ((double)dvi->den / 473628672) / 16.0;
741 dvi->params.flags = par->flags;
742 dvi->params.orientation = par->orientation;
743 dvi->params.fg = par->fg;
744 dvi->params.bg = par->bg;
746 /* initialize colors */
747 dvi->curr_fg = par->fg;
748 dvi->curr_bg = par->bg;
749 dvi->color_stack = NULL;
753 /* pixel conversion factors */
754 dvi->dviconv = dvi->params.conv;
755 dvi->dvivconv = dvi->params.vconv;
756 if(dvi->params.hshrink)
757 dvi->params.conv /= dvi->params.hshrink;
758 if(dvi->params.vshrink)
759 dvi->params.vconv /= dvi->params.vshrink;
761 /* get the comment from the preamble */
763 dvi->fileid = mdvi_malloc(n + 1);
764 fread(dvi->fileid, 1, n, p);
766 DEBUG((DBG_DVI, "%s: %s\n", filename, dvi->fileid));
769 * 3. Read postamble, extract page information (number of
770 * pages, dimensions) and stack depth.
773 /* jump to the end of the file */
774 if(fseek(p, (long)-1, SEEK_END) == -1)
776 for(n = 0; (op = fuget1(p)) == DVI_TRAILER; n++)
777 if(fseek(p, (long)-2, SEEK_CUR) < 0)
779 if(op != arg || n < 4)
781 /* get the pointer to postamble */
782 fseek(p, (long)-5, SEEK_CUR);
785 fseek(p, (long)arg, SEEK_SET);
786 if(fuget1(p) != DVI_POST)
789 if(dvi->num != fuget4(p) || dvi->den != fuget4(p) ||
790 dvi->dvimag != fuget4(p))
792 dvi->dvi_page_h = fuget4(p);
793 dvi->dvi_page_w = fuget4(p);
794 dvi->stacksize = fuget2(p);
795 dvi->npages = fuget2(p);
796 DEBUG((DBG_DVI, "%s: from postamble: stack depth %d, %d page%s\n",
797 filename, dvi->stacksize, dvi->npages, dvi->npages > 1 ? "s" : ""));
800 * 4. Process font definitions.
803 /* process font definitions */
807 * CAREFUL: here we need to use the dvi->buffer, but it might leave the
808 * the file cursor in the wrong position after reading fonts (because of
809 * buffering). It's ok, though, because after the font definitions we read
810 * the page offsets, and we fseek() to the relevant part of the file with
811 * SEEK_SET. Nothing is read after the page offsets.
813 while((op = duget1(dvi)) != DVI_POST_POST) {
818 else if(op < DVI_FNT_DEF1 || op > DVI_FNT_DEF4)
820 ref = define_font(dvi, op);
823 ref->next = dvi->fonts;
827 /* we don't need the buffer anymore */
830 if(op != DVI_POST_POST)
832 font_finish_definitions(dvi);
833 DEBUG((DBG_DVI, "%s: %d font%s required by this job\n",
834 filename, dvi->nfonts, dvi->nfonts > 1 ? "s" : ""));
835 dvi->findref = font_find_mapped;
838 * 5. Build the page map.
841 dvi->pagemap = xnalloc(PageNum, dvi->npages);
842 memzero(dvi->pagemap, sizeof(PageNum) * dvi->npages);
846 while(offset != -1) {
850 fseek(p, offset, SEEK_SET);
852 if(op != DVI_BOP || n < 0)
854 for(i = 1; i <= 10; i++)
858 /* check if the page is selected */
859 if(spec && mdvi_page_selected(spec, page, n) == 0) {
860 DEBUG((DBG_DVI, "Page %d (%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld) ignored by request\n",
861 n, page[1], page[2], page[3], page[4], page[5],
862 page[6], page[7], page[8], page[9], page[10]));
864 memcpy(&dvi->pagemap[pagecount], page, sizeof(PageNum));
870 if(pagecount >= dvi->npages) {
871 mdvi_error(_("no pages selected\n"));
875 DEBUG((DBG_DVI, "%d of %d pages selected\n",
876 dvi->npages - pagecount, dvi->npages));
877 dvi->npages -= pagecount;
878 memmove(dvi->pagemap, &dvi->pagemap[pagecount],
879 dvi->npages * sizeof(PageNum));
883 * 6. Setup stack, initialize device functions
887 dvi->stack = xnalloc(DviState, dvi->stacksize + 8);
889 dvi->device.draw_glyph = dummy_draw_glyph;
890 dvi->device.draw_rule = dummy_draw_rule;
891 dvi->device.alloc_colors = dummy_alloc_colors;
892 dvi->device.create_image = dummy_create_image;
893 dvi->device.free_image = dummy_free_image;
894 dvi->device.dev_destroy = dummy_dev_destroy;
895 dvi->device.put_pixel = dummy_dev_putpixel;
896 dvi->device.refresh = dummy_dev_refresh;
897 dvi->device.set_color = dummy_dev_set_color;
898 dvi->device.device_data = NULL;
900 DEBUG((DBG_DVI, "%s read successfully\n", filename));
904 mdvi_error(_("%s: File corrupted, or not a DVI file\n"), file);
906 /* if we came from the font definitions, this will be non-trivial */
908 mdvi_destroy_context(dvi);
912 void mdvi_destroy_context(DviContext *dvi)
914 if(dvi->device.dev_destroy)
915 dvi->device.dev_destroy(dvi->device.device_data);
916 /* release all fonts */
918 font_drop_chain(dvi->fonts);
919 font_free_unused(&dvi->device);
922 mdvi_free(dvi->fontmap);
924 mdvi_free(dvi->filename);
926 mdvi_free(dvi->stack);
928 mdvi_free(dvi->pagemap);
930 mdvi_free(dvi->fileid);
933 if(dvi->buffer.data && !dvi->buffer.frozen)
934 mdvi_free(dvi->buffer.data);
936 mdvi_free(dvi->color_stack);
941 void mdvi_setpage(DviContext *dvi, int pageno)
945 if(pageno > dvi->npages-1)
946 pageno = dvi->npages - 1;
947 dvi->currpage = pageno;
950 static int mdvi_run_macro(DviContext *dvi, Uchar *macro, size_t len)
952 DviFontRef *curr, *fonts;
953 DviBuffer saved_buffer;
966 curr = dvi->currfont;
968 saved_buffer = dvi->buffer;
969 saved_file = dvi->in;
970 dvi->currfont = curr->ref->subfonts;
971 dvi->fonts = curr->ref->subfonts;
972 dvi->buffer.data = macro;
974 dvi->buffer.length = len;
975 dvi->buffer.frozen = 1;
977 oldtop = dvi->stacktop;
979 /* execute commands */
980 while((opcode = duget1(dvi)) != DVI_EOP) {
981 if(dvi_commands[opcode](dvi, opcode) < 0)
984 if(opcode != DVI_EOP)
985 dviwarn(dvi, _("%s: vf macro had errors\n"),
986 curr->ref->fontname);
987 if(dvi->stacktop != oldtop)
988 dviwarn(dvi, _("%s: stack not empty after vf macro\n"),
989 curr->ref->fontname);
993 dvi->currfont = curr;
995 dvi->buffer = saved_buffer;
996 dvi->in = saved_file;
999 return (opcode != DVI_EOP ? -1 : 0);
1002 int mdvi_dopage(DviContext *dvi, int pageno)
1009 if(dvi->in == NULL) {
1010 /* try reopening the file */
1011 dvi->in = fopen(dvi->filename, "r");
1012 if(dvi->in == NULL) {
1013 mdvi_warning(_("%s: could not reopen file (%s)\n"),
1018 DEBUG((DBG_FILES, "reopen(%s) -> Ok\n", dvi->filename));
1021 /* check if we need to reload the file */
1022 if(!reloaded && get_mtime(fileno(dvi->in)) > dvi->modtime) {
1023 mdvi_reload(dvi, &dvi->params);
1024 /* we have to reopen the file, again */
1029 if(pageno < 0 || pageno > dvi->npages-1) {
1030 mdvi_error(_("%s: page %d out of range\n"),
1031 dvi->filename, pageno);
1035 fseek(dvi->in, (long)dvi->pagemap[pageno][0], SEEK_SET);
1036 if((op = fuget1(dvi->in)) != DVI_BOP) {
1037 mdvi_error(_("%s: bad offset at page %d\n"),
1038 dvi->filename, pageno+1);
1043 fseek(dvi->in, (long)44, SEEK_CUR);
1046 dvi->currfont = NULL;
1047 memzero(&dvi->pos, sizeof(DviState));
1049 dvi->currpage = pageno;
1050 dvi->curr_layer = 0;
1052 if(dvi->buffer.data && !dvi->buffer.frozen)
1053 mdvi_free(dvi->buffer.data);
1055 /* reset our buffer */
1056 dvi->buffer.data = NULL;
1057 dvi->buffer.length = 0;
1058 dvi->buffer.pos = 0;
1059 dvi->buffer.frozen = 0;
1061 #if 0 /* make colors survive page breaks */
1062 /* reset color stack */
1063 mdvi_reset_color(dvi);
1066 /* set max horizontal and vertical drift (from dvips) */
1067 if(dvi->params.hdrift < 0) {
1068 ppi = dvi->params.dpi / dvi->params.hshrink; /* shrunk pixels per inch */
1070 dvi->params.hdrift = ppi / 100;
1072 dvi->params.hdrift = ppi / 200;
1074 dvi->params.hdrift = ppi / 400;
1076 if(dvi->params.vdrift < 0) {
1077 ppi = dvi->params.vdpi / dvi->params.vshrink; /* shrunk pixels per inch */
1079 dvi->params.vdrift = ppi / 100;
1081 dvi->params.vdrift = ppi / 200;
1083 dvi->params.vdrift = ppi / 400;
1086 dvi->params.thinsp = FROUND(0.025 * dvi->params.dpi / dvi->params.conv);
1087 dvi->params.vsmallsp = FROUND(0.025 * dvi->params.vdpi / dvi->params.vconv);
1089 /* execute all the commands in the page */
1090 while((op = duget1(dvi)) != DVI_EOP) {
1091 if(dvi_commands[op](dvi, op) < 0)
1100 dviwarn(dvi, _("stack not empty at end of page\n"));
1104 static int inline move_vertical(DviContext *dvi, int amount)
1108 dvi->pos.v += amount;
1109 rvv = vpixel_round(dvi, dvi->pos.v);
1110 if(!dvi->params.vdrift)
1112 if(amount > dvi->params.vsmallsp || amount <= -dvi->params.vsmallsp)
1117 newvv = dvi->pos.vv + vpixel_round(dvi, amount);
1118 if(rvv - newvv > dvi->params.vdrift)
1119 return rvv - dvi->params.vdrift;
1120 else if(newvv - rvv > dvi->params.vdrift)
1121 return rvv + dvi->params.vdrift;
1127 static int inline move_horizontal(DviContext *dvi, int amount)
1131 dvi->pos.h += amount;
1132 rhh = pixel_round(dvi, dvi->pos.h);
1133 if(!dvi->params.hdrift)
1135 else if(amount > dvi->params.thinsp || amount <= -6 * dvi->params.thinsp)
1140 newhh = dvi->pos.hh + pixel_round(dvi, amount);
1141 if(rhh - newhh > dvi->params.hdrift)
1142 return rhh - dvi->params.hdrift;
1143 else if(newhh - rhh > dvi->params.hdrift)
1144 return rhh + dvi->params.hdrift;
1150 static void inline fix_after_horizontal(DviContext *dvi)
1154 rhh = pixel_round(dvi, dvi->pos.h);
1155 if(!dvi->params.hdrift)
1157 else if(rhh - dvi->pos.hh > dvi->params.hdrift)
1158 dvi->pos.hh = rhh - dvi->params.hdrift;
1159 else if(dvi->pos.hh - rhh > dvi->params.hdrift)
1160 dvi->pos.hh = rhh + dvi->params.hdrift;
1165 #define DBGSUM(a,b,c) \
1166 (a), (b) > 0 ? '+' : '-', \
1167 (b) > 0 ? (b) : -(b), (c)
1170 * Draw rules with some sort of antialias support. Usefult for high-rate
1174 static void draw_shrink_rule (DviContext *dvi, int x, int y, Uint w, Uint h, int f)
1176 int hs, vs, npixels;
1180 hs = dvi->params.hshrink;
1181 vs = dvi->params.vshrink;
1185 if (MDVI_ENABLED(dvi, MDVI_PARAM_ANTIALIASED)) {
1186 npixels = vs * hs + 1;
1187 pixels = get_color_table(&dvi->device, npixels, bg, fg,
1188 dvi->params.gamma, dvi->params.density);
1193 /* Lines with width 1 should be perfectly visible
1194 * in shrink about 15. That is the reason of constant
1197 color = (pow (vs / h * hs, 2) + pow (hs / w * vs, 2)) / 225;
1198 if (color < npixels) {
1201 fg = pixels[npixels - 1];
1206 mdvi_push_color (dvi, fg, bg);
1207 dvi->device.draw_rule(dvi, x, y, w, h, f);
1208 mdvi_pop_color (dvi);
1214 * The only commands that actually draw something are:
1215 * set_char, set_rule
1218 static void draw_box(DviContext *dvi, DviFontChar *ch)
1220 DviGlyph *glyph = NULL;
1223 if(!MDVI_GLYPH_UNSET(ch->shrunk.data))
1224 glyph = &ch->shrunk;
1225 else if(!MDVI_GLYPH_UNSET(ch->grey.data))
1227 else if(!MDVI_GLYPH_UNSET(ch->glyph.data))
1235 /* this is bad -- we have to undo the orientation */
1236 switch(dvi->params.orientation) {
1237 case MDVI_ORIENT_TBLR:
1239 case MDVI_ORIENT_TBRL:
1242 case MDVI_ORIENT_BTLR:
1245 case MDVI_ORIENT_BTRL:
1249 case MDVI_ORIENT_RP90:
1254 case MDVI_ORIENT_RM90:
1259 case MDVI_ORIENT_IRP90:
1263 case MDVI_ORIENT_IRM90:
1271 draw_shrink_rule(dvi, dvi->pos.hh - x, dvi->pos.vv - y, w, h, 1);
1274 int set_char(DviContext *dvi, int opcode)
1285 num = dugetn(dvi, opcode - DVI_SET1 + 1);
1286 if(dvi->currfont == NULL) {
1287 dvierr(dvi, _("no default font set yet\n"));
1290 font = dvi->currfont->ref;
1291 ch = font_get_glyph(dvi, font, num);
1292 if(ch == NULL || ch->missing) {
1293 /* try to display something anyway */
1294 ch = FONTCHAR(font, num);
1295 if(!glyph_present(ch)) {
1297 _("requested character %d does not exist in `%s'\n"),
1298 num, font->fontname);
1302 } else if(dvi->curr_layer <= dvi->params.layer) {
1304 mdvi_run_macro(dvi, (Uchar *)font->private +
1305 ch->offset, ch->width);
1306 else if(ch->width && ch->height)
1307 dvi->device.draw_glyph(dvi, ch,
1308 dvi->pos.hh, dvi->pos.vv);
1310 if(opcode >= DVI_PUT1 && opcode <= DVI_PUT4) {
1311 SHOWCMD((dvi, "putchar", opcode - DVI_PUT1 + 1,
1313 num, dvi->currfont->ref->fontname));
1315 h = dvi->pos.h + ch->tfmwidth;
1316 hh = dvi->pos.hh + pixel_round(dvi, ch->tfmwidth);
1317 SHOWCMD((dvi, "setchar", num, "(%d,%d) h:=%d%c%d=%d, hh:=%d (%s)\n",
1318 dvi->pos.hh, dvi->pos.vv,
1319 DBGSUM(dvi->pos.h, ch->tfmwidth, h), hh,
1323 fix_after_horizontal(dvi);
1329 int set_rule(DviContext *dvi, int opcode)
1335 b = dsget4(dvi); w = rule_round(dvi, b);
1336 if(a > 0 && b > 0) {
1337 h = vrule_round(dvi, a);
1338 SHOWCMD((dvi, opcode == DVI_SET_RULE ? "setrule" : "putrule", -1,
1339 "width %d, height %d (%dx%d pixels)\n",
1341 /* the `draw' functions expect the origin to be at the top left
1342 * corner of the rule, not the bottom left, as in DVI files */
1343 if(dvi->curr_layer <= dvi->params.layer) {
1344 draw_shrink_rule(dvi,
1345 dvi->pos.hh, dvi->pos.vv - h + 1, w, h, 1);
1348 SHOWCMD((dvi, opcode == DVI_SET_RULE ? "setrule" : "putrule", -1,
1349 "(moving left only, by %d)\n", b));
1352 if(opcode == DVI_SET_RULE) {
1355 fix_after_horizontal(dvi);
1360 int no_op(DviContext *dvi, int opcode)
1362 SHOWCMD((dvi, "noop", -1, ""));
1366 int push(DviContext *dvi, int opcode)
1368 if(dvi->stacktop == dvi->stacksize) {
1370 dviwarn(dvi, _("enlarging stack\n"));
1371 dvi->stacksize += 8;
1372 dvi->stack = xresize(dvi->stack,
1373 DviState, dvi->stacksize);
1375 memcpy(&dvi->stack[dvi->stacktop], &dvi->pos, sizeof(DviState));
1376 SHOWCMD((dvi, "push", -1,
1377 "level %d: (h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)\n",
1379 dvi->pos.h, dvi->pos.v, dvi->pos.w, dvi->pos.x,
1380 dvi->pos.y, dvi->pos.z, dvi->pos.hh, dvi->pos.vv));
1385 int pop(DviContext *dvi, int opcode)
1387 if(dvi->stacktop == 0) {
1388 dvierr(dvi, _("stack underflow\n"));
1391 memcpy(&dvi->pos, &dvi->stack[dvi->stacktop-1], sizeof(DviState));
1392 SHOWCMD((dvi, "pop", -1,
1393 "level %d: (h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)\n",
1395 dvi->pos.h, dvi->pos.v, dvi->pos.w, dvi->pos.x,
1396 dvi->pos.y, dvi->pos.z, dvi->pos.hh, dvi->pos.vv));
1401 int move_right(DviContext *dvi, int opcode)
1406 arg = dsgetn(dvi, opcode - DVI_RIGHT1 + 1);
1408 hh = move_horizontal(dvi, arg);
1409 SHOWCMD((dvi, "right", opcode - DVI_RIGHT1 + 1,
1410 "%d h:=%d%c%d=%d, hh:=%d\n",
1411 arg, DBGSUM(h, arg, dvi->pos.h), hh));
1416 int move_down(DviContext *dvi, int opcode)
1421 arg = dsgetn(dvi, opcode - DVI_DOWN1 + 1);
1423 vv = move_vertical(dvi, arg);
1424 SHOWCMD((dvi, "down", opcode - DVI_DOWN1 + 1,
1425 "%d v:=%d%c%d=%d, vv:=%d\n",
1426 arg, DBGSUM(v, arg, dvi->pos.v), vv));
1431 int move_w(DviContext *dvi, int opcode)
1435 if(opcode != DVI_W0)
1436 dvi->pos.w = dsgetn(dvi, opcode - DVI_W0);
1438 hh = move_horizontal(dvi, dvi->pos.w);
1439 SHOWCMD((dvi, "w", opcode - DVI_W0,
1440 "%d h:=%d%c%d=%d, hh:=%d\n",
1441 dvi->pos.w, DBGSUM(h, dvi->pos.w, dvi->pos.h), hh));
1446 int move_x(DviContext *dvi, int opcode)
1450 if(opcode != DVI_X0)
1451 dvi->pos.x = dsgetn(dvi, opcode - DVI_X0);
1453 hh = move_horizontal(dvi, dvi->pos.x);
1454 SHOWCMD((dvi, "x", opcode - DVI_X0,
1455 "%d h:=%d%c%d=%d, hh:=%d\n",
1456 dvi->pos.x, DBGSUM(h, dvi->pos.x, dvi->pos.h), hh));
1461 int move_y(DviContext *dvi, int opcode)
1465 if(opcode != DVI_Y0)
1466 dvi->pos.y = dsgetn(dvi, opcode - DVI_Y0);
1468 vv = move_vertical(dvi, dvi->pos.y);
1469 SHOWCMD((dvi, "y", opcode - DVI_Y0,
1470 "%d h:=%d%c%d=%d, hh:=%d\n",
1471 dvi->pos.y, DBGSUM(v, dvi->pos.y, dvi->pos.v), vv));
1476 int move_z(DviContext *dvi, int opcode)
1480 if(opcode != DVI_Z0)
1481 dvi->pos.z = dsgetn(dvi, opcode - DVI_Z0);
1483 vv = move_vertical(dvi, dvi->pos.z);
1484 SHOWCMD((dvi, "z", opcode - DVI_Z0,
1485 "%d h:=%d%c%d=%d, hh:=%d\n",
1486 dvi->pos.z, DBGSUM(v, dvi->pos.z, dvi->pos.v), vv));
1491 int sel_font(DviContext *dvi, int opcode)
1496 ndx = opcode - DVI_FNT_NUM0;
1498 ref = font_find_flat(dvi, ndx);
1500 ref = dvi->findref(dvi, ndx);
1502 dvierr(dvi, _("font %d is not defined\n"),
1503 opcode - DVI_FNT_NUM0);
1506 SHOWCMD((dvi, "fntnum", opcode - DVI_FNT_NUM0,
1507 "current font is %s\n",
1508 ref->ref->fontname));
1509 dvi->currfont = ref;
1513 int sel_fontn(DviContext *dvi, int opcode)
1518 arg = dugetn(dvi, opcode - DVI_FNT1 + 1);
1520 ref = font_find_flat(dvi, arg);
1522 ref = dvi->findref(dvi, arg);
1524 dvierr(dvi, _("font %d is not defined\n"), arg);
1527 SHOWCMD((dvi, "fnt", opcode - DVI_FNT1 + 1,
1528 "current font is %s (id %d)\n",
1529 ref->ref->fontname, arg));
1530 dvi->currfont = ref;
1534 int special(DviContext *dvi, int opcode)
1539 arg = dugetn(dvi, opcode - DVI_XXX1 + 1);
1540 s = mdvi_malloc(arg + 1);
1543 mdvi_do_special(dvi, s);
1544 SHOWCMD((dvi, "XXXX", opcode - DVI_XXX1 + 1,
1550 int def_font(DviContext *dvi, int opcode)
1555 arg = dugetn(dvi, opcode - DVI_FNT_DEF1 + 1);
1557 ref = font_find_flat(dvi, arg);
1559 ref = dvi->findref(dvi, arg);
1562 dskip(dvi, duget1(dvi) + duget1(dvi));
1564 dvierr(dvi, _("font %d is not defined in postamble\n"), arg);
1567 SHOWCMD((dvi, "fntdef", opcode - DVI_FNT_DEF1 + 1,
1568 "%d -> %s (%d links)\n",
1569 ref->fontid, ref->ref->fontname,
1574 int unexpected(DviContext *dvi, int opcode)
1576 dvierr(dvi, _("unexpected opcode %d\n"), opcode);
1580 int undefined(DviContext *dvi, int opcode)
1582 dvierr(dvi, _("undefined opcode %d\n"), opcode);