summaryrefslogtreecommitdiff
path: root/dviware/mdvi/lib
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/mdvi/lib
Initial commit
Diffstat (limited to 'dviware/mdvi/lib')
-rw-r--r--dviware/mdvi/lib/Makefile.in66
-rw-r--r--dviware/mdvi/lib/afmparse.c1302
-rw-r--r--dviware/mdvi/lib/afmparse.h307
-rw-r--r--dviware/mdvi/lib/assoc.c97
-rw-r--r--dviware/mdvi/lib/bitmap.c1111
-rw-r--r--dviware/mdvi/lib/common.c185
-rw-r--r--dviware/mdvi/lib/dvimisc.c62
-rw-r--r--dviware/mdvi/lib/dviread.c1548
-rw-r--r--dviware/mdvi/lib/files.c150
-rw-r--r--dviware/mdvi/lib/font.c542
-rw-r--r--dviware/mdvi/lib/fontmap.c1169
-rw-r--r--dviware/mdvi/lib/fontsrch.c370
-rw-r--r--dviware/mdvi/lib/gf.c394
-rw-r--r--dviware/mdvi/lib/hash.c223
-rw-r--r--dviware/mdvi/lib/list.c119
-rw-r--r--dviware/mdvi/lib/pagesel.c490
-rw-r--r--dviware/mdvi/lib/paper.c170
-rw-r--r--dviware/mdvi/lib/pk.c569
-rw-r--r--dviware/mdvi/lib/po/CVS/Entries7
-rw-r--r--dviware/mdvi/lib/po/CVS/Repository1
-rw-r--r--dviware/mdvi/lib/po/CVS/Root1
-rw-r--r--dviware/mdvi/lib/po/Makefile18
-rw-r--r--dviware/mdvi/lib/po/Makefile.in18
-rw-r--r--dviware/mdvi/lib/po/cat-id-tbl.c103
-rw-r--r--dviware/mdvi/lib/po/es.gmobin0 -> 8441 bytes
-rw-r--r--dviware/mdvi/lib/po/es.po595
-rw-r--r--dviware/mdvi/lib/po/mdvi.pot435
-rw-r--r--dviware/mdvi/lib/po/stamp-cat-id1
-rw-r--r--dviware/mdvi/lib/setup.c381
-rw-r--r--dviware/mdvi/lib/sp-epsf.c255
-rw-r--r--dviware/mdvi/lib/special.c248
-rw-r--r--dviware/mdvi/lib/t1.c634
-rw-r--r--dviware/mdvi/lib/tfm.c213
-rw-r--r--dviware/mdvi/lib/tfmfile.c744
-rw-r--r--dviware/mdvi/lib/tt.c494
-rw-r--r--dviware/mdvi/lib/util.c504
-rw-r--r--dviware/mdvi/lib/vf.c240
37 files changed, 13766 insertions, 0 deletions
diff --git a/dviware/mdvi/lib/Makefile.in b/dviware/mdvi/lib/Makefile.in
new file mode 100644
index 0000000000..9ad27f3d91
--- /dev/null
+++ b/dviware/mdvi/lib/Makefile.in
@@ -0,0 +1,66 @@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include ../config.mk
+
+SUBDIRS = po
+
+LOCAL_CFLAGS = $(KPSE_CFLAGS) -I$(srcdir) -I.. -I$(srcdir)/../include
+ALL_CFLAGS = $(CFLAGS) $(ADDCFLAGS) $(CPPFLAGS) $(LOCAL_CFLAGS)
+
+OBJS = common.o util.o pk.o gf.o vf.o bitmap.o font.o list.o \
+ dviread.o paper.o pagesel.o setup.o special.o tfm.o sp-epsf.o \
+ dvimisc.o hash.o assoc.o tfmfile.o t1.o tt.o fontmap.o \
+ afmparse.o fontsrch.o files.o
+SOURCES = common.c util.c pk.c gf.c vf.c bitmap.c font.c list.c \
+ dviread.c paper.c pagesel.c setup.c special.c tfm.c sp-epsf.c \
+ dvimisc.c hash.c assoc.c tfmfile.c t1.c tt.c fontmap.c \
+ afmparse.c fontsrch.c files.c
+HEADERS = bitmap.h common.h defaults.h dviopcodes.h fontmap.h mdvi.h sysdeps.h
+
+ALL_SOURCES = $(SOURCES)
+ALL_HEADERS = $(addprefix $(srcdir)/../include/, $(HEADERS))
+OTHERFILES = Makefile.in afmparse.h
+
+# Dedendency files depend on these
+DEPSOURCES = $(SOURCES)
+DEPCFLAGS = $(LOCAL_CFLAGS) $(T1LIB_CFLAGS) $(FREETYPE_CFLAGS)
+
+# Files we distribute
+DISTFILES = $(ALL_SOURCES) ../include $(OTHERFILES) po
+
+# Files that we clean on the `clean' and `distclean' targets resp.
+CLEANABLE += $(OBJS) $(MDVILIB)
+DISTCLEANABLE += Makefile
+
+# The main target of this Makefile
+MDVILIB = mdvi.a
+
+.PHONY: all $(SUBDIRS)
+all: $(MDVILIB) $(SUBDIRS)
+
+$(SUBDIRS):
+ if test -d "$@"; then $(MAKE) -C $@; else :; fi
+
+.PHONY: install uninstall
+install:
+uninstall:
+
+$(MDVILIB): $(OBJS)
+ $(MAKELIB) $@ $(OBJS)
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+.c.o:
+ $(CC) $(ALL_CFLAGS) -c $<
+
+t1.o: t1.c
+ $(CC) $(ALL_CFLAGS) $(T1LIB_CFLAGS) -c $<
+tt.o: tt.c
+ $(CC) $(ALL_CFLAGS) $(FREETYPE_CFLAGS) -c $<
+
+include $(FRAGDIR)/dist.mk
+include $(FRAGDIR)/targets.mk
+include $(FRAGDIR)/depend.mk
diff --git a/dviware/mdvi/lib/afmparse.c b/dviware/mdvi/lib/afmparse.c
new file mode 100644
index 0000000000..5b8ac68090
--- /dev/null
+++ b/dviware/mdvi/lib/afmparse.c
@@ -0,0 +1,1302 @@
+/*
+ * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * modified for MDVI:
+ * - some names changed to avoid conflicts with T1lib
+ * - changed to ANSI C prototypes, as used by MDVI
+ * mal - 3/01
+ */
+
+/* parseAFM.c
+ *
+ * This file is used in conjuction with the parseAFM.h header file.
+ * This file contains several procedures that are used to parse AFM
+ * files. It is intended to work with an application program that needs
+ * font metric information. The program can be used as is by making a
+ * procedure call to "parseFile" (passing in the expected parameters)
+ * and having it fill in a data structure with the data from the
+ * AFM file, or an application developer may wish to customize this
+ * code.
+ *
+ * There is also a file, parseAFMclient.c, that is a sample application
+ * showing how to call the "parseFile" procedure and how to use the data
+ * after "parseFile" has returned.
+ *
+ * Please read the comments in parseAFM.h and parseAFMclient.c.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed bug of not allocating extra byte for string duplication
+ * - fixed typos
+ * modified: DSM Tue Apr 3 11:18:34 PDT 1990
+ * - added free(ident) at end of parseFile routine
+ * modified: DSM Tue Jun 19 10:16:29 PDT 1990
+ * - changed (width == 250) to (width = 250) in initializeArray
+ */
+
+#include "sysdeps.h"
+
+#ifdef WITH_AFM_FILES
+
+#include <stdlib.h> /* added for MDVI */
+#include <string.h> /* added for MDVI */
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <math.h>
+#include "afmparse.h"
+#undef VERSION
+
+#define lineterm EOL /* line terminating character */
+#define normalEOF 1 /* return code from parsing routines used only */
+ /* in this module */
+#define Space "space" /* used in string comparison to look for the width */
+ /* of the space character to init the widths array */
+#define False "false" /* used in string comparison to check the value of */
+ /* boolean keys (e.g. IsFixedPitch) */
+
+#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
+
+
+
+/*************************** GLOBALS ***********************/
+
+static char *ident = NULL; /* storage buffer for keywords */
+
+
+/* "shorts" for fast case statement
+ * The values of each of these enumerated items correspond to an entry in the
+ * table of strings defined below. Therefore, if you add a new string as
+ * new keyword into the keyStrings table, you must also add a corresponding
+ * parseKey AND it MUST be in the same position!
+ *
+ * IMPORTANT: since the sorting algorithm is a binary search, the strings of
+ * keywords must be placed in lexicographical order, below. [Therefore, the
+ * enumerated items are not necessarily in lexicographical order, depending
+ * on the name chosen. BUT, they must be placed in the same position as the
+ * corresponding key string.] The NOPE shall remain in the last position,
+ * since it does not correspond to any key string, and it is used in the
+ * "recognize" procedure to calculate how many possible keys there are.
+ */
+
+enum parseKey {
+ ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
+ DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
+ ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
+ FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH,
+ ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
+ NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
+ STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
+ STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
+ UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
+ NOPE } ;
+
+/* keywords for the system:
+ * This a table of all of the current strings that are vaild AFM keys.
+ * Each entry can be referenced by the appropriate parseKey value (an
+ * enumerated data type defined above). If you add a new keyword here,
+ * a corresponding parseKey MUST be added to the enumerated data type
+ * defined above, AND it MUST be added in the same position as the
+ * string is in this table.
+ *
+ * IMPORTANT: since the sorting algorithm is a binary search, the keywords
+ * must be placed in lexicographical order. And, NULL should remain at the
+ * end.
+ */
+
+static char *keyStrings[] = {
+ "Ascender", "B", "C", "CC", "CapHeight", "Comment",
+ "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
+ "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
+ "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch",
+ "ItalicAngle", "KP", "KPX", "L", "N",
+ "Notice", "PCC", "StartCharMetrics", "StartComposites",
+ "StartFontMetrics", "StartKernData", "StartKernPairs",
+ "StartTrackKern", "TrackKern", "UnderlinePosition",
+ "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
+ NULL };
+
+/*************************** PARSING ROUTINES **************/
+
+/*************************** token *************************/
+
+/* A "AFM File Conventions" tokenizer. That means that it will
+ * return the next token delimited by white space. See also
+ * the `linetoken' routine, which does a similar thing but
+ * reads all tokens until the next end-of-line.
+ */
+
+static char *token(FILE *stream)
+{
+ int ch, idx;
+
+ /* skip over white space */
+ while ((ch = fgetc(stream)) == ' ' || ch == lineterm ||
+ ch == ',' || ch == '\t' || ch == ';');
+
+ idx = 0;
+ while (ch != EOF && ch != ' ' && ch != lineterm
+ && ch != '\t' && ch != ':' && ch != ';')
+ {
+ ident[idx++] = ch;
+ ch = fgetc(stream);
+ } /* while */
+
+ if (ch == EOF && idx < 1) return ((char *)NULL);
+ if (idx >= 1 && ch != ':' ) ungetc(ch, stream);
+ if (idx < 1 ) ident[idx++] = ch; /* single-character token */
+ ident[idx] = 0;
+
+ return(ident); /* returns pointer to the token */
+
+} /* token */
+
+
+/*************************** linetoken *************************/
+
+/* "linetoken" will get read all tokens until the EOL character from
+ * the given stream. This is used to get any arguments that can be
+ * more than one word (like Comment lines and FullName).
+ */
+
+static char *linetoken(FILE *stream)
+{
+ int ch, idx;
+
+ while ((ch = fgetc(stream)) == ' ' || ch == '\t' );
+
+ idx = 0;
+ while (ch != EOF && ch != lineterm)
+ {
+ ident[idx++] = ch;
+ ch = fgetc(stream);
+ } /* while */
+
+ ungetc(ch, stream);
+ ident[idx] = 0;
+
+ return(ident); /* returns pointer to the token */
+
+} /* linetoken */
+
+
+/*************************** recognize *************************/
+
+/* This function tries to match a string to a known list of
+ * valid AFM entries (check the keyStrings array above).
+ * "ident" contains everything from white space through the
+ * next space, tab, or ":" character.
+ *
+ * The algorithm is a standard Knuth binary search.
+ */
+
+static enum parseKey recognize(char *ident)
+{
+ int lower = 0, upper = (int) NOPE, midpoint, cmpvalue;
+ BOOL found = FALSE;
+
+ while ((upper >= lower) && !found)
+ {
+ midpoint = (lower + upper)/2;
+ if (keyStrings[midpoint] == NULL) break;
+ cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME);
+ if (cmpvalue == 0) found = TRUE;
+ else if (cmpvalue < 0) upper = midpoint - 1;
+ else lower = midpoint + 1;
+ } /* while */
+
+ if (found) return (enum parseKey) midpoint;
+ else return NOPE;
+
+} /* recognize */
+
+
+/************************* parseGlobals *****************************/
+
+/* This function is called by "parseFile". It will parse the AFM File
+ * up to the "StartCharMetrics" keyword, which essentially marks the
+ * end of the Global Font Information and the beginning of the character
+ * metrics information.
+ *
+ * If the caller of "parseFile" specified that it wanted the Global
+ * Font Information (as defined by the "AFM File Specification"
+ * document), then that information will be stored in the returned
+ * data structure.
+ *
+ * Any Global Font Information entries that are not found in a
+ * given file, will have the usual default initialization value
+ * for its type (i.e. entries of type int will be 0, etc).
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static BOOL parseGlobals(FILE *fp, GlobalFontInfo *gfi)
+{
+ BOOL cont = TRUE, save = (gfi != NULL);
+ int error = ok;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp);
+
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Global Font info section */
+ /* without saving any of the data */
+ switch (recognize(keyword))
+ {
+ case STARTCHARMETRICS:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire global font info section, */
+ /* saving the data */
+ switch(recognize(keyword))
+ {
+ case STARTFONTMETRICS:
+ keyword = token(fp);
+ gfi->afmVersion = (char *) malloc(strlen(keyword) + 1);
+ strcpy(gfi->afmVersion, keyword);
+ break;
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case FONTNAME:
+ keyword = token(fp);
+ gfi->fontName = (char *) malloc(strlen(keyword) + 1);
+ strcpy(gfi->fontName, keyword);
+ break;
+ case ENCODINGSCHEME:
+ keyword = token(fp);
+ gfi->encodingScheme = (char *)
+ malloc(strlen(keyword) + 1);
+ strcpy(gfi->encodingScheme, keyword);
+ break;
+ case FULLNAME:
+ keyword = linetoken(fp);
+ gfi->fullName = (char *) malloc(strlen(keyword) + 1);
+ strcpy(gfi->fullName, keyword);
+ break;
+ case FAMILYNAME:
+ keyword = linetoken(fp);
+ gfi->familyName = (char *) malloc(strlen(keyword) + 1);
+ strcpy(gfi->familyName, keyword);
+ break;
+ case WEIGHT:
+ keyword = token(fp);
+ gfi->weight = (char *) malloc(strlen(keyword) + 1);
+ strcpy(gfi->weight, keyword);
+ break;
+ case ITALICANGLE:
+ keyword = token(fp);
+ gfi->italicAngle = atof(keyword);
+ if (errno == ERANGE) error = parseError;
+ break;
+ case ISFIXEDPITCH:
+ keyword = token(fp);
+ if (MATCH(keyword, False))
+ gfi->isFixedPitch = 0;
+ else
+ gfi->isFixedPitch = 1;
+ break;
+ case UNDERLINEPOSITION:
+ keyword = token(fp);
+ gfi->underlinePosition = atoi(keyword);
+ break;
+ case UNDERLINETHICKNESS:
+ keyword = token(fp);
+ gfi->underlineThickness = atoi(keyword);
+ break;
+ case VERSION:
+ keyword = token(fp);
+ gfi->version = (char *) malloc(strlen(keyword) + 1);
+ strcpy(gfi->version, keyword);
+ break;
+ case NOTICE:
+ keyword = linetoken(fp);
+ gfi->notice = (char *) malloc(strlen(keyword) + 1);
+ strcpy(gfi->notice, keyword);
+ break;
+ case FONTBBOX:
+ keyword = token(fp);
+ gfi->fontBBox.llx = atoi(keyword);
+ keyword = token(fp);
+ gfi->fontBBox.lly = atoi(keyword);
+ keyword = token(fp);
+ gfi->fontBBox.urx = atoi(keyword);
+ keyword = token(fp);
+ gfi->fontBBox.ury = atoi(keyword);
+ break;
+ case CAPHEIGHT:
+ keyword = token(fp);
+ gfi->capHeight = atoi(keyword);
+ break;
+ case XHEIGHT:
+ keyword = token(fp);
+ gfi->xHeight = atoi(keyword);
+ break;
+ case DESCENDER:
+ keyword = token(fp);
+ gfi->descender = atoi(keyword);
+ break;
+ case ASCENDER:
+ keyword = token(fp);
+ gfi->ascender = atoi(keyword);
+ break;
+ case STARTCHARMETRICS:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseGlobals */
+
+
+
+#if 0 /* this function does not seem to be used anywhere */
+/************************* initializeArray ************************/
+
+/* Unmapped character codes are (at Adobe Systems) assigned the
+ * width of the space character (if one exists) else they get the
+ * value of 250 ems. This function initializes all entries in the
+ * char widths array to have this value. Then any mapped character
+ * codes will be replaced with the width of the appropriate character
+ * when parsing the character metric section.
+
+ * This function parses the Character Metrics Section looking
+ * for a space character (by comparing character names). If found,
+ * the width of the space character will be used to initialize the
+ * values in the array of character widths.
+ *
+ * Before returning, the position of the read/write pointer of the
+ * file is reset to be where it was upon entering this function.
+ */
+
+static int initializeArray(FILE *fp, int *cwi)
+{
+ BOOL cont = TRUE, found = FALSE;
+ long opos = ftell(fp);
+ int code = 0, width = 0, i = 0, error = 0;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ code = atoi(token(fp));
+ break;
+ case XWIDTH:
+ width = atoi(token(fp));
+ break;
+ case CHARNAME:
+ keyword = token(fp);
+ if (MATCH(keyword, Space))
+ {
+ cont = FALSE;
+ found = TRUE;
+ }
+ break;
+ case ENDCHARMETRICS:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (!found)
+ width = 250;
+
+ for (i = 0; i < 256; ++i)
+ cwi[i] = width;
+
+ fseek(fp, opos, 0);
+
+ return(error);
+
+} /* initializeArray */
+#endif /* unused */
+
+/************************* parseCharWidths **************************/
+
+/* This function is called by "parseFile". It will parse the AFM File
+ * up to the "EndCharMetrics" keyword. It will save the character
+ * width info (as opposed to all of the character metric information)
+ * if requested by the caller of parseFile. Otherwise, it will just
+ * parse through the section without saving any information.
+ *
+ * If data is to be saved, parseCharWidths is passed in a pointer
+ * to an array of widths that has already been initialized by the
+ * standard value for unmapped character codes. This function parses
+ * the Character Metrics section only storing the width information
+ * for the encoded characters into the array using the character code
+ * as the index into that array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharWidths(FILE *fp, int *cwi)
+{
+ BOOL cont = TRUE, save = (cwi != NULL);
+ int pos = 0, error = ok;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp);
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Char Metrics section without */
+ /* saving any of the data*/
+ switch (recognize(keyword))
+ {
+ case ENDCHARMETRICS:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire char metrics section, saving */
+ /* only the char x-width info */
+ switch(recognize(keyword))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ keyword = token(fp);
+ pos = atoi(keyword);
+ break;
+ case XYWIDTH:
+ /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
+ keyword = token(fp); keyword = token(fp); /* eat values */
+ error = parseError;
+ break;
+ case XWIDTH:
+ keyword = token(fp);
+ if (pos >= 0) /* ignore unmapped chars */
+ cwi[pos] = atoi(keyword);
+ break;
+ case ENDCHARMETRICS:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ case CHARNAME: /* eat values (so doesn't cause parseError) */
+ keyword = token(fp);
+ break;
+ case CHARBBOX:
+ keyword = token(fp); keyword = token(fp);
+ keyword = token(fp); keyword = token(fp);
+ break;
+ case LIGATURE:
+ keyword = token(fp); keyword = token(fp);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseCharWidths */
+
+
+/************************* parseCharMetrics ************************/
+
+/* This function is called by parseFile if the caller of parseFile
+ * requested that all character metric information be saved
+ * (as opposed to only the character width information).
+ *
+ * parseCharMetrics is passed in a pointer to an array of records
+ * to hold information on a per character basis. This function
+ * parses the Character Metrics section storing all character
+ * metric information for the ALL characters (mapped and unmapped)
+ * into the array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharMetrics(FILE *fp, FontInfo *fi)
+{
+ BOOL cont = TRUE, firstTime = TRUE;
+ int error = ok, count = 0;
+ register CharMetricInfo *temp = fi->cmi;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if (count < fi->numOfChars)
+ {
+ if (firstTime) firstTime = FALSE;
+ else temp++;
+ temp->code = atoi(token(fp));
+ count++;
+ }
+ else
+ {
+ error = parseError;
+ cont = FALSE;
+ }
+ break;
+ case XYWIDTH:
+ temp->wx = atoi(token(fp));
+ temp->wy = atoi(token(fp));
+ break;
+ case XWIDTH:
+ temp->wx = atoi(token(fp));
+ break;
+ case CHARNAME:
+ keyword = token(fp);
+ temp->name = (char *) malloc(strlen(keyword) + 1);
+ strcpy(temp->name, keyword);
+ break;
+ case CHARBBOX:
+ temp->charBBox.llx = atoi(token(fp));
+ temp->charBBox.lly = atoi(token(fp));
+ temp->charBBox.urx = atoi(token(fp));
+ temp->charBBox.ury = atoi(token(fp));
+ break;
+ case LIGATURE: {
+ Ligature **tail = &(temp->ligs);
+ Ligature *node = *tail;
+
+ if (*tail != NULL)
+ {
+ while (node->next != NULL)
+ node = node->next;
+ tail = &(node->next);
+ }
+
+ *tail = (Ligature *) calloc(1, sizeof(Ligature));
+ keyword = token(fp);
+ (*tail)->succ = (char *) malloc(strlen(keyword) + 1);
+ strcpy((*tail)->succ, keyword);
+ keyword = token(fp);
+ (*tail)->lig = (char *) malloc(strlen(keyword) + 1);
+ strcpy((*tail)->lig, keyword);
+ break; }
+ case ENDCHARMETRICS:
+ cont = FALSE;;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = parseError;
+
+ return(error);
+
+} /* parseCharMetrics */
+
+
+
+/************************* parseTrackKernData ***********************/
+
+/* This function is called by "parseFile". It will parse the AFM File
+ * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
+ * track kerning data if requested by the caller of parseFile.
+ *
+ * parseTrackKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the track kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseTrackKernData(FILE *fp, FontInfo *fi)
+{
+ BOOL cont = TRUE, save = (fi->tkd != NULL);
+ int pos = 0, error = ok, tcount = 0;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Track Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword))
+ {
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Track Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case TRACKKERN:
+ if (tcount < fi->numOfTracks)
+ {
+ keyword = token(fp);
+ fi->tkd[pos].degree = atoi(keyword);
+ keyword = token(fp);
+ fi->tkd[pos].minPtSize = atof(keyword);
+ if (errno == ERANGE) error = parseError;
+ keyword = token(fp);
+ fi->tkd[pos].minKernAmt = atof(keyword);
+ if (errno == ERANGE) error = parseError;
+ keyword = token(fp);
+ fi->tkd[pos].maxPtSize = atof(keyword);
+ if (errno == ERANGE) error = parseError;
+ keyword = token(fp);
+ fi->tkd[pos++].maxKernAmt = atof(keyword);
+ if (errno == ERANGE) error = parseError;
+ tcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = FALSE;
+ }
+ break;
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = parseError;
+
+ return(error);
+
+} /* parseTrackKernData */
+
+
+/************************* parsePairKernData ************************/
+
+/* This function is called by "parseFile". It will parse the AFM File
+ * up to the "EndKernPairs" or "EndKernData" keywords. It will save
+ * the pair kerning data if requested by the caller of parseFile.
+ *
+ * parsePairKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the pair kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parsePairKernData(FILE *fp, FontInfo *fi)
+{
+ BOOL cont = TRUE, save = (fi->pkd != NULL);
+ int pos = 0, error = ok, pcount = 0;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Pair Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword))
+ {
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Pair Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case KERNPAIR:
+ if (pcount < fi->numOfPairs)
+ {
+ keyword = token(fp);
+ fi->pkd[pos].name1 = (char *)
+ malloc(strlen(keyword) + 1);
+ strcpy(fi->pkd[pos].name1, keyword);
+ keyword = token(fp);
+ fi->pkd[pos].name2 = (char *)
+ malloc(strlen(keyword) + 1);
+ strcpy(fi->pkd[pos].name2, keyword);
+ keyword = token(fp);
+ fi->pkd[pos].xamt = atoi(keyword);
+ keyword = token(fp);
+ fi->pkd[pos++].yamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = FALSE;
+ }
+ break;
+ case KERNPAIRXAMT:
+ if (pcount < fi->numOfPairs)
+ {
+ keyword = token(fp);
+ fi->pkd[pos].name1 = (char *)
+ malloc(strlen(keyword) + 1);
+ strcpy(fi->pkd[pos].name1, keyword);
+ keyword = token(fp);
+ fi->pkd[pos].name2 = (char *)
+ malloc(strlen(keyword) + 1);
+ strcpy(fi->pkd[pos].name2, keyword);
+ keyword = token(fp);
+ fi->pkd[pos++].xamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = FALSE;
+ }
+ break;
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && pcount != fi->numOfPairs)
+ error = parseError;
+
+ return(error);
+
+} /* parsePairKernData */
+
+
+/************************* parseCompCharData **************************/
+
+/* This function is called by "parseFile". It will parse the AFM File
+ * up to the "EndComposites" keyword. It will save the composite
+ * character data if requested by the caller of parseFile.
+ *
+ * parseCompCharData is passed in a pointer to the FontInfo record, and
+ * a boolean representing if the data should be saved.
+ *
+ * This function will create the appropriate amount of storage for
+ * the composite character data and store a pointer to the storage
+ * in the FontInfo record.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCompCharData(FILE *fp, FontInfo *fi)
+{
+ BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
+ int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (ccount > fi->numOfComps)
+ {
+ error = parseError;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Composite Character info */
+ /* section without saving any of the data */
+ switch(recognize(keyword))
+ {
+ case ENDCOMPOSITES:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Composite Character info section, */
+ /* saving the data */
+ switch(recognize(keyword))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case COMPCHAR:
+ if (ccount < fi->numOfComps)
+ {
+ keyword = token(fp);
+ if (pcount != fi->ccd[pos].numOfPieces)
+ error = parseError;
+ pcount = 0;
+ if (firstTime) firstTime = FALSE;
+ else pos++;
+ fi->ccd[pos].ccName = (char *)
+ malloc(strlen(keyword) + 1);
+ strcpy(fi->ccd[pos].ccName, keyword);
+ keyword = token(fp);
+ fi->ccd[pos].numOfPieces = atoi(keyword);
+ fi->ccd[pos].pieces = (Pcc *)
+ calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
+ j = 0;
+ ccount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = FALSE;
+ }
+ break;
+ case COMPCHARPIECE:
+ if (pcount < fi->ccd[pos].numOfPieces)
+ {
+ keyword = token(fp);
+ fi->ccd[pos].pieces[j].pccName = (char *)
+ malloc(strlen(keyword) + 1);
+ strcpy(fi->ccd[pos].pieces[j].pccName, keyword);
+ keyword = token(fp);
+ fi->ccd[pos].pieces[j].deltax = atoi(keyword);
+ keyword = token(fp);
+ fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
+ pcount++;
+ }
+ else
+ error = parseError;
+ break;
+ case ENDCOMPOSITES:
+ cont = FALSE;
+ break;
+ case ENDFONTMETRICS:
+ cont = FALSE;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && ccount != fi->numOfComps)
+ error = parseError;
+
+ return(error);
+
+} /* parseCompCharData */
+
+
+
+
+/*************************** 'PUBLIC' FUNCTION ********************/
+
+
+/*************************** parseFile *****************************/
+
+/* parseFile is the only 'public' procedure available. It is called
+ * from an application wishing to get information from an AFM file.
+ * The caller of this function is responsible for locating and opening
+ * an AFM file and handling all errors associated with that task.
+ *
+ * parseFile expects 3 parameters: a vaild file pointer, a pointer
+ * to a (FontInfo *) variable (for which storage will be allocated and
+ * the data requested filled in), and a mask specifying which
+ * data from the AFM File should be saved in the FontInfo structure.
+ *
+ * The file will be parsed and the requested data will be stored in
+ * a record of type FontInfo (refer to ParseAFM.h).
+ *
+ * parseFile returns an error code as defined in parseAFM.h.
+ *
+ * The position of the read/write pointer associated with the file
+ * pointer upon return of this function is undefined.
+ */
+
+extern int afm_parse_file(FILE *fp, FontInfo **fi, FLAGS flags)
+{
+
+ int code = ok; /* return code from each of the parsing routines */
+ int error = ok; /* used as the return code from this function */
+
+ register char *keyword; /* used to store a token */
+
+
+ /* storage data for the global variable ident */
+ ident = (char *) calloc(MAX_NAME, sizeof(char));
+ if (ident == NULL) {error = storageProblem; return(error);}
+
+ (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
+ if ((*fi) == NULL) {error = storageProblem; return(error);}
+
+ if (flags & P_G)
+ {
+ (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
+ if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}
+ }
+
+ /* The AFM File begins with Global Font Information. This section */
+ /* will be parsed whether or not information should be saved. */
+ code = parseGlobals(fp, (*fi)->gfi);
+
+ if (code < 0) error = code;
+
+ /* The Global Font Information is followed by the Character Metrics */
+ /* section. Which procedure is used to parse this section depends on */
+ /* how much information should be saved. If all of the metrics info */
+ /* is wanted, parseCharMetrics is called. If only the character widths */
+ /* is wanted, parseCharWidths is called. parseCharWidths will also */
+ /* be called in the case that no character data is to be saved, just */
+ /* to parse through the section. */
+
+ if ((code != normalEOF) && (code != earlyEOF))
+ {
+ (*fi)->numOfChars = atoi(token(fp));
+ if (flags & (P_M ^ P_W))
+ {
+ (*fi)->cmi = (CharMetricInfo *)
+ calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
+ if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
+ code = parseCharMetrics(fp, *fi);
+ }
+ else
+ {
+ if (flags & P_W)
+ {
+ (*fi)->cwi = (int *) calloc(256, sizeof(int));
+ if ((*fi)->cwi == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ }
+ /* parse section regardless */
+ code = parseCharWidths(fp, (*fi)->cwi);
+ } /* else */
+ } /* if */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ /* The remaining sections of the AFM are optional. This code will */
+ /* look at the next keyword in the file to determine what section */
+ /* is next, and then allocate the appropriate amount of storage */
+ /* for the data (if the data is to be saved) and call the */
+ /* appropriate parsing routine to parse the section. */
+
+ while ((code != normalEOF) && (code != earlyEOF))
+ {
+ keyword = token(fp);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ code = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword))
+ {
+ case STARTKERNDATA:
+ break;
+ case ENDKERNDATA:
+ break;
+ case STARTTRACKKERN:
+ keyword = token(fp);
+ if (flags & P_T)
+ {
+ (*fi)->numOfTracks = atoi(keyword);
+ (*fi)->tkd = (TrackKernData *)
+ calloc((*fi)->numOfTracks, sizeof(TrackKernData));
+ if ((*fi)->tkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseTrackKernData(fp, *fi);
+ break;
+ case STARTKERNPAIRS:
+ keyword = token(fp);
+ if (flags & P_P)
+ {
+ (*fi)->numOfPairs = atoi(keyword);
+ (*fi)->pkd = (PairKernData *)
+ calloc((*fi)->numOfPairs, sizeof(PairKernData));
+ if ((*fi)->pkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parsePairKernData(fp, *fi);
+ break;
+ case STARTCOMPOSITES:
+ keyword = token(fp);
+ if (flags & P_C)
+ {
+ (*fi)->numOfComps = atoi(keyword);
+ (*fi)->ccd = (CompCharData *)
+ calloc((*fi)->numOfComps, sizeof(CompCharData));
+ if ((*fi)->ccd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseCompCharData(fp, *fi);
+ break;
+ case ENDFONTMETRICS:
+ code = normalEOF;
+ break;
+ case NOPE:
+ default:
+ code = parseError;
+ break;
+ } /* switch */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ } /* while */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ if (ident != NULL) { free(ident); ident = NULL; }
+
+ return(error);
+
+} /* parseFile */
+
+/* added for MDVI: this function was copied from `parseAFMclient.c' */
+
+void afm_free_fontinfo(FontInfo *fi)
+{
+ if (fi != NULL)
+ {
+ if (fi->gfi != NULL)
+ {
+ free(fi->gfi->afmVersion); fi->gfi->afmVersion = NULL;
+ free(fi->gfi->fontName); fi->gfi->fontName = NULL;
+ free(fi->gfi->fullName); fi->gfi->fullName = NULL;
+ free(fi->gfi->familyName); fi->gfi->familyName = NULL;
+ free(fi->gfi->weight); fi->gfi->weight = NULL;
+ free(fi->gfi->version); fi->gfi->version = NULL;
+ free(fi->gfi->notice); fi->gfi->notice = NULL;
+ free(fi->gfi->encodingScheme); fi->gfi->encodingScheme = NULL;
+ free(fi->gfi); fi->gfi = NULL;
+ }
+
+ if (fi->cwi != NULL)
+ { free(fi->cwi); fi->cwi = NULL; }
+
+ if (fi->cmi != NULL)
+ {
+ int i = 0;
+ CharMetricInfo *temp = fi->cmi;
+ Ligature *node = temp->ligs;
+
+ for (i = 0; i < fi->numOfChars; ++i)
+ {
+ for (node = temp->ligs; node != NULL; node = node->next)
+ {
+ free(node->succ); node->succ = NULL;
+ free(node->lig); node->lig = NULL;
+ }
+
+ free(temp->name); temp->name = NULL;
+ temp++;
+ }
+
+ free(fi->cmi); fi->cmi = NULL;
+ }
+
+ if (fi->tkd != NULL)
+ { free(fi->tkd); fi->tkd = NULL; }
+
+ if (fi->pkd != NULL)
+ {
+ free(fi->pkd->name1); fi->pkd->name1 = NULL;
+ free(fi->pkd->name2); fi->pkd->name2 = NULL;
+ free(fi->pkd); fi->pkd = NULL;
+ }
+
+ if (fi->ccd != NULL)
+ {
+ int i = 0, j = 0;
+ CompCharData *ccd = fi->ccd;
+
+ for (i = 0; i < fi->numOfComps; ++i)
+ {
+ for (j = 0; j < ccd[i].numOfPieces; ++j)
+ {
+ free(ccd[i].pieces[j].pccName);
+ ccd[i].pieces[j].pccName = NULL;
+ }
+
+ free(ccd[i].ccName); ccd[i].ccName = NULL;
+ }
+
+ free(fi->ccd); fi->ccd = NULL;
+ }
+
+ free(fi);
+
+ } /* if */
+
+} /* afm_free_fontinfo */
+
+#endif /* WITH_AFM_FILES */
diff --git a/dviware/mdvi/lib/afmparse.h b/dviware/mdvi/lib/afmparse.h
new file mode 100644
index 0000000000..6cce780cdf
--- /dev/null
+++ b/dviware/mdvi/lib/afmparse.h
@@ -0,0 +1,307 @@
+/* modified for MDVI -- some names changed to avoid conflicts with T1lib */
+/*
+ * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/* ParseAFM.h
+ *
+ * This header file is used in conjuction with the parseAFM.c file.
+ * Together these files provide the functionality to parse Adobe Font
+ * Metrics files and store the information in predefined data structures.
+ * It is intended to work with an application program that needs font metric
+ * information. The program can be used as is by making a procedure call to
+ * parse an AFM file and have the data stored, or an application developer
+ * may wish to customize the code.
+ *
+ * This header file defines the data structures used as well as the key
+ * strings that are currently recognized by this version of the AFM parser.
+ * This program is based on the document "Adobe Font Metrics Files,
+ * Specification Version 2.0".
+ *
+ * AFM files are separated into distinct sections of different data. Because
+ * of this, the parseAFM program can parse a specified file to only save
+ * certain sections of information based on the application's needs. A record
+ * containing the requested information will be returned to the application.
+ *
+ * AFM files are divided into five sections of data:
+ * 1) The Global Font Information
+ * 2) The Character Metrics Information
+ * 3) The Track Kerning Data
+ * 4) The Pair-Wise Kerning Data
+ * 5) The Composite Character Data
+ *
+ * Basically, the application can request any of these sections independent
+ * of what other sections are requested. In addition, in recognizing that
+ * many applications will want ONLY the x-width of characters and not all
+ * of the other character metrics information, there is a way to receive
+ * only the width information so as not to pay the storage cost for the
+ * unwanted data. An application should never request both the
+ * "quick and dirty" char metrics (widths only) and the Character Metrics
+ * Information since the Character Metrics Information will contain all
+ * of the character widths as well.
+ *
+ * There is a procedure in parseAFM.c, called parseFile, that can be
+ * called from any application wishing to get information from the AFM File.
+ * This procedure expects 3 parameters: a vaild file descriptor, a pointer
+ * to a (FontInfo *) variable (for which space will be allocated and then
+ * will be filled in with the data requested), and a mask specifying
+ * which data from the AFM File should be saved in the FontInfo structure.
+ *
+ * The flags that can be used to set the appropriate mask are defined below.
+ * In addition, several commonly used masks have already been defined.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed typos
+ */
+#ifndef _MDVI_PARSEAFM_H
+#define _MDVI_PARSEAFM_H 1
+
+#include "sysdeps.h"
+
+#include <stdio.h>
+
+/* your basic constants */
+#define TRUE 1
+#define FALSE 0
+#define EOL '\n' /* end-of-line indicator */
+#define MAX_NAME 4096 /* max length for identifiers */
+#define BOOL int
+#define FLAGS int
+
+/* Flags that can be AND'ed together to specify exactly what
+ * information from the AFM file should be saved. */
+#define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
+#define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
+#define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
+#define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
+#define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
+#define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
+
+/* Commonly used flags */
+#define P_GW (P_G | P_W)
+#define P_GM (P_G | P_M)
+#define P_GMP (P_G | P_M | P_P)
+#define P_GMK (P_G | P_M | P_P | P_T)
+#define P_ALL (P_G | P_M | P_P | P_T | P_C)
+
+/* Possible return codes from the parseFile procedure.
+ *
+ * ok means there were no problems parsing the file.
+ *
+ * parseError means that there was some kind of parsing error, but the
+ * parser went on. This could include problems like the count for any given
+ * section does not add up to how many entries there actually were, or
+ * there was a key that was not recognized. The return record may contain
+ * vaild data or it may not.
+ *
+ * earlyEOF means that an End of File was encountered before expected. This
+ * may mean that the AFM file had been truncated, or improperly formed.
+ *
+ * storageProblem means that there were problems allocating storage for
+ * the data structures that would have contained the AFM data.
+ */
+#define ok 0
+#define parseError -1
+#define earlyEOF -2
+#define storageProblem -3
+
+/************************* TYPES *********************************/
+/* Below are all of the data structure definitions. These structures
+ * try to map as closely as possible to grouping and naming of data
+ * in the AFM Files.
+ */
+
+/* Bounding box definition. Used for the Font BBox as well as the
+ * Character BBox.
+ */
+typedef struct
+{
+ int llx; /* lower left x-position */
+ int lly; /* lower left y-position */
+ int urx; /* upper right x-position */
+ int ury; /* upper right y-position */
+} BBox;
+
+/* Global Font information.
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the AFM
+ * documentation (full title & version given above).
+ */
+typedef struct
+{
+ char *afmVersion; /* key: StartFontMetrics */
+ char *fontName; /* key: FontName */
+ char *fullName; /* key: FullName */
+ char *familyName; /* key: FamilyName */
+ char *weight; /* key: Weight */
+ float italicAngle; /* key: ItalicAngle */
+ BOOL isFixedPitch; /* key: IsFixedPitch */
+ BBox fontBBox; /* key: FontBBox */
+ int underlinePosition; /* key: UnderlinePosition */
+ int underlineThickness; /* key: UnderlineThickness */
+ char *version; /* key: Version */
+ char *notice; /* key: Notice */
+ char *encodingScheme; /* key: EncodingScheme */
+ int capHeight; /* key: CapHeight */
+ int xHeight; /* key: XHeight */
+ int ascender; /* key: Ascender */
+ int descender; /* key: Descender */
+} GlobalFontInfo;
+
+/* Ligature definition is a linked list since any character can have
+ * any number of ligatures.
+ */
+typedef struct _t_ligature
+{
+ char *succ, *lig;
+ struct _t_ligature *next;
+} Ligature;
+
+/* Character Metric Information. This structure is used only if ALL
+ * character metric information is requested. If only the character
+ * widths is requested, then only an array of the character x-widths
+ * is returned.
+ *
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the
+ * Character Metrics section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int code, /* key: C */
+ wx, /* key: WX */
+ wy; /* together wx and wy are associated with key: W */
+ char *name; /* key: N */
+ BBox charBBox; /* key: B */
+ Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */
+} CharMetricInfo;
+
+/* Track kerning data structure.
+ * The fields of this record are the five values associated with every
+ * TrackKern entry.
+ *
+ * For an explanation about each value please refer to the
+ * Track Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int degree;
+ float minPtSize,
+ minKernAmt,
+ maxPtSize,
+ maxKernAmt;
+} TrackKernData;
+
+/* Pair Kerning data structure.
+ * The fields of this record are the four values associated with every
+ * KP entry. For KPX entries, the yamt will be zero.
+ *
+ * For an explanation about each value please refer to the
+ * Pair Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *name1;
+ char *name2;
+ int xamt,
+ yamt;
+} PairKernData;
+
+/* PCC is a piece of a composite character. This is a sub structure of a
+ * compCharData described below.
+ * These fields will be filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *pccName;
+ int deltax,
+ deltay;
+} Pcc;
+
+/* Composite Character Information data structure.
+ * The fields ccName and numOfPieces are filled with the values associated
+ * with the key CC. The field pieces points to an array (size = numOfPieces)
+ * of information about each of the parts of the composite character. That
+ * array is filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *ccName;
+ int numOfPieces;
+ Pcc *pieces;
+} CompCharData;
+
+/* FontInfo
+ * Record type containing pointers to all of the other data
+ * structures containing information about a font.
+ * A a record of this type is filled with data by the
+ * parseFile function.
+ */
+typedef struct
+{
+ GlobalFontInfo *gfi; /* ptr to a GlobalFontInfo record */
+ int *cwi; /* ptr to 256 element array of just char widths */
+ int numOfChars; /* number of entries in char metrics array */
+ CharMetricInfo *cmi; /* ptr to char metrics array */
+ int numOfTracks; /* number to entries in track kerning array */
+ TrackKernData *tkd; /* ptr to track kerning array */
+ int numOfPairs; /* number to entries in pair kerning array */
+ PairKernData *pkd; /* ptr to pair kerning array */
+ int numOfComps; /* number to entries in comp char array */
+ CompCharData *ccd; /* ptr to comp char array */
+} FontInfo;
+
+/************************* PROCEDURES ****************************/
+
+/* Call this procedure to do the grunt work of parsing an AFM file.
+ *
+ * "fp" should be a valid file pointer to an AFM file.
+ *
+ * "fi" is a pointer to a pointer to a FontInfo record sturcture
+ * (defined above). Storage for the FontInfo structure will be
+ * allocated in parseFile and the structure will be filled in
+ * with the requested data from the AFM File.
+ *
+ * "flags" is a mask with bits set representing what data should
+ * be saved. Defined above are valid flags that can be used to set
+ * the mask, as well as a few commonly used masks.
+ *
+ * The possible return codes from parseFile are defined above.
+ */
+
+extern int afm_parse_file __PROTO((FILE *, FontInfo **, FLAGS));
+extern void afm_free_fontinfo __PROTO((FontInfo *));
+
+#endif /* _MDVI_PARSEAFM_H */
diff --git a/dviware/mdvi/lib/assoc.c b/dviware/mdvi/lib/assoc.c
new file mode 100644
index 0000000000..472f8bd9fe
--- /dev/null
+++ b/dviware/mdvi/lib/assoc.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "mdvi.h"
+
+typedef struct {
+ void *data;
+ DviFree2Func free_func;
+} DviAssoc;
+
+#define MDVI_ASSOC_SIZE 31
+
+static void assoc_free(DviHashKey key, void *ptr)
+{
+ DviAssoc *assoc = (DviAssoc *)ptr;
+
+ DEBUG((4, "Destroying association `%s'\n", (char *)key));
+ if(assoc->free_func)
+ assoc->free_func(key, assoc->data);
+ xfree(assoc);
+}
+
+int mdvi_assoc_put(DviContext *dvi, char *key, void *data, DviFree2Func f)
+{
+ DviAssoc *assoc;
+ int ok;
+
+ if(dvi->assoc.buckets == NULL) {
+ mdvi_hash_create(&dvi->assoc, MDVI_ASSOC_SIZE);
+ dvi->assoc.hash_free = assoc_free;
+ }
+ assoc = xalloc(DviAssoc);
+ assoc->data = data;
+ assoc->free_func = f;
+
+ ok = mdvi_hash_add(&dvi->assoc, MDVI_KEY(key),
+ assoc, MDVI_HASH_UNIQUE);
+ if(ok < 0) {
+ xfree(assoc);
+ return -1;
+ }
+ return 0;
+}
+
+void *mdvi_assoc_get(DviContext *dvi, char *key)
+{
+ DviAssoc *assoc;
+
+ if(dvi->assoc.buckets == NULL)
+ return NULL;
+ assoc = (DviAssoc *)mdvi_hash_lookup(&dvi->assoc, MDVI_KEY(key));
+ return assoc ? assoc->data : NULL;
+}
+
+void *mdvi_assoc_del(DviContext *dvi, char *key)
+{
+ DviAssoc *assoc;
+ void *ptr;
+
+ if(dvi->assoc.buckets == NULL)
+ return NULL;
+ assoc = mdvi_hash_remove(&dvi->assoc, MDVI_KEY(key));
+ if(assoc == NULL)
+ return NULL;
+ ptr = assoc->data;
+ xfree(assoc);
+ return ptr;
+}
+
+void mdvi_assoc_free(DviContext *dvi, char *key)
+{
+ if(dvi->assoc.buckets) {
+ /* this will call `assoc_free' */
+ mdvi_hash_destroy_key(&dvi->assoc, MDVI_KEY(key));
+ }
+}
+
+void mdvi_assoc_flush(DviContext *dvi)
+{
+ if(dvi->assoc.buckets)
+ mdvi_hash_reset(&dvi->assoc, 0);
+}
diff --git a/dviware/mdvi/lib/bitmap.c b/dviware/mdvi/lib/bitmap.c
new file mode 100644
index 0000000000..2d9d0e978f
--- /dev/null
+++ b/dviware/mdvi/lib/bitmap.c
@@ -0,0 +1,1111 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Bitmap manipulation routines */
+
+#include <stdlib.h>
+
+#include "mdvi.h"
+
+/* bit_masks[n] contains a BmUnit with `n' contiguous bits */
+
+static BmUnit bit_masks[] = {
+ 0x0, 0x1, 0x3, 0x7,
+ 0xf, 0x1f, 0x3f, 0x7f,
+ 0xff,
+#if BITMAP_BYTES > 1
+ 0x1ff, 0x3ff, 0x7ff,
+ 0xfff, 0x1fff, 0x3fff, 0x7fff,
+ 0xffff,
+#if BITMAP_BYTES > 2
+ 0x1ffff, 0x3ffff, 0x7ffff,
+ 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
+ 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff,
+ 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff
+#endif /* BITMAP_BYTES > 2 */
+#endif /* BITMAP_BYTES > 1 */
+};
+
+#ifndef NODEBUG
+#define SHOW_OP_DATA (DEBUGGING(BITMAP_OPS) && DEBUGGING(BITMAP_DATA))
+#endif
+
+/* cache for color tables, to avoid creating them for every glyph */
+typedef struct {
+ Ulong fg;
+ Ulong bg;
+ Uint nlevels;
+ Ulong *pixels;
+ int density;
+ double gamma;
+ Uint hits;
+} ColorCache;
+
+/*
+ * Some useful macros to manipulate bitmap data
+ * SEGMENT(m,n) = bit mask for a segment of `m' contiguous bits
+ * starting at column `n'. These macros assume that
+ * m + n <= BITMAP_BITS, 0 <= m, n.
+ */
+#ifdef WORD_BIG_ENDIAN
+#define SEGMENT(m,n) (bit_masks[m] << (BITMAP_BITS - (m) - (n)))
+#else
+#define SEGMENT(m,n) (bit_masks[m] << (n))
+#endif
+
+/* sampling and shrinking routines shamelessly stolen from xdvi */
+
+static int sample_count[] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+/* bit_swap[j] = j with all bits inverted (i.e. msb -> lsb) */
+static Uchar bit_swap[] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+#define CCSIZE 256
+static ColorCache color_cache[CCSIZE];
+static int cc_entries;
+
+#define GAMMA_DIFF 0.005
+
+/* create a color table */
+Ulong *get_color_table(DviDevice *dev,
+ int nlevels, Ulong fg, Ulong bg, double gamma, int density)
+{
+ ColorCache *cc, *tofree;
+ int lohits;
+ Ulong *pixels;
+ int status;
+
+ lohits = color_cache[0].hits;
+ tofree = &color_cache[0];
+ /* look in the cache and see if we have one that matches this request */
+ for(cc = &color_cache[0]; cc < &color_cache[cc_entries]; cc++) {
+ if(cc->hits < lohits) {
+ lohits = cc->hits;
+ tofree = cc;
+ }
+ if(cc->fg == fg && cc->bg == bg && cc->density == density &&
+ cc->nlevels == nlevels && fabs(cc->gamma - gamma) <= GAMMA_DIFF)
+ break;
+ }
+
+ if(cc < &color_cache[cc_entries]) {
+ cc->hits++;
+ return cc->pixels;
+ }
+
+ DEBUG((DBG_DEVICE, "Adding color table to cache (fg=%lu, bg=%lu, n=%d)\n",
+ fg, bg, nlevels));
+
+ /* no entry was found in the cache, create a new one */
+ if(cc_entries < CCSIZE) {
+ cc = &color_cache[cc_entries++];
+ cc->pixels = NULL;
+ } else {
+ cc = tofree;
+ xfree(cc->pixels);
+ }
+ pixels = xnalloc(Ulong, nlevels);
+ status = dev->alloc_colors(dev->device_data,
+ pixels, nlevels, fg, bg, gamma, density);
+ if(status < 0) {
+ xfree(pixels);
+ return NULL;
+ }
+ cc->fg = fg;
+ cc->bg = bg;
+ cc->gamma = gamma;
+ cc->density = density;
+ cc->nlevels = nlevels;
+ cc->pixels = pixels;
+ cc->hits = 1;
+ return pixels;
+}
+
+void flush_color_table(void)
+{
+ ColorCache *cc;
+
+ for(cc = &color_cache[0]; cc < &color_cache[cc_entries]; cc++)
+ xfree(cc->pixels);
+ cc_entries = 0;
+}
+
+/*
+ * next we have three bitmap functions to convert bitmaps in LSB bit order
+ * with 8, 16 and 32 bits per unit, to our internal format. The differences
+ * are minimal, but writing a generic function to handle all unit sizes is
+ * hopelessly slow.
+ */
+
+BITMAP *bitmap_convert_lsb8(Uchar *bits, int w, int h)
+{
+ BITMAP *bm;
+ int i;
+ Uchar *unit;
+ register Uchar *curr;
+ Uchar *end;
+ int bytes;
+
+ DEBUG((DBG_BITMAP_OPS, "convert LSB %dx%d@8 -> bitmap\n", w, h));
+
+ bm = bitmap_alloc_raw(w, h);
+
+ /* this is the number of bytes in the original bitmap */
+ bytes = ROUND(w, 8);
+ unit = (Uchar *)bm->data;
+ end = unit + bm->stride;
+ curr = bits;
+ /* we try to do this as fast as we can */
+ for(i = 0; i < h; i++) {
+#ifdef WORD_LITTLE_ENDIAN
+ memcpy(unit, curr, bytes);
+ curr += bytes;
+#else
+ int j;
+
+ for(j = 0; j < bytes; curr++, j++)
+ unit[j] = bit_swap[*curr];
+#endif
+ memzero(unit + bytes, bm->stride - bytes);
+ unit += bm->stride;
+ }
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+ return bm;
+}
+
+BITMAP *bitmap_convert_msb8(Uchar *data, int w, int h)
+{
+ BITMAP *bm;
+ Uchar *unit;
+ Uchar *curr;
+ int i;
+ int bytes;
+
+ bm = bitmap_alloc(w, h);
+ bytes = ROUND(w, 8);
+ unit = (Uchar *)bm->data;
+ curr = data;
+ for(i = 0; i < h; i++) {
+#ifdef WORD_LITTLE_ENDIAN
+ int j;
+
+ for(j = 0; j < bytes; curr++, j++)
+ unit[j] = bit_swap[*curr];
+#else
+ memcpy(unit, curr, bytes);
+ curr += bytes;
+#endif
+ memzero(unit + bytes, bm->stride - bytes);
+ unit += bm->stride;
+ }
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+ return bm;
+}
+
+
+BITMAP *bitmap_copy(BITMAP *bm)
+{
+ BITMAP *nb = bitmap_alloc(bm->width, bm->height);
+
+ DEBUG((DBG_BITMAP_OPS, "copy %dx%d\n", bm->width, bm->height));
+ memcpy(nb->data, bm->data, bm->height * bm->stride);
+ return nb;
+}
+
+BITMAP *bitmap_alloc(int w, int h)
+{
+ BITMAP *bm;
+
+ bm = xalloc(BITMAP);
+ bm->width = w;
+ bm->height = h;
+ bm->stride = BM_BYTES_PER_LINE(bm);
+ if(h && bm->stride)
+ bm->data = (BmUnit *)xcalloc(h, bm->stride);
+ else
+ bm->data = NULL;
+
+ return bm;
+}
+
+BITMAP *bitmap_alloc_raw(int w, int h)
+{
+ BITMAP *bm;
+
+ bm = xalloc(BITMAP);
+ bm->width = w;
+ bm->height = h;
+ bm->stride = BM_BYTES_PER_LINE(bm);
+ if(h && bm->stride)
+ bm->data = (BmUnit *)xmalloc(h * bm->stride);
+ else
+ bm->data = NULL;
+
+ return bm;
+}
+
+void bitmap_destroy(BITMAP *bm)
+{
+ if(bm->data)
+ free(bm->data);
+ free(bm);
+}
+
+void bitmap_print(FILE *out, BITMAP *bm)
+{
+ int i, j;
+ BmUnit *a, mask;
+ static const char labels[] = {
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'
+ };
+ int sub;
+
+ a = bm->data;
+ fprintf(out, " ");
+ if(bm->width > 10) {
+ putchar('0');
+ sub = 0;
+ for(j = 2; j <= bm->width; j++)
+ if((j %10) == 0) {
+ if((j % 100) == 0) {
+ fprintf(out, "*");
+ sub += 100;
+ } else
+ fprintf(out, "%d", (j - sub)/10);
+ } else
+ putc(' ', out);
+ fprintf(out, "\n ");
+ }
+ for(j = 0; j < bm->width; j++)
+ putc(labels[j % 10], out);
+ putchar('\n');
+ for(i = 0; i < bm->height; i++) {
+ mask = FIRSTMASK;
+ a = (BmUnit *)((char *)bm->data + i * bm->stride);
+ fprintf(out, "%3d ", i+1);
+ for(j = 0; j < bm->width; j++) {
+ if(*a & mask)
+ putc('#', out);
+ else
+ putc('.', out);
+ if(mask == LASTMASK) {
+ a++;
+ mask = FIRSTMASK;
+ } else
+ NEXTMASK(mask);
+ }
+ putchar('\n');
+ }
+}
+
+void bitmap_set_col(BITMAP *bm, int row, int col, int count, int state)
+{
+ BmUnit *ptr;
+ BmUnit mask;
+
+ ptr = __bm_unit_ptr(bm, col, row);
+ mask = FIRSTMASKAT(col);
+
+ while(count-- > 0) {
+ if(state)
+ *ptr |= mask;
+ else
+ *ptr &= ~mask;
+ /* move to next row */
+ ptr = bm_offset(ptr, bm->stride);
+ }
+}
+
+/*
+ * to use this function you should first make sure that
+ * there is room for `count' bits in the scanline
+ *
+ * A general-purpose (but not very efficient) function to paint `n' pixels
+ * on a bitmap, starting at position (x, y) would be:
+ *
+ * bitmap_paint_bits(__bm_unit_ptr(bitmap, x, y), x % BITMAP_BITS, n)
+ *
+ */
+void bitmap_paint_bits(BmUnit *ptr, int n, int count)
+{
+ /* paint the head */
+ if(n + count > BITMAP_BITS) {
+ *ptr |= SEGMENT(BITMAP_BITS - n, n);
+ count -= BITMAP_BITS - n;
+ ptr++;
+ } else {
+ *ptr |= SEGMENT(count, n);
+ return;
+ }
+
+ /* paint the middle */
+ for(; count >= BITMAP_BITS; count -= BITMAP_BITS)
+ *ptr++ = bit_masks[BITMAP_BITS];
+
+ /* paint the tail */
+ if(count > 0)
+ *ptr |= SEGMENT(count, 0);
+}
+
+/*
+ * same as paint_bits but clears pixels instead of painting them. Written
+ * as a separate function for efficiency reasons.
+ */
+void bitmap_clear_bits(BmUnit *ptr, int n, int count)
+{
+ if(n + count > BITMAP_BITS) {
+ *ptr &= ~SEGMENT(BITMAP_BITS - n, n);
+ count -= BITMAP_BITS;
+ ptr++;
+ } else {
+ *ptr &= ~SEGMENT(count, n);
+ return;
+ }
+
+ for(; count >= BITMAP_BITS; count -= BITMAP_BITS)
+ *ptr++ = 0;
+
+ if(count > 0)
+ *ptr &= ~SEGMENT(count, 0);
+}
+
+/* the general function to paint rows. Still used by the PK reader, but that
+ * will change soon (The GF reader already uses bitmap_paint_bits()).
+ */
+void bitmap_set_row(BITMAP *bm, int row, int col, int count, int state)
+{
+ BmUnit *ptr;
+
+ ptr = __bm_unit_ptr(bm, col, row);
+ if(state)
+ bitmap_paint_bits(ptr, col & (BITMAP_BITS-1), count);
+ else
+ bitmap_clear_bits(ptr, col & (BITMAP_BITS-1), count);
+}
+
+/*
+ * Now several `flipping' operations
+ */
+
+void bitmap_flip_horizontally(BITMAP *bm)
+{
+ BITMAP nb;
+ BmUnit *fptr, *tptr;
+ BmUnit fmask, tmask;
+ int w, h;
+
+ nb.width = bm->width;
+ nb.height = bm->height;
+ nb.stride = bm->stride;
+ nb.data = xcalloc(bm->height, bm->stride);
+
+ fptr = bm->data;
+ tptr = __bm_unit_ptr(&nb, nb.width-1, 0);
+ for(h = 0; h < bm->height; h++) {
+ BmUnit *fline, *tline;
+
+ fline = fptr;
+ tline = tptr;
+ fmask = FIRSTMASK;
+ tmask = FIRSTMASKAT(nb.width-1);
+ for(w = 0; w < bm->width; w++) {
+ if(*fline & fmask)
+ *tline |= tmask;
+ if(fmask == LASTMASK) {
+ fmask = FIRSTMASK;
+ fline++;
+ } else
+ NEXTMASK(fmask);
+ if(tmask == FIRSTMASK) {
+ tmask = LASTMASK;
+ tline--;
+ } else
+ PREVMASK(tmask);
+ }
+ fptr = bm_offset(fptr, bm->stride);
+ tptr = bm_offset(tptr, bm->stride);
+ }
+ DEBUG((DBG_BITMAP_OPS, "flip_horizontally (%d,%d) -> (%d,%d)\n",
+ bm->width, bm->height, nb.width, nb.height));
+ xfree(bm->data);
+ bm->data = nb.data;
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+}
+
+void bitmap_flip_vertically(BITMAP *bm)
+{
+ BITMAP nb;
+ BmUnit *fptr, *tptr;
+ BmUnit fmask;
+ int w, h;
+
+ nb.width = bm->width;
+ nb.height = bm->height;
+ nb.stride = bm->stride;
+ nb.data = xcalloc(bm->height, bm->stride);
+
+ fptr = bm->data;
+ tptr = __bm_unit_ptr(&nb, 0, nb.height-1);
+ for(h = 0; h < bm->height; h++) {
+ BmUnit *fline, *tline;
+
+ fline = fptr;
+ tline = tptr;
+ fmask = FIRSTMASK;
+ for(w = 0; w < bm->width; w++) {
+ if(*fline & fmask)
+ *tline |= fmask;
+ if(fmask == LASTMASK) {
+ fmask = FIRSTMASK;
+ fline++;
+ tline++;
+ } else
+ NEXTMASK(fmask);
+ }
+ fptr = bm_offset(fptr, bm->stride);
+ tptr = (BmUnit *)((char *)tptr - bm->stride);
+ }
+ DEBUG((DBG_BITMAP_OPS, "flip_vertically (%d,%d) -> (%d,%d)\n",
+ bm->width, bm->height, nb.width, nb.height));
+ xfree(bm->data);
+ bm->data = nb.data;
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+}
+
+void bitmap_flip_diagonally(BITMAP *bm)
+{
+ BITMAP nb;
+ BmUnit *fptr, *tptr;
+ BmUnit fmask, tmask;
+ int w, h;
+
+ nb.width = bm->width;
+ nb.height = bm->height;
+ nb.stride = bm->stride;
+ nb.data = xcalloc(bm->height, bm->stride);
+
+ fptr = bm->data;
+ tptr = __bm_unit_ptr(&nb, nb.width-1, nb.height-1);
+ for(h = 0; h < bm->height; h++) {
+ BmUnit *fline, *tline;
+
+ fline = fptr;
+ tline = tptr;
+ fmask = FIRSTMASK;
+ tmask = FIRSTMASKAT(nb.width-1);
+ for(w = 0; w < bm->width; w++) {
+ if(*fline & fmask)
+ *tline |= tmask;
+ if(fmask == LASTMASK) {
+ fmask = FIRSTMASK;
+ fline++;
+ } else
+ NEXTMASK(fmask);
+ if(tmask == FIRSTMASK) {
+ tmask = LASTMASK;
+ tline--;
+ } else
+ PREVMASK(tmask);
+ }
+ fptr = bm_offset(fptr, bm->stride);
+ tptr = bm_offset(tptr, -nb.stride);
+ }
+ DEBUG((DBG_BITMAP_OPS, "flip_diagonally (%d,%d) -> (%d,%d)\n",
+ bm->width, bm->height, nb.width, nb.height));
+ xfree(bm->data);
+ bm->data = nb.data;
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+}
+
+void bitmap_rotate_clockwise(BITMAP *bm)
+{
+ BITMAP nb;
+ BmUnit *fptr, *tptr;
+ BmUnit fmask, tmask;
+ int w, h;
+
+ nb.width = bm->height;
+ nb.height = bm->width;
+ nb.stride = BM_BYTES_PER_LINE(&nb);
+ nb.data = xcalloc(nb.height, nb.stride);
+
+ fptr = bm->data;
+ tptr = __bm_unit_ptr(&nb, nb.width - 1, 0);
+
+ tmask = FIRSTMASKAT(nb.width-1);
+ for(h = 0; h < bm->height; h++) {
+ BmUnit *fline, *tline;
+
+ fmask = FIRSTMASK;
+ fline = fptr;
+ tline = tptr;
+ for(w = 0; w < bm->width; w++) {
+ if(*fline & fmask)
+ *tline |= tmask;
+ if(fmask == LASTMASK) {
+ fmask = FIRSTMASK;
+ fline++;
+ } else
+ NEXTMASK(fmask);
+ /* go to next row */
+ tline = bm_offset(tline, nb.stride);
+ }
+ fptr = bm_offset(fptr, bm->stride);
+ if(tmask == FIRSTMASK) {
+ tmask = LASTMASK;
+ tptr--;
+ } else
+ PREVMASK(tmask);
+ }
+
+ DEBUG((DBG_BITMAP_OPS, "rotate_clockwise (%d,%d) -> (%d,%d)\n",
+ bm->width, bm->height, nb.width, nb.height));
+ xfree(bm->data);
+ bm->data = nb.data;
+ bm->width = nb.width;
+ bm->height = nb.height;
+ bm->stride = nb.stride;
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+}
+
+void bitmap_rotate_counter_clockwise(BITMAP *bm)
+{
+ BITMAP nb;
+ BmUnit *fptr, *tptr;
+ BmUnit fmask, tmask;
+ int w, h;
+
+ nb.width = bm->height;
+ nb.height = bm->width;
+ nb.stride = BM_BYTES_PER_LINE(&nb);
+ nb.data = xcalloc(nb.height, nb.stride);
+
+ fptr = bm->data;
+ tptr = __bm_unit_ptr(&nb, 0, nb.height - 1);
+
+ tmask = FIRSTMASK;
+ for(h = 0; h < bm->height; h++) {
+ BmUnit *fline, *tline;
+
+ fmask = FIRSTMASK;
+ fline = fptr;
+ tline = tptr;
+ for(w = 0; w < bm->width; w++) {
+ if(*fline & fmask)
+ *tline |= tmask;
+ if(fmask == LASTMASK) {
+ fmask = FIRSTMASK;
+ fline++;
+ } else
+ NEXTMASK(fmask);
+ /* go to previous row */
+ tline = bm_offset(tline, -nb.stride);
+ }
+ fptr = bm_offset(fptr, bm->stride);
+ if(tmask == LASTMASK) {
+ tmask = FIRSTMASK;
+ tptr++;
+ } else
+ NEXTMASK(tmask);
+ }
+
+ DEBUG((DBG_BITMAP_OPS, "rotate_counter_clockwise (%d,%d) -> (%d,%d)\n",
+ bm->width, bm->height, nb.width, nb.height));
+ xfree(bm->data);
+ bm->data = nb.data;
+ bm->width = nb.width;
+ bm->height = nb.height;
+ bm->stride = nb.stride;
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+}
+
+void bitmap_flip_rotate_clockwise(BITMAP *bm)
+{
+ BITMAP nb;
+ BmUnit *fptr, *tptr;
+ BmUnit fmask, tmask;
+ int w, h;
+
+ nb.width = bm->height;
+ nb.height = bm->width;
+ nb.stride = BM_BYTES_PER_LINE(&nb);
+ nb.data = xcalloc(nb.height, nb.stride);
+
+ fptr = bm->data;
+ tptr = __bm_unit_ptr(&nb, nb.width-1, nb.height-1);
+
+ tmask = FIRSTMASKAT(nb.width-1);
+ for(h = 0; h < bm->height; h++) {
+ BmUnit *fline, *tline;
+
+ fmask = FIRSTMASK;
+ fline = fptr;
+ tline = tptr;
+ for(w = 0; w < bm->width; w++) {
+ if(*fline & fmask)
+ *tline |= tmask;
+ if(fmask == LASTMASK) {
+ fmask = FIRSTMASK;
+ fline++;
+ } else
+ NEXTMASK(fmask);
+ /* go to previous line */
+ tline = bm_offset(tline, -nb.stride);
+ }
+ fptr = bm_offset(fptr, bm->stride);
+ if(tmask == FIRSTMASK) {
+ tmask = LASTMASK;
+ tptr--;
+ } else
+ PREVMASK(tmask);
+ }
+ DEBUG((DBG_BITMAP_OPS, "flip_rotate_clockwise (%d,%d) -> (%d,%d)\n",
+ bm->width, bm->height, nb.width, nb.height));
+ xfree(bm->data);
+ bm->data = nb.data;
+ bm->width = nb.width;
+ bm->height = nb.height;
+ bm->stride = nb.stride;
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+}
+
+void bitmap_flip_rotate_counter_clockwise(BITMAP *bm)
+{
+ BITMAP nb;
+ BmUnit *fptr, *tptr;
+ BmUnit fmask, tmask;
+ int w, h;
+
+ nb.width = bm->height;
+ nb.height = bm->width;
+ nb.stride = BM_BYTES_PER_LINE(&nb);
+ nb.data = xcalloc(nb.height, nb.stride);
+
+ fptr = bm->data;
+ tptr = nb.data;
+ tmask = FIRSTMASK;
+
+ for(h = 0; h < bm->height; h++) {
+ BmUnit *fline, *tline;
+
+ fmask = FIRSTMASK;
+ fline = fptr;
+ tline = tptr;
+ for(w = 0; w < bm->width; w++) {
+ if(*fline & fmask)
+ *tline |= tmask;
+ if(fmask == LASTMASK) {
+ fmask = FIRSTMASK;
+ fline++;
+ } else
+ NEXTMASK(fmask);
+ /* go to next line */
+ tline = bm_offset(tline, nb.stride);
+ }
+ fptr = bm_offset(fptr, bm->stride);
+ if(tmask == LASTMASK) {
+ tmask = FIRSTMASK;
+ tptr++;
+ } else
+ NEXTMASK(tmask);
+ }
+
+ DEBUG((DBG_BITMAP_OPS, "flip_rotate_counter_clockwise (%d,%d) -> (%d,%d)\n",
+ bm->width, bm->height, nb.width, nb.height));
+ xfree(bm->data);
+ bm->data = nb.data;
+ bm->width = nb.width;
+ bm->height = nb.height;
+ bm->stride = nb.stride;
+ if(SHOW_OP_DATA)
+ bitmap_print(stderr, bm);
+}
+
+#if 0
+void bitmap_transform(BITMAP *map, DviOrientation orient)
+{
+ switch(orient) {
+ case MDVI_ORIENT_TBLR:
+ break;
+ case MDVI_ORIENT_TBRL:
+ bitmap_flip_horizontally(map);
+ break;
+ case MDVI_ORIENT_BTLR:
+ bitmap_flip_vertically(map);
+ break;
+ case MDVI_ORIENT_BTRL:
+ bitmap_flip_diagonally(map);
+ break;
+ case MDVI_ORIENT_RP90:
+ bitmap_rotate_counter_clockwise(map);
+ break;
+ case MDVI_ORIENT_RM90:
+ bitmap_rotate_clockwise(map);
+ break;
+ case MDVI_ORIENT_IRP90:
+ bitmap_flip_rotate_counter_clockwise(map);
+ break;
+ case MDVI_ORIENT_IRM90:
+ bitmap_flip_rotate_clockwise(map);
+ break;
+ }
+}
+#endif
+
+/*
+ * Count the number of non-zero bits in a box of dimensions w x h, starting
+ * at column `step' in row `data'.
+ *
+ * Shamelessly stolen from xdvi.
+ */
+static int do_sample(BmUnit *data, int stride, int step, int w, int h)
+{
+ BmUnit *ptr, *end, *cp;
+ int shift, n;
+ int bits_left;
+ int wid;
+
+ ptr = data + step / BITMAP_BITS;
+ end = bm_offset(data, h * stride);
+ shift = FIRSTSHIFTAT(step);
+ bits_left = w;
+ n = 0;
+ while(bits_left) {
+#ifndef WORD_BIG_ENDIAN
+ wid = BITMAP_BITS - shift;
+#else
+ wid = shift;
+#endif
+ if(wid > bits_left)
+ wid = bits_left;
+ if(wid > 8)
+ wid = 8;
+#ifdef WORD_BIG_ENDIAN
+ shift -= wid;
+#endif
+ for(cp = ptr; cp < end; cp = bm_offset(cp, stride))
+ n += sample_count[(*cp >> shift) & bit_masks[wid]];
+#ifndef WORD_BIG_ENDIAN
+ shift += wid;
+#endif
+#ifdef WORD_BIG_ENDIAN
+ if(shift == 0) {
+ shift = BITMAP_BITS;
+ ptr++;
+ }
+#else
+ if(shift == BITMAP_BITS) {
+ shift = 0;
+ ptr++;
+ }
+#endif
+ bits_left -= wid;
+ }
+ return n;
+}
+
+void mdvi_shrink_box(DviContext *dvi, DviFont *font,
+ DviFontChar *pk, DviGlyph *dest)
+{
+ int x, y, z;
+ DviGlyph *glyph;
+ int hs, vs;
+
+ hs = dvi->params.hshrink;
+ vs = dvi->params.vshrink;
+ glyph = &pk->glyph;
+
+ x = (int)glyph->x / hs;
+ if((int)glyph->x - x * hs > 0)
+ x++;
+ dest->w = x + ROUND((int)glyph->w - glyph->x, hs);
+
+ z = (int)glyph->y + 1;
+ y = z / vs;
+ if(z - y * vs <= 0)
+ y--;
+ dest->h = y + ROUND((int)glyph->h - z, vs) + 1;
+ dest->x = x;
+ dest->y = glyph->y / vs;
+ dest->data = MDVI_GLYPH_EMPTY;
+ DEBUG((DBG_BITMAPS, "shrink_box: (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
+ glyph->w, glyph->h, glyph->x, glyph->y,
+ dest->w, dest->h, dest->x, dest->y));
+}
+
+void mdvi_shrink_glyph(DviContext *dvi, DviFont *font,
+ DviFontChar *pk, DviGlyph *dest)
+{
+ int rows_left, rows, init_cols;
+ int cols_left, cols;
+ BmUnit *old_ptr, *new_ptr;
+ BITMAP *oldmap, *newmap;
+ BmUnit m, *cp;
+ DviGlyph *glyph;
+ int sample, min_sample;
+ int old_stride;
+ int new_stride;
+ int x, y;
+ int w, h;
+ int hs, vs;
+
+ hs = dvi->params.hshrink;
+ vs = dvi->params.vshrink;
+
+ min_sample = vs * hs * dvi->params.density / 100;
+
+ glyph = &pk->glyph;
+ oldmap = (BITMAP *)glyph->data;
+
+ x = (int)glyph->x / hs;
+ init_cols = (int)glyph->x - x * hs;
+ if(init_cols <= 0)
+ init_cols += hs;
+ else
+ x++;
+ w = x + ROUND((int)glyph->w - glyph->x, hs);
+
+ cols = (int)glyph->y + 1;
+ y = cols / vs;
+ rows = cols - y * vs;
+ if(rows <= 0) {
+ rows += vs;
+ y--;
+ }
+ h = y + ROUND((int)glyph->h - cols, vs) + 1;
+
+ /* create the new glyph */
+ newmap = bitmap_alloc(w, h);
+ dest->data = newmap;
+ dest->x = x;
+ dest->y = glyph->y / vs;
+ dest->w = w;
+ dest->h = h;
+
+ old_ptr = oldmap->data;
+ old_stride = oldmap->stride;
+ new_ptr = newmap->data;
+ new_stride = newmap->stride;
+ rows_left = glyph->h;
+
+ while(rows_left) {
+ if(rows > rows_left)
+ rows = rows_left;
+ cols_left = glyph->w;
+ m = FIRSTMASK;
+ cp = new_ptr;
+ cols = init_cols;
+ while(cols_left > 0) {
+ if(cols > cols_left)
+ cols = cols_left;
+ sample = do_sample(old_ptr, old_stride,
+ glyph->w - cols_left, cols, rows);
+ if(sample >= min_sample)
+ *cp |= m;
+ if(m == LASTMASK) {
+ m = FIRSTMASK;
+ cp++;
+ } else
+ NEXTMASK(m);
+ cols_left -= cols;
+ cols = hs;
+ }
+ new_ptr = bm_offset(new_ptr, new_stride);
+ old_ptr = bm_offset(old_ptr, rows * old_stride);
+ rows_left -= rows;
+ rows = vs;
+ }
+ DEBUG((DBG_BITMAPS, "shrink_glyph: (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
+ glyph->w, glyph->h, glyph->x, glyph->y,
+ dest->w, dest->h, dest->x, dest->y));
+ if(DEBUGGING(BITMAP_DATA))
+ bitmap_print(stderr, newmap);
+}
+
+void mdvi_shrink_glyph_grey(DviContext *dvi, DviFont *font,
+ DviFontChar *pk, DviGlyph *dest)
+{
+ int rows_left, rows;
+ int cols_left, cols, init_cols;
+ long sampleval, samplemax;
+ BmUnit *old_ptr;
+ void *image;
+ int w, h;
+ int x, y;
+ DviGlyph *glyph;
+ BITMAP *map;
+ Ulong *pixels;
+ int npixels;
+ Ulong colortab[2];
+ int hs, vs;
+ DviDevice *dev;
+
+ hs = dvi->params.hshrink;
+ vs = dvi->params.vshrink;
+ dev = &dvi->device;
+
+ glyph = &pk->glyph;
+ map = (BITMAP *)glyph->data;
+
+ x = (int)glyph->x / hs;
+ init_cols = (int)glyph->x - x * hs;
+ if(init_cols <= 0)
+ init_cols += hs;
+ else
+ x++;
+ w = x + ROUND((int)glyph->w - glyph->x, hs);
+
+ cols = (int)glyph->y + 1;
+ y = cols / vs;
+ rows = cols - y * vs;
+ if(rows <= 0) {
+ rows += vs;
+ y--;
+ }
+ h = y + ROUND((int)glyph->h - cols, vs) + 1;
+ ASSERT(w && h);
+
+ /* before touching anything, do this */
+ image = dev->create_image(dev->device_data, w, h, BITMAP_BITS);
+ if(image == NULL) {
+ mdvi_shrink_glyph(dvi, font, pk, dest);
+ return;
+ }
+
+ /* save these colors */
+ pk->fg = MDVI_CURRFG(dvi);
+ pk->bg = MDVI_CURRBG(dvi);
+
+ samplemax = vs * hs;
+ npixels = samplemax + 1;
+ pixels = get_color_table(&dvi->device, npixels, pk->fg, pk->bg,
+ dvi->params.gamma, dvi->params.density);
+ if(pixels == NULL) {
+ npixels = 2;
+ colortab[0] = pk->fg;
+ colortab[1] = pk->bg;
+ pixels = &colortab[0];
+ }
+
+ /* setup the new glyph */
+ dest->data = image;
+ dest->x = x;
+ dest->y = glyph->y / vs;
+ dest->w = w;
+ dest->h = h;
+
+ y = 0;
+ old_ptr = map->data;
+ rows_left = glyph->h;
+
+ while(rows_left && y < h) {
+ x = 0;
+ if(rows > rows_left)
+ rows = rows_left;
+ cols_left = glyph->w;
+ cols = init_cols;
+ while(cols_left && x < w) {
+ if(cols > cols_left)
+ cols = cols_left;
+ sampleval = do_sample(old_ptr, map->stride,
+ glyph->w - cols_left, cols, rows);
+ /* scale the sample value by the number of grey levels */
+ if(npixels - 1 != samplemax)
+ sampleval = ((npixels-1) * sampleval) / samplemax;
+ ASSERT(sampleval < npixels);
+ dev->put_pixel(image, x, y, pixels[sampleval]);
+ cols_left -= cols;
+ cols = hs;
+ x++;
+ }
+ for(; x < w; x++)
+ dev->put_pixel(image, x, y, pixels[0]);
+ old_ptr = bm_offset(old_ptr, rows * map->stride);
+ rows_left -= rows;
+ rows = vs;
+ y++;
+ }
+
+ for(; y < h; y++) {
+ for(x = 0; x < w; x++)
+ dev->put_pixel(image, x, y, pixels[0]);
+ }
+ DEBUG((DBG_BITMAPS, "shrink_glyph_grey: (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
+ glyph->w, glyph->h, glyph->x, glyph->y,
+ dest->w, dest->h, dest->x, dest->y));
+}
+
diff --git a/dviware/mdvi/lib/common.c b/dviware/mdvi/lib/common.c
new file mode 100644
index 0000000000..24b30da537
--- /dev/null
+++ b/dviware/mdvi/lib/common.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+
+long fsgetn(FILE *p, size_t n)
+{
+ long v;
+
+ v = fgetbyte(p);
+ if(v & 0x80)
+ v -= 0x100;
+ while(--n > 0)
+ v = (v << 8) | fgetbyte(p);
+ return v;
+}
+
+Ulong fugetn(FILE *p, size_t n)
+{
+ Ulong v;
+
+ v = fgetbyte(p);
+ while(--n > 0)
+ v = (v << 8) | fgetbyte(p);
+ return v;
+}
+
+long msgetn(const Uchar *p, size_t n)
+{
+ long v = (long)*p++;
+
+ if(v & 0x80)
+ v -= 0x100;
+ while(--n > 0)
+ v = (v << 8) | *p++;
+ return v;
+}
+
+Ulong mugetn(const Uchar *p, size_t n)
+{
+ Ulong v = (Ulong)*p++;
+
+ while(--n > 0)
+ v = (v << 8) | *p++;
+ return v;
+}
+
+char *read_string(FILE *in, int s, char *buffer, size_t len)
+{
+ int n;
+ char *str;
+
+ n = fugetn(in, s ? s : 1);
+ if((str = buffer) == NULL || n + 1 > len)
+ str = xmalloc(n + 1);
+ if(fread(str, 1, n, in) != n) {
+ if(str != buffer) xfree(str);
+ return NULL;
+ }
+ str[n] = 0;
+ return str;
+}
+
+size_t read_bcpl(FILE *in, char *buffer, size_t maxlen, size_t wanted)
+{
+ size_t i;
+
+ i = (int)fuget1(in);
+ if(maxlen && i > maxlen)
+ i = maxlen;
+ if(fread(buffer, i, 1, in) != 1)
+ return -1;
+ buffer[i] = '\0';
+ while(wanted-- > i)
+ (void)fgetc(in);
+ return i;
+}
+
+char *read_alloc_bcpl(FILE *in, size_t maxlen, size_t *size)
+{
+ size_t i;
+ char *buffer;
+
+ i = (size_t)fuget1(in);
+ if(maxlen && i > maxlen)
+ i = maxlen;
+ buffer = (char *)malloc(i + 1);
+ if(buffer == NULL)
+ return NULL;
+ if(fread(buffer, i, 1, in) != 1) {
+ free(buffer);
+ return NULL;
+ }
+ buffer[i] = '\0';
+ if(size) *size = i;
+ return buffer;
+}
+
+/* stolen from dvips */
+Int32 scaled_width(Int32 fix, int scale)
+{
+ Int32 al, bl;
+
+ if(fix < 0)
+ return -scaled_width(-fix, scale);
+ if(scale < 0)
+ return -scaled_width(fix, -scale);
+ al = fix & 32767;
+ bl = scale & 32767;
+ al >>= 15;
+ bl >>= 15;
+
+ return (((al*bl / 32768) + fix*bl + al*scale) / 32 +
+ fix * scale / 1024);
+}
+
+/* buffers */
+
+void buff_free(Buffer *buf)
+{
+ if(buf->data)
+ xfree(buf->data);
+ buff_init(buf);
+}
+
+void buff_init(Buffer *buf)
+{
+ buf->data = NULL;
+ buf->size = 0;
+ buf->length = 0;
+}
+
+size_t buff_add(Buffer *buf, const char *data, size_t len)
+{
+ if(!len && data)
+ len = strlen(data);
+ if(buf->length + len + 1 > buf->size) {
+ buf->size = buf->length + len + 256;
+ buf->data = xrealloc(buf->data, buf->size);
+ }
+ memcpy(buf->data + buf->length, data, len);
+ buf->length += len;
+ return buf->length;
+}
+
+char *buff_gets(Buffer *buf, size_t *length)
+{
+ char *ptr;
+ char *ret;
+ size_t len;
+
+ ptr = strchr(buf->data, '\n');
+ if(ptr == NULL)
+ return NULL;
+ ptr++; /* include newline */
+ len = ptr - buf->data;
+ ret = xmalloc(len + 1);
+ if(len > 0) {
+ memcpy(ret, buf->data, len);
+ memmove(buf->data, buf->data + len, buf->length - len);
+ buf->length -= len;
+ }
+ ret[len] = 0;
+ if(length) *length = len;
+ return ret;
+}
+
diff --git a/dviware/mdvi/lib/dvimisc.c b/dviware/mdvi/lib/dvimisc.c
new file mode 100644
index 0000000000..5dbacfbf01
--- /dev/null
+++ b/dviware/mdvi/lib/dvimisc.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "mdvi.h"
+
+void mdvi_set_color(DviContext *dvi, Ulong fg, Ulong bg)
+{
+ if(dvi->curr_fg != fg || dvi->curr_bg != bg) {
+ DEBUG((DBG_DEVICE, "setting color to (%lu,%lu)\n", fg, bg));
+ if(dvi->device.set_color)
+ dvi->device.set_color(dvi->device.device_data, fg, bg);
+ dvi->curr_fg = fg;
+ dvi->curr_bg = bg;
+ }
+}
+
+void mdvi_push_color(DviContext *dvi, Ulong fg, Ulong bg)
+{
+ if(dvi->color_top == dvi->color_size) {
+ dvi->color_size += 32;
+ dvi->color_stack = xrealloc(dvi->color_stack,
+ dvi->color_size * sizeof(DviColorPair));
+ }
+ dvi->color_stack[dvi->color_top].fg = dvi->curr_fg;
+ dvi->color_stack[dvi->color_top].bg = dvi->curr_bg;
+ dvi->color_top++;
+ mdvi_set_color(dvi, fg, bg);
+}
+
+void mdvi_pop_color(DviContext *dvi)
+{
+ Ulong fg, bg;
+
+ if(dvi->color_top == 0)
+ return;
+ dvi->color_top--;
+ fg = dvi->color_stack[dvi->color_top].fg;
+ bg = dvi->color_stack[dvi->color_top].bg;
+ mdvi_set_color(dvi, fg, bg);
+}
+
+void mdvi_reset_color(DviContext *dvi)
+{
+ dvi->color_top = 0;
+ mdvi_set_color(dvi, dvi->params.fg, dvi->params.bg);
+}
+
diff --git a/dviware/mdvi/lib/dviread.c b/dviware/mdvi/lib/dviread.c
new file mode 100644
index 0000000000..1b8db1369f
--- /dev/null
+++ b/dviware/mdvi/lib/dviread.c
@@ -0,0 +1,1548 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+typedef int (*DviCommand) __PROTO((DviContext *, int));
+
+#define DVICMDDEF(x) static int x __PROTO((DviContext *, int))
+
+DVICMDDEF(set_char);
+DVICMDDEF(set_rule);
+DVICMDDEF(no_op);
+DVICMDDEF(push);
+DVICMDDEF(pop);
+DVICMDDEF(move_right);
+DVICMDDEF(move_down);
+DVICMDDEF(move_w);
+DVICMDDEF(move_x);
+DVICMDDEF(move_y);
+DVICMDDEF(move_z);
+DVICMDDEF(sel_font);
+DVICMDDEF(sel_fontn);
+DVICMDDEF(special);
+DVICMDDEF(def_font);
+DVICMDDEF(undefined);
+DVICMDDEF(unexpected);
+
+static const DviCommand dvi_commands[] = {
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char,
+ set_char, set_char, set_char, set_char, /* 0 - 127 */
+ set_char, set_char, set_char, set_char, /* 128 - 131 */
+ set_rule, /* 132 */
+ set_char, set_char, set_char, set_char, /* 133 - 136 */
+ set_rule, /* 137 */
+ no_op, /* 138 */
+ unexpected, /* 139 (BOP) */
+ unexpected, /* 140 (EOP) */
+ push, /* 141 */
+ pop, /* 142 */
+ move_right, move_right, move_right, move_right, /* 143 - 146 */
+ move_w, move_w, move_w, move_w, move_w, /* 147 - 151 */
+ move_x, move_x, move_x, move_x, move_x, /* 152 - 156 */
+ move_down, move_down, move_down, move_down, /* 157 - 160 */
+ move_y, move_y, move_y, move_y, move_y, /* 161 - 165 */
+ move_z, move_z, move_z, move_z, move_z, /* 166 - 170 */
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font,
+ sel_font, sel_font, sel_font, sel_font, /* 171 - 234 */
+ sel_fontn, sel_fontn, sel_fontn, sel_fontn, /* 235 - 238 */
+ special, special, special, special, /* 239 - 242 */
+ def_font, def_font, def_font, def_font, /* 243 - 246 */
+ unexpected, /* 247 (PRE) */
+ unexpected, /* 248 (POST) */
+ unexpected, /* 249 (POST_POST) */
+ undefined, undefined, undefined,
+ undefined, undefined, undefined /* 250 - 255 */
+};
+
+#define DVI_BUFLEN 4096
+
+static void dummy_draw_glyph(DviContext *dvi, DviFontChar *ch, int x, int y)
+{
+}
+
+static void dummy_draw_rule(DviContext *dvi, int x, int y, Uint w, Uint h, int f)
+{
+}
+
+static int dummy_alloc_colors(void *a, Ulong *b, int c, Ulong d, Ulong e, double f, int g)
+{
+ return -1;
+}
+
+static void *dummy_create_image(void *a, Uint b, Uint c, Uint d)
+{
+ return NULL;
+}
+
+static void dummy_free_image(void *a)
+{
+}
+
+static void dummy_dev_destroy(void *a)
+{
+}
+
+static void dummy_dev_putpixel(void *a, int x, int y, Ulong c)
+{
+}
+
+static void dummy_dev_refresh(DviContext *a, void *b)
+{
+}
+
+static void dummy_dev_set_color(void *a, Ulong b, Ulong c)
+{
+}
+
+/* functions to report errors */
+static void dvierr(DviContext *dvi, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ fprintf(stderr, "%s[%d]: Error: ",
+ dvi->filename, dvi->currpage);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+static void dviwarn(DviContext *dvi, const char *format, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s[%d]: Warning: ",
+ dvi->filename, dvi->currpage);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+#define NEEDBYTES(d,n) \
+ ((d)->buffer.pos + (n) > (d)->buffer.length)
+
+static int get_bytes(DviContext *dvi, size_t n)
+{
+ /*
+ * caller wants to read `n' bytes from dvi->buffer + dvi->pos.
+ * Make sure there is enough data to satisfy the request
+ */
+ if(NEEDBYTES(dvi, n)) {
+ size_t required;
+ int newlen;
+
+ if(dvi->buffer.frozen || dvi->in == NULL || feof(dvi->in)) {
+ /* this is EOF */
+ dviwarn(dvi, _("unexpected EOF\n"));
+ return -1;
+ }
+ /* get more data */
+ if(dvi->buffer.data == NULL) {
+ /* first allocation */
+ dvi->buffer.size = Max(DVI_BUFLEN, n);
+ dvi->buffer.data = (Uchar *)xmalloc(dvi->buffer.size);
+ dvi->buffer.length = 0;
+ dvi->buffer.frozen = 0;
+ } else if(dvi->buffer.pos < dvi->buffer.length) {
+ /* move whatever we want to keep */
+ dvi->buffer.length -= dvi->buffer.pos;
+ memmove(dvi->buffer.data,
+ dvi->buffer.data + dvi->buffer.pos,
+ dvi->buffer.length);
+ } else {
+ /* we can discard all the data in this buffer */
+ dvi->buffer.length = 0;
+ }
+
+ required = n - dvi->buffer.length;
+ if(required > dvi->buffer.size - dvi->buffer.length) {
+ /* need to allocate more memory */
+ dvi->buffer.size = dvi->buffer.length + required + 128;
+ dvi->buffer.data = (Uchar *)xresize(dvi->buffer.data,
+ char, dvi->buffer.size);
+ }
+ /* now read into the buffer */
+ newlen = fread(dvi->buffer.data + dvi->buffer.length,
+ 1, dvi->buffer.size - dvi->buffer.length, dvi->in);
+ if(newlen == -1) {
+ error("%s: %s\n", dvi->filename, strerror(errno));
+ return -1;
+ }
+ dvi->buffer.length += newlen;
+ dvi->buffer.pos = 0;
+ }
+ return 0;
+}
+
+/* only relative forward seeks are supported by this function */
+static int dskip(DviContext *dvi, long offset)
+{
+ ASSERT(offset > 0);
+
+ if(NEEDBYTES(dvi, offset) && get_bytes(dvi, offset) == -1)
+ return -1;
+ dvi->buffer.pos += offset;
+ return 0;
+}
+
+/* DVI I/O functions (note: here `n' must be <= 4) */
+static long dsgetn(DviContext *dvi, size_t n)
+{
+ long val;
+
+ if(NEEDBYTES(dvi, n) && get_bytes(dvi, n) == -1)
+ return -1;
+ val = msgetn(dvi->buffer.data + dvi->buffer.pos, n);
+ dvi->buffer.pos += n;
+ return val;
+}
+
+static int dread(DviContext *dvi, char *buffer, size_t len)
+{
+ if(NEEDBYTES(dvi, len) && get_bytes(dvi, len) == -1)
+ return -1;
+ memcpy(buffer, dvi->buffer.data + dvi->buffer.pos, len);
+ dvi->buffer.pos += len;
+ return 0;
+}
+
+static long dugetn(DviContext *dvi, size_t n)
+{
+ long val;
+
+ if(NEEDBYTES(dvi, n) && get_bytes(dvi, n) == -1)
+ return -1;
+ val = mugetn(dvi->buffer.data + dvi->buffer.pos, n);
+ dvi->buffer.pos += n;
+ return val;
+}
+
+static long dtell(DviContext *dvi)
+{
+ return dvi->depth ?
+ dvi->buffer.pos :
+ ftell(dvi->in) - dvi->buffer.length + dvi->buffer.pos;
+}
+
+static void dreset(DviContext *dvi)
+{
+ if(!dvi->buffer.frozen && dvi->buffer.data)
+ xfree(dvi->buffer.data);
+ dvi->buffer.data = NULL;
+ dvi->buffer.size = 0;
+ dvi->buffer.length = 0;
+ dvi->buffer.pos = 0;
+}
+
+#define dsget1(d) dsgetn((d), 1)
+#define dsget2(d) dsgetn((d), 2)
+#define dsget3(d) dsgetn((d), 3)
+#define dsget4(d) dsgetn((d), 4)
+#define duget1(d) dugetn((d), 1)
+#define duget2(d) dugetn((d), 2)
+#define duget3(d) dugetn((d), 3)
+#define duget4(d) dugetn((d), 4)
+
+#ifndef NODEBUG
+static void dviprint(DviContext *dvi, const char *command, int sub, const char *fmt, ...)
+{
+ int i;
+ va_list ap;
+
+ printf("%s: ", dvi->filename);
+ for(i = 0; i < dvi->depth; i++)
+ printf(" ");
+ printf("%4lu: %s", dtell(dvi), command);
+ if(sub >= 0) printf("%d", sub);
+ if(*fmt) printf(": ");
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+#define SHOWCMD(x) \
+ if(_mdvi_debug_mask & DBG_OPCODE) do { dviprint x; } while(0)
+#else
+#define SHOWCMD(x) do { } while(0)
+#endif
+
+int mdvi_find_tex_page(DviContext *dvi, int tex_page)
+{
+ int i;
+
+ for(i = 0; i < dvi->npages; i++)
+ if(dvi->pagemap[i][1] == tex_page)
+ return i;
+ return -1;
+}
+
+/* page sorting functions */
+static int sort_up(const void *p1, const void *p2)
+{
+ return ((long *)p1)[1] - ((long *)p2)[1];
+}
+static int sort_down(const void *p1, const void *p2)
+{
+ return ((long *)p2)[1] - ((long *)p1)[1];
+}
+static int sort_random(const void *p1, const void *p2)
+{
+ return (random() % 1) ? -1 : 1;
+}
+static int sort_dvi_up(const void *p1, const void *p2)
+{
+ return ((long *)p1)[0] - ((long *)p2)[0];
+}
+static int sort_dvi_down(const void *p1, const void *p2)
+{
+ return ((long *)p1)[0] - ((long *)p2)[0];
+}
+
+void mdvi_sort_pages(DviContext *dvi, DviPageSort type)
+{
+ int (*sortfunc) __PROTO((const void *, const void *));
+
+ switch(type) {
+ case MDVI_PAGE_SORT_UP:
+ sortfunc = sort_up;
+ break;
+ case MDVI_PAGE_SORT_DOWN:
+ sortfunc = sort_down;
+ break;
+ case MDVI_PAGE_SORT_RANDOM:
+ sortfunc = sort_random;
+ break;
+ case MDVI_PAGE_SORT_DVI_UP:
+ sortfunc = sort_dvi_up;
+ break;
+ case MDVI_PAGE_SORT_DVI_DOWN:
+ sortfunc = sort_dvi_down;
+ break;
+ case MDVI_PAGE_SORT_NONE:
+ default:
+ sortfunc = NULL;
+ break;
+ }
+
+ if(sortfunc)
+ qsort(dvi->pagemap, dvi->npages, sizeof(PageNum), sortfunc);
+}
+
+static DviFontRef *define_font(DviContext *dvi, int op)
+{
+ Int32 arg;
+ Int32 scale;
+ Int32 dsize;
+ Int32 checksum;
+ int hdpi;
+ int vdpi;
+ int n;
+ char *name;
+ DviFontRef *ref;
+
+ arg = dugetn(dvi, op - DVI_FNT_DEF1 + 1);
+ checksum = duget4(dvi);
+ scale = duget4(dvi);
+ dsize = duget4(dvi);
+ hdpi = FROUND(dvi->params.mag * dvi->params.dpi * scale / dsize);
+ vdpi = FROUND(dvi->params.mag * dvi->params.vdpi * scale / dsize);
+ n = duget1(dvi) + duget1(dvi);
+ name = xmalloc(n + 1);
+ dread(dvi, name, n);
+ name[n] = 0;
+ DEBUG((DBG_FONTS, "requesting font %d = `%s' at %.1fpt (%dx%d dpi)\n",
+ arg, name, (double)scale / (dvi->params.tfm_conv * 0x100000),
+ hdpi, vdpi));
+ ref = font_reference(&dvi->params, arg, name, checksum, hdpi, vdpi, scale);
+ if(ref == NULL) {
+ error(_("could not load font `%s'\n"), name);
+ xfree(name);
+ return NULL;
+ }
+ xfree(name);
+ return ref;
+}
+
+static char *opendvi(const char *name)
+{
+ int len;
+ char *file;
+
+ len = strlen(name);
+ /* if file ends with .dvi and it exists, that's it */
+ if(len >= 4 && STREQ(name+len-4, ".dvi")) {
+ DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", name));
+ if(access(name, R_OK) == 0)
+ return xstrdup(name);
+ }
+
+ /* try appending .dvi */
+ file = xmalloc(len + 5);
+ strcpy(file, name);
+ strcpy(file+len, ".dvi");
+ DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", file));
+ if(access(file, R_OK) == 0)
+ return file;
+ /* try the given name */
+ file[len] = 0;
+ DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", file));
+ if(access(file, R_OK) == 0)
+ return file;
+ xfree(file);
+ return NULL;
+}
+
+int mdvi_reload(DviContext *dvi, DviParams *np)
+{
+ DviContext *newdvi;
+ DviParams *pars;
+
+ /* close our file */
+ if(dvi->in) {
+ fclose(dvi->in);
+ dvi->in = NULL;
+ }
+
+ pars = np ? np : &dvi->params;
+ DEBUG((DBG_DVI, "%s: reloading\n", dvi->filename));
+
+ /* load it again */
+ newdvi = mdvi_init_context(pars, dvi->pagesel, dvi->filename);
+ if(newdvi == NULL) {
+ warning(_("could not reload `%s'\n"), dvi->filename);
+ return -1;
+ }
+
+ /* drop all our font references */
+ font_drop_chain(dvi->fonts);
+ /* destroy our font map */
+ if(dvi->fontmap)
+ xfree(dvi->fontmap);
+ dvi->currfont = NULL;
+
+ /* and use the ones we just loaded */
+ dvi->fonts = newdvi->fonts;
+ dvi->fontmap = newdvi->fontmap;
+ dvi->nfonts = newdvi->nfonts;
+
+ /* copy the new information */
+ dvi->params = newdvi->params;
+ dvi->num = newdvi->num;
+ dvi->den = newdvi->den;
+ dvi->dvimag = newdvi->dvimag;
+ dvi->dviconv = newdvi->dviconv;
+ dvi->dvivconv = newdvi->dvivconv;
+ dvi->modtime = newdvi->modtime;
+
+ if(dvi->fileid) xfree(dvi->fileid);
+ dvi->fileid = newdvi->fileid;
+
+ dvi->dvi_page_w = newdvi->dvi_page_w;
+ dvi->dvi_page_h = newdvi->dvi_page_h;
+
+ xfree(dvi->pagemap);
+ dvi->pagemap = newdvi->pagemap;
+ dvi->npages = newdvi->npages;
+ if(dvi->currpage > dvi->npages-1)
+ dvi->currpage = 0;
+
+ xfree(dvi->stack);
+ dvi->stack = newdvi->stack;
+ dvi->stacksize = newdvi->stacksize;
+
+ /* remove fonts that are not being used anymore */
+ font_free_unused(&dvi->device);
+
+ xfree(newdvi->filename);
+ xfree(newdvi);
+
+ DEBUG((DBG_DVI, "%s: reload successful\n", dvi->filename));
+ if(dvi->device.refresh)
+ dvi->device.refresh(dvi, dvi->device.device_data);
+
+ return 0;
+}
+
+/* function to change parameters ia DVI context
+ * The DVI context is modified ONLY if this function is successful */
+int mdvi_configure(DviContext *dvi, DviParamCode option, ...)
+{
+ va_list ap;
+ int reset_all;
+ int reset_font;
+ DviParams np;
+
+ va_start(ap, option);
+
+ reset_font = 0;
+ reset_all = 0;
+ np = dvi->params; /* structure copy */
+ while(option != MDVI_PARAM_LAST) {
+ switch(option) {
+ case MDVI_SET_DPI:
+ np.dpi = np.vdpi = va_arg(ap, Uint);
+ reset_all = 1;
+ break;
+ case MDVI_SET_XDPI:
+ np.dpi = va_arg(ap, Uint);
+ reset_all = 1;
+ break;
+ case MDVI_SET_YDPI:
+ np.vdpi = va_arg(ap, Uint);
+ break;
+ case MDVI_SET_SHRINK:
+ np.hshrink = np.vshrink = va_arg(ap, Uint);
+ reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
+ break;
+ case MDVI_SET_XSHRINK:
+ np.hshrink = va_arg(ap, Uint);
+ reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
+ break;
+ case MDVI_SET_YSHRINK:
+ np.vshrink = va_arg(ap, Uint);
+ reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
+ break;
+ case MDVI_SET_ORIENTATION:
+ np.orientation = va_arg(ap, DviOrientation);
+ reset_font = MDVI_FONTSEL_GLYPH;
+ break;
+ case MDVI_SET_GAMMA:
+ np.gamma = va_arg(ap, double);
+ if(np.pixels) {
+ xfree(np.pixels);
+ np.pixels = 0;
+ np.npixels = 0;
+ }
+ reset_font = MDVI_FONTSEL_GREY;
+ break;
+ case MDVI_SET_DENSITY:
+ np.density = va_arg(ap, Uint);
+ reset_font = MDVI_FONTSEL_BITMAP;
+ break;
+ case MDVI_SET_MAGNIFICATION:
+ np.mag = va_arg(ap, double);
+ reset_all = 1;
+ break;
+ case MDVI_SET_DRIFT:
+ np.hdrift = np.vdrift = va_arg(ap, int);
+ break;
+ case MDVI_SET_HDRIFT:
+ np.hdrift = va_arg(ap, int);
+ break;
+ case MDVI_SET_VDRIFT:
+ np.vdrift = va_arg(ap, int);
+ break;
+ case MDVI_SET_FOREGROUND:
+ np.fg = va_arg(ap, Ulong);
+ reset_font = MDVI_FONTSEL_GREY;
+ break;
+ case MDVI_SET_BACKGROUND:
+ np.bg = va_arg(ap, Ulong);
+ reset_font = MDVI_FONTSEL_GREY;
+ break;
+ default:
+ break;
+ }
+ option = va_arg(ap, DviParamCode);
+ }
+ va_end(ap);
+
+ /* check that all values make sense */
+ if(np.dpi <= 0 || np.vdpi <= 0)
+ return -1;
+ if(np.mag <= 0.0)
+ return -1;
+ if(np.density < 0)
+ return -1;
+ if(np.hshrink < 1 || np.vshrink < 1)
+ return -1;
+ if(np.hdrift < 0 || np.vdrift < 0)
+ return -1;
+ if(np.fg == np.bg)
+ return -1;
+
+ /*
+ * If the dpi or the magnification change, we basically have to reload
+ * the DVI file again from scratch.
+ */
+
+ if(reset_all)
+ return (mdvi_reload(dvi, &np) == 0);
+
+ if(np.hshrink != dvi->params.hshrink) {
+ np.conv = dvi->dviconv;
+ if(np.hshrink)
+ np.conv /= np.hshrink;
+ }
+ if(np.vshrink != dvi->params.vshrink) {
+ np.vconv = dvi->dvivconv;
+ if(np.vshrink)
+ np.vconv /= np.vshrink;
+ }
+
+ if(reset_font) {
+ font_reset_chain_glyphs(&dvi->device, dvi->fonts, reset_font);
+ }
+ dvi->params = np;
+ if((reset_font & MDVI_FONTSEL_GLYPH) && dvi->device.refresh) {
+ dvi->device.refresh(dvi, dvi->device.device_data);
+ return 0;
+ }
+
+ return 1;
+}
+/*
+ * Read the initial data from the DVI file. If something is wrong with the
+ * file, we just spit out an error message and refuse to load the file,
+ * without giving any details. This makes sense because DVI files are ok
+ * 99.99% of the time, and dvitype(1) can be used to check the other 0.01%.
+ */
+DviContext *mdvi_init_context(DviParams *par, DviPageSpec *spec, const char *file)
+{
+ FILE *p;
+ Int32 arg;
+ int op;
+ long offset;
+ int n;
+ DviContext *dvi;
+ char *filename;
+ int pagecount;
+
+ /*
+ * 1. Open the file and initialize the DVI context
+ */
+
+ filename = opendvi(file);
+ if(filename == NULL) {
+ perror(file);
+ return NULL;
+ }
+ p = fopen(filename, "r");
+ if(p == NULL) {
+ perror(file);
+ xfree(filename);
+ return NULL;
+ }
+ dvi = xalloc(DviContext);
+ memzero(dvi, sizeof(DviContext));
+ dvi->pagemap = NULL;
+ dvi->filename = filename;
+ dvi->stack = NULL;
+ dvi->modtime = get_mtime(fileno(p));
+ dvi->buffer.data = NULL;
+ dvi->pagesel = spec;
+ dvi->in = p; /* now we can use the dget*() functions */
+
+ /*
+ * 2. Read the preamble, extract scaling information, and
+ * setup the DVI parameters.
+ */
+
+ if(fuget1(p) != DVI_PRE)
+ goto bad_dvi;
+ if((arg = fuget1(p)) != DVI_ID) {
+ error(_("%s: unsupported DVI format (version %u)\n"),
+ file, arg);
+ goto error; /* jump to the end of this routine,
+ * where we handle errors */
+ }
+ /* get dimensions */
+ dvi->num = fuget4(p);
+ dvi->den = fuget4(p);
+ dvi->dvimag = fuget4(p);
+
+ /* check that these numbers make sense */
+ if(!dvi->num || !dvi->den || !dvi->dvimag)
+ goto bad_dvi;
+
+ dvi->params.mag =
+ (par->mag > 0 ? par->mag : (double)dvi->dvimag / 1000.0);
+ dvi->params.hdrift = par->hdrift;
+ dvi->params.vdrift = par->vdrift;
+ dvi->params.dpi = par->dpi ? par->dpi : MDVI_DPI;
+ dvi->params.vdpi = par->vdpi ? par->vdpi : par->dpi;
+ dvi->params.hshrink = par->hshrink;
+ dvi->params.vshrink = par->vshrink;
+ dvi->params.density = par->density;
+ dvi->params.gamma = par->gamma;
+ dvi->params.conv = (double)dvi->num / dvi->den;
+ dvi->params.conv *= (dvi->params.dpi / 254000.0) * dvi->params.mag;
+ dvi->params.vconv = (double)dvi->num / dvi->den;
+ dvi->params.vconv *= (dvi->params.vdpi / 254000.0) * dvi->params.mag;
+ dvi->params.tfm_conv = (25400000.0 / dvi->num) *
+ ((double)dvi->den / 473628672) / 16.0;
+ dvi->params.flags = par->flags;
+ dvi->params.orientation = par->orientation;
+ dvi->params.fg = par->fg;
+ dvi->params.bg = par->bg;
+ dvi->params.pixels = NULL;
+ dvi->params.npixels = 0;
+
+ /* initialize colors */
+ dvi->curr_fg = par->fg;
+ dvi->curr_bg = par->bg;
+ dvi->color_stack = NULL;
+ dvi->color_top = 0;
+ dvi->color_size = 0;
+
+ /* pixel conversion factors */
+ dvi->dviconv = dvi->params.conv;
+ dvi->dvivconv = dvi->params.vconv;
+ if(dvi->params.hshrink)
+ dvi->params.conv /= dvi->params.hshrink;
+ if(dvi->params.vshrink)
+ dvi->params.vconv /= dvi->params.vshrink;
+
+ /* get the comment from the preamble */
+ n = fuget1(p);
+ dvi->fileid = xmalloc(n + 1);
+ fread(dvi->fileid, 1, n, p);
+ dvi->fileid[n] = 0;
+ DEBUG((DBG_DVI, "%s: %s\n", filename, dvi->fileid));
+
+ /*
+ * 3. Read postamble, extract page information (number of
+ * pages, dimensions) and stack depth.
+ */
+
+ /* jump to the end of the file */
+ if(fseek(p, (long)-1, SEEK_END) == -1)
+ goto error;
+ for(n = 0; (op = fuget1(p)) == DVI_TRAILER; n++)
+ if(fseek(p, (long)-2, SEEK_CUR) < 0)
+ break;
+ if(op != arg || n < 4)
+ goto bad_dvi;
+ /* get the pointer to postamble */
+ fseek(p, (long)-5, SEEK_CUR);
+ arg = fuget4(p);
+ /* jump to it */
+ fseek(p, (long)arg, SEEK_SET);
+ if(fuget1(p) != DVI_POST)
+ goto bad_dvi;
+ offset = fuget4(p);
+ if(dvi->num != fuget4(p) || dvi->den != fuget4(p) ||
+ dvi->dvimag != fuget4(p))
+ goto bad_dvi;
+ dvi->dvi_page_h = fuget4(p);
+ dvi->dvi_page_w = fuget4(p);
+ dvi->stacksize = fuget2(p);
+ dvi->npages = fuget2(p);
+ DEBUG((DBG_DVI, "%s: from postamble: stack depth %d, %d page%s\n",
+ filename, dvi->stacksize, dvi->npages, dvi->npages > 1 ? "s" : ""));
+
+ /*
+ * 4. Process font definitions.
+ */
+
+ /* process font definitions */
+ dvi->nfonts = 0;
+ dvi->fontmap = NULL;
+ /*
+ * CAREFUL: here we need to use the dvi->buffer, but it might leave the
+ * the file cursor in the wrong position after reading fonts (because of
+ * buffering). It's ok, though, because after the font definitions we read
+ * the page offsets, and we fseek() to the relevant part of the file with
+ * SEEK_SET. Nothing is read after the page offsets.
+ */
+ while((op = duget1(dvi)) != DVI_POST_POST) {
+ DviFontRef *ref;
+
+ if(op == DVI_NOOP)
+ continue;
+ else if(op < DVI_FNT_DEF1 || op > DVI_FNT_DEF4)
+ goto error;
+ ref = define_font(dvi, op);
+ if(ref == NULL)
+ goto error;
+ ref->next = dvi->fonts;
+ dvi->fonts = ref;
+ dvi->nfonts++;
+ }
+ /* we don't need the buffer anymore */
+ dreset(dvi);
+
+ if(op != DVI_POST_POST)
+ goto bad_dvi;
+ font_finish_definitions(dvi);
+ DEBUG((DBG_DVI, "%s: %d font%s required by this job\n",
+ filename, dvi->nfonts, dvi->nfonts > 1 ? "s" : ""));
+ dvi->findref = font_find_mapped;
+
+ /*
+ * 5. Build the page map.
+ */
+
+ dvi->pagemap = xnalloc(PageNum, dvi->npages);
+ memzero(dvi->pagemap, sizeof(PageNum) * dvi->npages);
+
+ n = dvi->npages - 1;
+ pagecount = n;
+ while(offset != -1) {
+ int i;
+ PageNum page;
+
+ fseek(p, offset, SEEK_SET);
+ op = fuget1(p);
+ if(op != DVI_BOP || n < 0)
+ goto bad_dvi;
+ for(i = 1; i <= 10; i++)
+ page[i] = fsget4(p);
+ page[0] = offset;
+ offset = (long)fuget4(p);
+ /* check if the page is selected */
+ if(spec && mdvi_page_selected(spec, page, n) == 0) {
+ DEBUG((DBG_DVI, "Page %d (%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld) ignored by request\n",
+ n, page[1], page[2], page[3], page[4], page[5],
+ page[6], page[7], page[8], page[9], page[10]));
+ } else {
+ memcpy(&dvi->pagemap[pagecount], page, sizeof(PageNum));
+ pagecount--;
+ }
+ n--;
+ }
+ pagecount++;
+ if(pagecount >= dvi->npages) {
+ error(_("no pages selected\n"));
+ goto error;
+ }
+ if(pagecount) {
+ DEBUG((DBG_DVI, "%d of %d pages selected\n",
+ dvi->npages - pagecount, dvi->npages));
+ dvi->npages -= pagecount;
+ memmove(dvi->pagemap, &dvi->pagemap[pagecount],
+ dvi->npages * sizeof(PageNum));
+ }
+
+ /*
+ * 6. Setup stack, initialize device functions
+ */
+
+ dvi->curr_layer = 0;
+ dvi->stack = xnalloc(DviState, dvi->stacksize + 8);
+
+ dvi->device.draw_glyph = dummy_draw_glyph;
+ dvi->device.draw_rule = dummy_draw_rule;
+ dvi->device.alloc_colors = dummy_alloc_colors;
+ dvi->device.create_image = dummy_create_image;
+ dvi->device.free_image = dummy_free_image;
+ dvi->device.dev_destroy = dummy_dev_destroy;
+ dvi->device.put_pixel = dummy_dev_putpixel;
+ dvi->device.refresh = dummy_dev_refresh;
+ dvi->device.set_color = dummy_dev_set_color;
+ dvi->device.device_data = NULL;
+
+ /* initialize associations */
+ mdvi_hash_init(&dvi->assoc);
+
+ DEBUG((DBG_DVI, "%s read successfully\n", filename));
+ return dvi;
+
+bad_dvi:
+ error(_("%s: File corrupted, or not a DVI file\n"), file);
+error:
+ /* if we came from the font definitions, this will be non-trivial */
+ dreset(dvi);
+ mdvi_destroy_context(dvi);
+ return NULL;
+}
+
+void mdvi_destroy_context(DviContext *dvi)
+{
+ if(dvi->device.dev_destroy)
+ dvi->device.dev_destroy(dvi->device.device_data);
+ /* release all fonts */
+ if(dvi->fonts) {
+ font_drop_chain(dvi->fonts);
+ font_free_unused(&dvi->device);
+ }
+ if(dvi->fontmap)
+ xfree(dvi->fontmap);
+ if(dvi->filename)
+ xfree(dvi->filename);
+ if(dvi->stack)
+ xfree(dvi->stack);
+ if(dvi->pagemap)
+ xfree(dvi->pagemap);
+ if(dvi->fileid)
+ xfree(dvi->fileid);
+ if(dvi->in)
+ fclose(dvi->in);
+ if(dvi->buffer.data && !dvi->buffer.frozen)
+ xfree(dvi->buffer.data);
+ if(dvi->color_stack)
+ xfree(dvi->color_stack);
+ mdvi_assoc_flush(dvi);
+
+ xfree(dvi);
+}
+
+void mdvi_setpage(DviContext *dvi, int pageno)
+{
+ if(pageno < 0)
+ pageno = 0;
+ if(pageno > dvi->npages-1)
+ pageno = dvi->npages - 1;
+ dvi->currpage = pageno;
+}
+
+int mdvi_run_macro(DviContext *dvi, Uchar *macro, size_t len)
+{
+ DviFontRef *curr, *fonts;
+ DviBuffer saved_buffer;
+ FILE *saved_file;
+ int opcode;
+ int oldtop;
+
+ dvi->depth++;
+ push(dvi, DVI_PUSH);
+ dvi->pos.w = 0;
+ dvi->pos.x = 0;
+ dvi->pos.y = 0;
+ dvi->pos.z = 0;
+
+ /* save our state */
+ curr = dvi->currfont;
+ fonts = dvi->fonts;
+ saved_buffer = dvi->buffer;
+ saved_file = dvi->in;
+ dvi->currfont = curr->ref->subfonts;
+ dvi->fonts = curr->ref->subfonts;
+ dvi->buffer.data = macro;
+ dvi->buffer.pos = 0;
+ dvi->buffer.length = len;
+ dvi->buffer.frozen = 1;
+ dvi->in = NULL;
+ oldtop = dvi->stacktop;
+
+ /* execute commands */
+ while((opcode = duget1(dvi)) != DVI_EOP) {
+ if(dvi_commands[opcode](dvi, opcode) < 0)
+ break;
+ }
+ if(opcode != DVI_EOP)
+ dviwarn(dvi, _("%s: vf macro had errors\n"),
+ curr->ref->fontname);
+ if(dvi->stacktop != oldtop)
+ dviwarn(dvi, _("%s: stack not empty after vf macro\n"),
+ curr->ref->fontname);
+
+ /* restore things */
+ pop(dvi, DVI_POP);
+ dvi->currfont = curr;
+ dvi->fonts = fonts;
+ dvi->buffer = saved_buffer;
+ dvi->in = saved_file;
+ dvi->depth--;
+
+ return (opcode != DVI_EOP ? -1 : 0);
+}
+
+int mdvi_dopage(DviContext *dvi, int pageno)
+{
+ int op;
+ int ppi;
+ int reloaded = 0;
+
+again:
+ if(dvi->in == NULL) {
+ /* try reopening the file */
+ dvi->in = fopen(dvi->filename, "r");
+ if(dvi->in == NULL) {
+ warning(_("%s: could not reopen file (%s)\n"),
+ dvi->filename,
+ strerror(errno));
+ return -1;
+ }
+ DEBUG((DBG_FILES, "reopen(%s) -> Ok\n", dvi->filename));
+ }
+
+ /* check if we need to reload the file */
+ if(!reloaded && get_mtime(fileno(dvi->in)) > dvi->modtime) {
+ mdvi_reload(dvi, &dvi->params);
+ /* we have to reopen the file, again */
+ reloaded = 1;
+ goto again;
+ }
+
+ if(pageno < 0 || pageno > dvi->npages-1) {
+ error(_("%s: page %d out of range\n"),
+ dvi->filename, pageno);
+ return -1;
+ }
+
+ fseek(dvi->in, (long)dvi->pagemap[pageno][0], SEEK_SET);
+ if((op = fuget1(dvi->in)) != DVI_BOP) {
+ error(_("%s: bad offset at page %d\n"),
+ dvi->filename, pageno+1);
+ return -1;
+ }
+
+ /* skip bop */
+ fseek(dvi->in, (long)44, SEEK_CUR);
+
+ /* reset state */
+ dvi->currfont = NULL;
+ memzero(&dvi->pos, sizeof(DviState));
+ dvi->stacktop = 0;
+ dvi->currpage = pageno;
+ dvi->curr_layer = 0;
+
+ if(dvi->buffer.data && !dvi->buffer.frozen)
+ xfree(dvi->buffer.data);
+
+ /* reset our buffer */
+ dvi->buffer.data = NULL;
+ dvi->buffer.length = 0;
+ dvi->buffer.pos = 0;
+ dvi->buffer.frozen = 0;
+
+#if 0 /* make colors survive page breaks */
+ /* reset color stack */
+ mdvi_reset_color(dvi);
+#endif
+
+ /* set max horizontal and vertical drift (from dvips) */
+ if(dvi->params.hdrift < 0) {
+ ppi = dvi->params.dpi / dvi->params.hshrink; /* shrunk pixels per inch */
+ if(ppi < 600)
+ dvi->params.hdrift = ppi / 100;
+ else if(ppi < 1200)
+ dvi->params.hdrift = ppi / 200;
+ else
+ dvi->params.hdrift = ppi / 400;
+ }
+ if(dvi->params.vdrift < 0) {
+ ppi = dvi->params.vdpi / dvi->params.vshrink; /* shrunk pixels per inch */
+ if(ppi < 600)
+ dvi->params.vdrift = ppi / 100;
+ else if(ppi < 1200)
+ dvi->params.vdrift = ppi / 200;
+ else
+ dvi->params.vdrift = ppi / 400;
+ }
+
+ dvi->params.thinsp = FROUND(0.025 * dvi->params.dpi / dvi->params.conv);
+ dvi->params.vsmallsp = FROUND(0.025 * dvi->params.vdpi / dvi->params.vconv);
+
+ /* execute all the commands in the page */
+ while((op = duget1(dvi)) != DVI_EOP) {
+ if(dvi_commands[op](dvi, op) < 0)
+ break;
+ }
+
+ fflush(stdout);
+ fflush(stderr);
+ if(op != DVI_EOP)
+ return -1;
+ if(dvi->stacktop)
+ dviwarn(dvi, _("stack not empty at end of page\n"));
+ return 0;
+}
+
+static int inline move_vertical(DviContext *dvi, int amount)
+{
+ int rvv;
+
+ dvi->pos.v += amount;
+ rvv = vpixel_round(dvi, dvi->pos.v);
+ if(!dvi->params.vdrift)
+ return rvv;
+ if(amount > dvi->params.vsmallsp || amount <= -dvi->params.vsmallsp)
+ return rvv;
+ else {
+ int newvv;
+
+ newvv = dvi->pos.vv + vpixel_round(dvi, amount);
+ if(rvv - newvv > dvi->params.vdrift)
+ return rvv - dvi->params.vdrift;
+ else if(newvv - rvv > dvi->params.vdrift)
+ return rvv + dvi->params.vdrift;
+ else
+ return newvv;
+ }
+}
+
+static int inline move_horizontal(DviContext *dvi, int amount)
+{
+ int rhh;
+
+ dvi->pos.h += amount;
+ rhh = pixel_round(dvi, dvi->pos.h);
+ if(!dvi->params.hdrift)
+ return rhh;
+ else if(amount > dvi->params.thinsp || amount <= -6 * dvi->params.thinsp)
+ return rhh;
+ else {
+ int newhh;
+
+ newhh = dvi->pos.hh + pixel_round(dvi, amount);
+ if(rhh - newhh > dvi->params.hdrift)
+ return rhh - dvi->params.hdrift;
+ else if(newhh - rhh > dvi->params.hdrift)
+ return rhh + dvi->params.hdrift;
+ else
+ return newhh;
+ }
+}
+
+static void inline fix_after_horizontal(DviContext *dvi)
+{
+ int rhh;
+
+ rhh = pixel_round(dvi, dvi->pos.h);
+ if(!dvi->params.hdrift)
+ dvi->pos.hh = rhh;
+ else if(rhh - dvi->pos.hh > dvi->params.hdrift)
+ dvi->pos.hh = rhh - dvi->params.hdrift;
+ else if(dvi->pos.hh - rhh > dvi->params.hdrift)
+ dvi->pos.hh = rhh + dvi->params.hdrift;
+}
+
+/* commands */
+
+#define DBGSUM(a,b,c) \
+ (a), (b) > 0 ? '+' : '-', \
+ (b) > 0 ? (b) : -(b), (c)
+
+/*
+ * The only commands that actually draw something are:
+ * set_char, set_rule
+ */
+
+static void draw_box(DviContext *dvi, DviFontChar *ch)
+{
+ DviGlyph *glyph = NULL;
+ int x, y, w, h;
+
+ if(!MDVI_GLYPH_UNSET(ch->shrunk.data))
+ glyph = &ch->shrunk;
+ else if(!MDVI_GLYPH_UNSET(ch->grey.data))
+ glyph = &ch->grey;
+ else if(!MDVI_GLYPH_UNSET(ch->glyph.data))
+ glyph = &ch->glyph;
+ if(glyph == NULL)
+ return;
+ x = glyph->x;
+ y = glyph->y;
+ w = glyph->w;
+ h = glyph->h;
+ /* this is bad -- we have to undo the orientation */
+ switch(dvi->params.orientation) {
+ case MDVI_ORIENT_TBLR:
+ break;
+ case MDVI_ORIENT_TBRL:
+ x = w - x;
+ break;
+ case MDVI_ORIENT_BTLR:
+ y = h - y;
+ break;
+ case MDVI_ORIENT_BTRL:
+ x = w - x;
+ y = h - y;
+ break;
+ case MDVI_ORIENT_RP90:
+ SWAPINT(w, h);
+ SWAPINT(x, y);
+ x = w - x;
+ break;
+ case MDVI_ORIENT_RM90:
+ SWAPINT(w, h);
+ SWAPINT(x, y);
+ y = h - y;
+ break;
+ case MDVI_ORIENT_IRP90:
+ SWAPINT(w, h);
+ SWAPINT(x, y);
+ break;
+ case MDVI_ORIENT_IRM90:
+ SWAPINT(w, h);
+ SWAPINT(x, y);
+ x = w - x;
+ y = h - y;
+ break;
+ }
+
+ dvi->device.draw_rule(dvi,
+ dvi->pos.hh - x, dvi->pos.vv - y, w, h, 1);
+}
+
+int set_char(DviContext *dvi, int opcode)
+{
+ int num;
+ int h;
+ int hh;
+ DviFontChar *ch;
+ DviFont *font;
+
+ if(opcode < 128)
+ num = opcode;
+ else
+ num = dugetn(dvi, opcode - DVI_SET1 + 1);
+ if(dvi->currfont == NULL) {
+ dvierr(dvi, _("no default font set yet\n"));
+ return -1;
+ }
+ font = dvi->currfont->ref;
+ ch = font_get_glyph(dvi, font, num);
+ if(ch == NULL || ch->missing) {
+ /* try to display something anyway */
+ ch = FONTCHAR(font, num);
+ if(!glyph_present(ch)) {
+ dviwarn(dvi,
+ _("requested character %d does not exist in `%s'\n"),
+ num, font->fontname);
+ return 0;
+ }
+ draw_box(dvi, ch);
+ } else if(dvi->curr_layer <= dvi->params.layer) {
+ if(ISVIRTUAL(font))
+ mdvi_run_macro(dvi, (Uchar *)font->private +
+ ch->offset, ch->width);
+ else if(ch->width && ch->height)
+ dvi->device.draw_glyph(dvi, ch,
+ dvi->pos.hh, dvi->pos.vv);
+ }
+ if(opcode >= DVI_PUT1 && opcode <= DVI_PUT4) {
+ SHOWCMD((dvi, "putchar", opcode - DVI_PUT1 + 1,
+ "char %d (%s)\n",
+ num, dvi->currfont->ref->fontname));
+ } else {
+ h = dvi->pos.h + ch->tfmwidth;
+ hh = dvi->pos.hh + pixel_round(dvi, ch->tfmwidth);
+ SHOWCMD((dvi, "setchar", num, "(%d,%d) h:=%d%c%d=%d, hh:=%d (%s)\n",
+ dvi->pos.hh, dvi->pos.vv,
+ DBGSUM(dvi->pos.h, ch->tfmwidth, h), hh,
+ font->fontname));
+ dvi->pos.h = h;
+ dvi->pos.hh = hh;
+ fix_after_horizontal(dvi);
+ }
+
+ return 0;
+}
+
+int set_rule(DviContext *dvi, int opcode)
+{
+ Int32 a, b;
+ int h, w;
+
+ a = dsget4(dvi);
+ b = dsget4(dvi); w = rule_round(dvi, b);
+ if(a > 0 && b > 0) {
+ h = vrule_round(dvi, a);
+ SHOWCMD((dvi, opcode == DVI_SET_RULE ? "setrule" : "putrule", -1,
+ "width %d, height %d (%dx%d pixels)\n",
+ b, a, w, h));
+ /* the `draw' functions expect the origin to be at the top left
+ * corner of the rule, not the bottom left, as in DVI files */
+ if(dvi->curr_layer <= dvi->params.layer)
+ dvi->device.draw_rule(dvi,
+ dvi->pos.hh, dvi->pos.vv - h + 1, w, h, 1);
+ } else {
+ SHOWCMD((dvi, opcode == DVI_SET_RULE ? "setrule" : "putrule", -1,
+ "(moving left only, by %d)\n", b));
+ }
+
+ if(opcode == DVI_SET_RULE) {
+ dvi->pos.h += b;
+ dvi->pos.hh += w;
+ fix_after_horizontal(dvi);
+ }
+ return 0;
+}
+
+int no_op(DviContext *dvi, int opcode)
+{
+ SHOWCMD((dvi, "noop", -1, ""));
+ return 0;
+}
+
+int push(DviContext *dvi, int opcode)
+{
+ if(dvi->stacktop == dvi->stacksize) {
+ if(!dvi->depth)
+ dviwarn(dvi, _("enlarging stack\n"));
+ dvi->stacksize += 8;
+ dvi->stack = xresize(dvi->stack,
+ DviState, dvi->stacksize);
+ }
+ memcpy(&dvi->stack[dvi->stacktop], &dvi->pos, sizeof(DviState));
+ SHOWCMD((dvi, "push", -1,
+ "level %d: (h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)\n",
+ dvi->stacktop,
+ dvi->pos.h, dvi->pos.v, dvi->pos.w, dvi->pos.x,
+ dvi->pos.y, dvi->pos.z, dvi->pos.hh, dvi->pos.vv));
+ dvi->stacktop++;
+ return 0;
+}
+
+int pop(DviContext *dvi, int opcode)
+{
+ if(dvi->stacktop == 0) {
+ dvierr(dvi, _("stack underflow\n"));
+ return -1;
+ }
+ memcpy(&dvi->pos, &dvi->stack[dvi->stacktop-1], sizeof(DviState));
+ SHOWCMD((dvi, "pop", -1,
+ "level %d: (h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)\n",
+ dvi->stacktop,
+ dvi->pos.h, dvi->pos.v, dvi->pos.w, dvi->pos.x,
+ dvi->pos.y, dvi->pos.z, dvi->pos.hh, dvi->pos.vv));
+ dvi->stacktop--;
+ return 0;
+}
+
+int move_right(DviContext *dvi, int opcode)
+{
+ Int32 arg;
+ int h, hh;
+
+ arg = dsgetn(dvi, opcode - DVI_RIGHT1 + 1);
+ h = dvi->pos.h;
+ hh = move_horizontal(dvi, arg);
+ SHOWCMD((dvi, "right", opcode - DVI_RIGHT1 + 1,
+ "%d h:=%d%c%d=%d, hh:=%d\n",
+ arg, DBGSUM(h, arg, dvi->pos.h), hh));
+ dvi->pos.hh = hh;
+ return 0;
+}
+
+int move_down(DviContext *dvi, int opcode)
+{
+ Int32 arg;
+ int v, vv;
+
+ arg = dsgetn(dvi, opcode - DVI_DOWN1 + 1);
+ v = dvi->pos.v;
+ vv = move_vertical(dvi, arg);
+ SHOWCMD((dvi, "down", opcode - DVI_DOWN1 + 1,
+ "%d v:=%d%c%d=%d, vv:=%d\n",
+ arg, DBGSUM(v, arg, dvi->pos.v), vv));
+ dvi->pos.vv = vv;
+ return 0;
+}
+
+int move_w(DviContext *dvi, int opcode)
+{
+ int h, hh;
+
+ if(opcode != DVI_W0)
+ dvi->pos.w = dsgetn(dvi, opcode - DVI_W0);
+ h = dvi->pos.h;
+ hh = move_horizontal(dvi, dvi->pos.w);
+ SHOWCMD((dvi, "w", opcode - DVI_W0,
+ "%d h:=%d%c%d=%d, hh:=%d\n",
+ dvi->pos.w, DBGSUM(h, dvi->pos.w, dvi->pos.h), hh));
+ dvi->pos.hh = hh;
+ return 0;
+}
+
+int move_x(DviContext *dvi, int opcode)
+{
+ int h, hh;
+
+ if(opcode != DVI_X0)
+ dvi->pos.x = dsgetn(dvi, opcode - DVI_X0);
+ h = dvi->pos.h;
+ hh = move_horizontal(dvi, dvi->pos.x);
+ SHOWCMD((dvi, "x", opcode - DVI_X0,
+ "%d h:=%d%c%d=%d, hh:=%d\n",
+ dvi->pos.x, DBGSUM(h, dvi->pos.x, dvi->pos.h), hh));
+ dvi->pos.hh = hh;
+ return 0;
+}
+
+int move_y(DviContext *dvi, int opcode)
+{
+ int v, vv;
+
+ if(opcode != DVI_Y0)
+ dvi->pos.y = dsgetn(dvi, opcode - DVI_Y0);
+ v = dvi->pos.v;
+ vv = move_vertical(dvi, dvi->pos.y);
+ SHOWCMD((dvi, "y", opcode - DVI_Y0,
+ "%d h:=%d%c%d=%d, hh:=%d\n",
+ dvi->pos.y, DBGSUM(v, dvi->pos.y, dvi->pos.v), vv));
+ dvi->pos.vv = vv;
+ return 0;
+}
+
+int move_z(DviContext *dvi, int opcode)
+{
+ int v, vv;
+
+ if(opcode != DVI_Z0)
+ dvi->pos.z = dsgetn(dvi, opcode - DVI_Z0);
+ v = dvi->pos.v;
+ vv = move_vertical(dvi, dvi->pos.z);
+ SHOWCMD((dvi, "z", opcode - DVI_Z0,
+ "%d h:=%d%c%d=%d, hh:=%d\n",
+ dvi->pos.z, DBGSUM(v, dvi->pos.z, dvi->pos.v), vv));
+ dvi->pos.vv = vv;
+ return 0;
+}
+
+int sel_font(DviContext *dvi, int opcode)
+{
+ DviFontRef *ref;
+ int ndx;
+
+ ndx = opcode - DVI_FNT_NUM0;
+ if(dvi->depth)
+ ref = font_find_flat(dvi, ndx);
+ else
+ ref = dvi->findref(dvi, ndx);
+ if(ref == NULL) {
+ dvierr(dvi, _("font %d is not defined\n"),
+ opcode - DVI_FNT_NUM0);
+ return -1;
+ }
+ SHOWCMD((dvi, "fntnum", opcode - DVI_FNT_NUM0,
+ "current font is %s\n",
+ ref->ref->fontname));
+ dvi->currfont = ref;
+ return 0;
+}
+
+int sel_fontn(DviContext *dvi, int opcode)
+{
+ Int32 arg;
+ DviFontRef *ref;
+
+ arg = dugetn(dvi, opcode - DVI_FNT1 + 1);
+ if(dvi->depth)
+ ref = font_find_flat(dvi, arg);
+ else
+ ref = dvi->findref(dvi, arg);
+ if(ref == NULL) {
+ dvierr(dvi, _("font %d is not defined\n"), arg);
+ return -1;
+ }
+ SHOWCMD((dvi, "fnt", opcode - DVI_FNT1 + 1,
+ "current font is %s (id %d)\n",
+ ref->ref->fontname, arg));
+ dvi->currfont = ref;
+ return 0;
+}
+
+int special(DviContext *dvi, int opcode)
+{
+ char *s;
+ Int32 arg;
+
+ arg = dugetn(dvi, opcode - DVI_XXX1 + 1);
+ s = xmalloc(arg + 1);
+ dread(dvi, s, arg);
+ s[arg] = 0;
+ mdvi_do_special(dvi, s);
+ SHOWCMD((dvi, "XXXX", opcode - DVI_XXX1 + 1,
+ "[%s]", s));
+ xfree(s);
+ return 0;
+}
+
+int def_font(DviContext *dvi, int opcode)
+{
+ DviFontRef *ref;
+ Int32 arg;
+
+ arg = dugetn(dvi, opcode - DVI_FNT_DEF1 + 1);
+ if(dvi->depth)
+ ref = font_find_flat(dvi, arg);
+ else
+ ref = dvi->findref(dvi, arg);
+ /* skip the rest */
+ dskip(dvi, 12);
+ dskip(dvi, duget1(dvi) + duget1(dvi));
+ if(ref == NULL) {
+ dvierr(dvi, _("font %d is not defined in postamble\n"), arg);
+ return -1;
+ }
+ SHOWCMD((dvi, "fntdef", opcode - DVI_FNT_DEF1 + 1,
+ "%d -> %s (%d links)\n",
+ ref->fontid, ref->ref->fontname,
+ ref->ref->links));
+ return 0;
+}
+
+int unexpected(DviContext *dvi, int opcode)
+{
+ dvierr(dvi, _("unexpected opcode %d\n"), opcode);
+ return -1;
+}
+
+int undefined(DviContext *dvi, int opcode)
+{
+ dvierr(dvi, _("undefined opcode %d\n"), opcode);
+ return -1;
+}
+
diff --git a/dviware/mdvi/lib/files.c b/dviware/mdvi/lib/files.c
new file mode 100644
index 0000000000..d3dbcfedc1
--- /dev/null
+++ b/dviware/mdvi/lib/files.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "common.h"
+
+char *dgets(Dstring *dstr, FILE *in)
+{
+ char buffer[256];
+
+ dstr->length = 0;
+ if(feof(in))
+ return NULL;
+ while(fgets(buffer, 256, in) != NULL) {
+ int len = strlen(buffer);
+
+ if(buffer[len-1] == '\n') {
+ dstring_append(dstr, buffer, len - 1);
+ break;
+ }
+ dstring_append(dstr, buffer, len);
+ }
+ if(dstr->data)
+ dstr->data[dstr->length] = 0;
+ return dstr->data;
+}
+
+/* some simple helper functions to manipulate file names */
+
+const char *file_basename(const char *filename)
+{
+ const char *ptr = strrchr(filename, '/');
+
+ return (ptr ? ptr + 1 : filename);
+}
+
+const char *file_extension(const char *filename)
+{
+ const char *ptr = strchr(file_basename(filename), '.');
+
+ return (ptr ? ptr + 1 : NULL);
+}
+
+int file_readable(const char *filename)
+{
+ int status = (access(filename, R_OK) == 0);
+
+ DEBUG((DBG_FILES, "file_redable(%s) -> %s\n",
+ filename, status ? "Yes" : "No"));
+ return status;
+}
+
+int file_exists(const char *filename)
+{
+ int status = (access(filename, F_OK) == 0);
+
+ DEBUG((DBG_FILES, "file_exists(%s) -> %s\n",
+ filename, status ? "Yes" : "No"));
+ return status;
+}
+
+static char *xstrchre(const char *string, int c)
+{
+ const char *ptr;
+
+ for(ptr = string; *ptr && *ptr != c; ptr++);
+ return (char *)ptr;
+}
+
+char *find_in_path(const char *filename, const char *path)
+{
+ const char *p, *q;
+ char *try;
+ int len;
+
+ /* if the file is readable as given, return it */
+ if(file_readable(filename))
+ return xstrdup(filename);
+
+ /* worst case scenario */
+ try = xmalloc(strlen(path) + strlen(filename) + 2);
+ try[0] = 0;
+
+ for(p = path; *p; p = q) {
+ q = xstrchre(p, ':');
+ len = q - p;
+ xstrncpy(try, p, len);
+ try[len] = '/';
+ strcpy(try + len + 1, filename);
+ if(file_readable(try))
+ break;
+ if(*q) q++;
+ }
+
+ if(*p)
+ return try;
+ else {
+ xfree(try);
+ return NULL;
+ }
+}
+
+char *read_into_core(const char *file, size_t *size)
+{
+ FILE *in;
+ struct stat st;
+ char *ptr;
+
+ in = fopen(file, "r");
+ if(in == NULL)
+ return NULL;
+ if(fstat(fileno(in), &st) < 0) {
+ /* I don't think this is possible, but who knows */
+ fclose(in);
+ return NULL;
+ }
+ if(st.st_size == 0) {
+ warning("%s: file is empty\n", file);
+ fclose(in);
+ return NULL;
+ }
+ ptr = xmalloc(st.st_size + 1);
+ if(fread(ptr, st.st_size, 1, in) != 1) {
+ fclose(in);
+ xfree(ptr);
+ return NULL;
+ }
+ fclose(in);
+ ptr[st.st_size] = 0;
+ if(size) *size = st.st_size;
+ return ptr;
+}
diff --git a/dviware/mdvi/lib/font.c b/dviware/mdvi/lib/font.c
new file mode 100644
index 0000000000..63fed3eb88
--- /dev/null
+++ b/dviware/mdvi/lib/font.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+static ListHead fontlist;
+
+extern char *_mdvi_fallback_font;
+
+extern void vf_free_macros(DviFont *);
+
+#define finfo search.info
+#define TYPENAME(font) \
+ ((font)->finfo ? (font)->finfo->name : "none")
+
+void font_print(void)
+{
+ DviFont *font;
+
+ message("Fonts registered (%d):\n", fontlist.count);
+ LIST_FOREACH(font, DviFont, &fontlist) {
+ message("%s: %dx%ddpi, scaled %.2f of %.2fpt, type `%s' at %p\n",
+ font->fontname, font->hdpi, font->vdpi,
+ (double)font->scale / 1048576,
+ (double)font->design / 1048576,
+ font->search.id < 0 ? "unknown" : font->search.info->name,
+ font);
+ message(" %sloaded, filename: %s\n",
+ font->chars ? "" : "not ", font->filename);
+ if(font->links) {
+ message(" in use (%d links), %d glyphs [%d, %d]\n",
+ font->links, FONT_GLYPH_COUNT(font),
+ font->loc, font->hic);
+ if(font->subfonts) {
+ DviFontRef *ref;
+
+ message(" subfonts:\n");
+ for(ref = font->subfonts; ref; ref = ref->next) {
+ message(" %s (id %d) at %p\n",
+ ref->ref->fontname,
+ ref->fontid, ref->ref);
+ }
+ }
+ } else
+ message(" not used\n");
+ }
+}
+
+int font_reopen(DviFont *font)
+{
+ if(font->in)
+ fseek(font->in, (long)0, SEEK_SET);
+ else if((font->in = fopen(font->filename, "r")) == NULL) {
+ DEBUG((DBG_FILES, "reopen(%s) -> Error\n", font->filename));
+ return -1;
+ }
+ DEBUG((DBG_FILES, "reopen(%s) -> Ok.\n", font->filename));
+ return 0;
+}
+
+/* used from context: params and device */
+static int load_font_file(DviParams *params, DviFont *font)
+{
+ int status;
+
+ if(SEARCH_DONE(font->search))
+ return -1;
+ if(font->in == NULL && font_reopen(font) < 0)
+ return -1;
+ DEBUG((DBG_FONTS, "%s: loading %s font from `%s'\n",
+ font->fontname,
+ font->finfo->name, font->filename));
+ do {
+ status = font->finfo->load(params, font);
+ } while(status < 0 && mdvi_font_retry(params, font) == 0);
+ if(status < 0)
+ return -1;
+ if(font->in) {
+ fclose(font->in);
+ font->in = NULL;
+ }
+ DEBUG((DBG_FONTS, "reload_font(%s) -> %s\n",
+ font->fontname, status < 0 ? "Error" : "Ok"));
+ return 0;
+}
+
+void font_drop_one(DviFontRef *ref)
+{
+ DviFont *font;
+
+ font = ref->ref;
+ xfree(ref);
+ /* drop all children */
+ for(ref = font->subfonts; ref; ref = ref->next) {
+ /* just adjust the reference counts */
+ ref->ref->links--;
+ }
+ if(--font->links == 0) {
+ /*
+ * this font doesn't have any more references, but
+ * we still keep it around in case a virtual font
+ * requests it.
+ */
+ if(font->in) {
+ fclose(font->in);
+ font->in = NULL;
+ }
+ if(LIST(font) != fontlist.tail) {
+ /* move it to the end of the list */
+ listh_remove(&fontlist, LIST(font));
+ listh_append(&fontlist, LIST(font));
+ }
+ }
+ DEBUG((DBG_FONTS, "%s: reference dropped, %d more left\n",
+ font->fontname, font->links));
+}
+
+void font_drop_chain(DviFontRef *head)
+{
+ DviFontRef *ptr;
+
+ for(; (ptr = head); ) {
+ head = ptr->next;
+ font_drop_one(ptr);
+ }
+}
+
+int font_free_unused(DviDevice *dev)
+{
+ DviFont *font, *next;
+ int count = 0;
+
+ DEBUG((DBG_FONTS, "destroying unused fonts\n"));
+ for(font = (DviFont *)fontlist.head; font; font = next) {
+ DviFontRef *ref;
+
+ next = font->next;
+ if(font->links)
+ continue;
+ count++;
+ DEBUG((DBG_FONTS, "removing unused %s font `%s'\n",
+ TYPENAME(font), font->fontname));
+ listh_remove(&fontlist, LIST(font));
+ if(font->in)
+ fclose(font->in);
+ /* get rid of subfonts (but can't use `drop_chain' here) */
+ for(; (ref = font->subfonts); ) {
+ font->subfonts = ref->next;
+ xfree(ref);
+ }
+ /* remove this font */
+ font_reset_font_glyphs(dev, font, MDVI_FONTSEL_GLYPH);
+ /* let the font destroy its private data */
+ if(font->finfo->freedata)
+ font->finfo->freedata(font);
+ /* destroy characters */
+ if(font->chars)
+ xfree(font->chars);
+ xfree(font->fontname);
+ xfree(font->filename);
+ xfree(font);
+ }
+ DEBUG((DBG_FONTS, "%d unused fonts removed\n", count));
+ return count;
+}
+
+/* used from context: params and device */
+DviFontRef *
+font_reference(
+ DviParams *params, /* rendering parameters */
+ Int32 id, /* external id number */
+ const char *name, /* font name */
+ Int32 sum, /* checksum (from DVI of VF) */
+ int hdpi, /* resolution */
+ int vdpi,
+ Int32 scale) /* scaling factor (from DVI or VF) */
+{
+ DviFont *font;
+ DviFontRef *ref;
+
+ /* see if there is a font with the same characteristics */
+ for(font = (DviFont *)fontlist.head; font; font = font->next) {
+ if(strcmp(name, font->fontname) == 0
+ && (!sum || !font->checksum || font->checksum == sum)
+ && font->hdpi == hdpi
+ && font->vdpi == vdpi
+ && font->scale == scale)
+ break;
+ }
+ /* try to load the font */
+ if(font == NULL) {
+ font = mdvi_add_font(name, sum, hdpi, vdpi, scale);
+ if(font == NULL)
+ return NULL;
+ listh_append(&fontlist, LIST(font));
+ }
+ if(!font->links && !font->chars && load_font_file(params, font) < 0) {
+ DEBUG((DBG_FONTS, "font_reference(%s) -> Error\n", name));
+ return NULL;
+ }
+ ref = xalloc(DviFontRef);
+ ref->ref = font;
+ font->links++;
+ ref->fontid = id;
+
+ if(LIST(font) != fontlist.head) {
+ listh_remove(&fontlist, LIST(font));
+ listh_prepend(&fontlist, LIST(font));
+ }
+
+ DEBUG((DBG_FONTS, "font_reference(%s) -> %d links\n",
+ font->fontname, font->links));
+ return ref;
+}
+
+void font_transform_glyph(DviOrientation orient, DviGlyph *g)
+{
+ BITMAP *map;
+ int x, y;
+
+ map = (BITMAP *)g->data;
+ if(MDVI_GLYPH_ISEMPTY(map))
+ map = NULL;
+
+ /* put the glyph in the right orientation */
+ switch(orient) {
+ case MDVI_ORIENT_TBLR:
+ break;
+ case MDVI_ORIENT_TBRL:
+ g->x = g->w - g->x;
+ if(map) bitmap_flip_horizontally(map);
+ break;
+ case MDVI_ORIENT_BTLR:
+ g->y = g->h - g->y;
+ if(map) bitmap_flip_vertically(map);
+ break;
+ case MDVI_ORIENT_BTRL:
+ g->x = g->w - g->x;
+ g->y = g->h - g->y;
+ if(map) bitmap_flip_diagonally(map);
+ break;
+ case MDVI_ORIENT_RP90:
+ if(map) bitmap_rotate_counter_clockwise(map);
+ y = g->y;
+ x = g->w - g->x;
+ g->x = y;
+ g->y = x;
+ SWAPINT(g->w, g->h);
+ break;
+ case MDVI_ORIENT_RM90:
+ if(map) bitmap_rotate_clockwise(map);
+ y = g->h - g->y;
+ x = g->x;
+ g->x = y;
+ g->y = x;
+ SWAPINT(g->w, g->h);
+ break;
+ case MDVI_ORIENT_IRP90:
+ if(map) bitmap_flip_rotate_counter_clockwise(map);
+ y = g->y;
+ x = g->x;
+ g->x = y;
+ g->y = x;
+ SWAPINT(g->w, g->h);
+ break;
+ case MDVI_ORIENT_IRM90:
+ if(map) bitmap_flip_rotate_clockwise(map);
+ y = g->h - g->y;
+ x = g->w - g->x;
+ g->x = y;
+ g->y = x;
+ SWAPINT(g->w, g->h);
+ break;
+ }
+}
+
+static int load_one_glyph(DviContext *dvi, DviFont *font, int code)
+{
+ BITMAP *map;
+ DviFontChar *ch;
+ int status;
+
+#ifndef NODEBUG
+ ch = FONTCHAR(font, code);
+ DEBUG((DBG_GLYPHS, "loading glyph code %d in %s (at %u)\n",
+ code, font->fontname, ch->offset));
+#endif
+ if(font->finfo->getglyph == NULL) {
+ /* font type does not need to load glyphs (e.g. vf) */
+ return 0;
+ }
+
+ status = font->finfo->getglyph(&dvi->params, font, code);
+ if(status < 0)
+ return -1;
+ /* get the glyph again (font->chars may have changed) */
+ ch = FONTCHAR(font, code);
+#ifndef NODEBUG
+ map = (BITMAP *)ch->glyph.data;
+ if(DEBUGGING(BITMAP_DATA)) {
+ DEBUG((DBG_BITMAP_DATA,
+ "%s: new %s bitmap for character %d:\n",
+ font->fontname, TYPENAME(font), code));
+ if(MDVI_GLYPH_ISEMPTY(map))
+ DEBUG((DBG_BITMAP_DATA, "blank bitmap\n"));
+ else
+ bitmap_print(stderr, map);
+ }
+#endif
+ /* check if we have to scale it */
+ if(!font->finfo->scalable && font->hdpi != font->vdpi) {
+ int hs, vs, d;
+
+ /* we scale it ourselves */
+ d = Max(font->hdpi, font->vdpi);
+ hs = d / font->hdpi;
+ vs = d / font->vdpi;
+ if(ch->width && ch->height && (hs > 1 || vs > 1)) {
+ int h, v;
+ DviGlyph glyph;
+
+ DEBUG((DBG_FONTS,
+ "%s: scaling glyph %d to resolution %dx%d\n",
+ font->fontname, code, font->hdpi, font->vdpi));
+ h = dvi->params.hshrink;
+ v = dvi->params.vshrink;
+ d = dvi->params.density;
+ dvi->params.hshrink = hs;
+ dvi->params.vshrink = vs;
+ dvi->params.density = 50;
+ /* shrink it */
+ font->finfo->shrink0(dvi, font, ch, &glyph);
+ /* restore parameters */
+ dvi->params.hshrink = h;
+ dvi->params.vshrink = v;
+ dvi->params.density = d;
+ /* update glyph data */
+ if(!MDVI_GLYPH_ISEMPTY(ch->glyph.data))
+ bitmap_destroy((BITMAP *)ch->glyph.data);
+ ch->glyph.data = glyph.data;
+ ch->glyph.x = glyph.x;
+ ch->glyph.y = glyph.y;
+ ch->glyph.w = glyph.w;
+ ch->glyph.h = glyph.h;
+ }
+
+ }
+ font_transform_glyph(dvi->params.orientation, &ch->glyph);
+
+ return 0;
+}
+
+DviFontChar *font_get_glyph(DviContext *dvi, DviFont *font, int code)
+{
+ DviFontChar *ch;
+
+again:
+ /* if we have not loaded the font yet, do so now */
+ if(!font->chars && load_font_file(&dvi->params, font) < 0)
+ return NULL;
+
+ /* get the unscaled glyph, maybe loading it from disk */
+ ch = FONTCHAR(font, code);
+ if(!ch || !glyph_present(ch))
+ return NULL;
+ if(!ch->loaded && load_one_glyph(dvi, font, code) == -1) {
+ if(font->chars == NULL) {
+ /* we need to try another font class */
+ goto again;
+ }
+ return NULL;
+ }
+ /* yes, we have to do this again */
+ ch = FONTCHAR(font, code);
+
+ /* Got the glyph. If we also have the right scaled glyph, do no more */
+ if(!ch->width || !ch->height ||
+ font->finfo->getglyph == NULL ||
+ (dvi->params.hshrink == 1 && dvi->params.vshrink == 1))
+ return ch;
+
+ /* If the glyph is empty, we just need to shrink the box */
+ if(ch->missing || MDVI_GLYPH_ISEMPTY(ch->glyph.data)) {
+ if(MDVI_GLYPH_UNSET(ch->shrunk.data))
+ mdvi_shrink_box(dvi, font, ch, &ch->shrunk);
+ return ch;
+ } else if(MDVI_ENABLED(dvi, MDVI_PARAM_ANTIALIASED)) {
+ if(ch->grey.data &&
+ ch->fg == dvi->curr_fg &&
+ ch->bg == dvi->curr_bg)
+ return ch;
+ if(ch->grey.data) {
+ if(dvi->device.free_image)
+ dvi->device.free_image(ch->grey.data);
+ ch->grey.data = NULL;
+ }
+ font->finfo->shrink1(dvi, font, ch, &ch->grey);
+ } else if(!ch->shrunk.data)
+ font->finfo->shrink0(dvi, font, ch, &ch->shrunk);
+
+ return ch;
+}
+
+void font_reset_one_glyph(DviDevice *dev, DviFontChar *ch, int what)
+{
+ if(!glyph_present(ch))
+ return;
+ if(what & MDVI_FONTSEL_BITMAP) {
+ if(MDVI_GLYPH_NONEMPTY(ch->shrunk.data))
+ bitmap_destroy((BITMAP *)ch->shrunk.data);
+ ch->shrunk.data = NULL;
+ }
+ if(what & MDVI_FONTSEL_GREY) {
+ if(MDVI_GLYPH_NONEMPTY(ch->grey.data)) {
+ if(dev->free_image)
+ dev->free_image(ch->grey.data);
+ }
+ ch->grey.data = NULL;
+ }
+ if(what & MDVI_FONTSEL_GLYPH) {
+ if(MDVI_GLYPH_NONEMPTY(ch->glyph.data))
+ bitmap_destroy((BITMAP *)ch->glyph.data);
+ ch->glyph.data = NULL;
+ ch->loaded = 0;
+ }
+}
+
+void font_reset_font_glyphs(DviDevice *dev, DviFont *font, int what)
+{
+ int i;
+ DviFontChar *ch;
+
+ if(what & MDVI_FONTSEL_GLYPH)
+ what |= MDVI_FONTSEL_BITMAP|MDVI_FONTSEL_GREY;
+ if(font->subfonts) {
+ DviFontRef *ref;
+
+ for(ref = font->subfonts; ref; ref = ref->next)
+ font_reset_font_glyphs(dev, ref->ref, what);
+ }
+ if(font->in) {
+ DEBUG((DBG_FILES, "close(%s)\n", font->filename));
+ fclose(font->in);
+ font->in = NULL;
+ }
+ if(font->finfo->getglyph == NULL)
+ return;
+ DEBUG((DBG_FONTS, "resetting glyphs in font `%s'\n", font->fontname));
+ for(ch = font->chars, i = font->loc; i <= font->hic; ch++, i++) {
+ if(glyph_present(ch))
+ font_reset_one_glyph(dev, ch, what);
+ }
+ if((what & MDVI_FONTSEL_GLYPH) && font->finfo->reset)
+ font->finfo->reset(font);
+}
+
+void font_reset_chain_glyphs(DviDevice *dev, DviFontRef *head, int what)
+{
+ DviFontRef *ref;
+
+ for(ref = head; ref; ref = ref->next)
+ font_reset_font_glyphs(dev, ref->ref, what);
+}
+
+static int compare_refs(const void *p1, const void *p2)
+{
+ return ((*(DviFontRef **)p1)->fontid - (*(DviFontRef **)p2)->fontid);
+}
+
+void font_finish_definitions(DviContext *dvi)
+{
+ int count;
+ DviFontRef **map, *ref;
+
+ /* first get rid of unused fonts */
+ font_free_unused(&dvi->device);
+
+ if(dvi->fonts == NULL) {
+ warning(_("%s: no fonts defined\n"), dvi->filename);
+ return;
+ }
+ map = xnalloc(DviFontRef *, dvi->nfonts);
+ for(count = 0, ref = dvi->fonts; ref; ref = ref->next)
+ map[count++] = ref;
+ /* sort the array by font id */
+ qsort(map, dvi->nfonts, sizeof(DviFontRef *), compare_refs);
+ dvi->fontmap = map;
+}
+
+DviFontRef *font_find_flat(DviContext *dvi, Int32 id)
+{
+ DviFontRef *ref;
+
+ for(ref = dvi->fonts; ref; ref = ref->next)
+ if(ref->fontid == id)
+ break;
+ return ref;
+}
+
+DviFontRef *font_find_mapped(DviContext *dvi, Int32 id)
+{
+ int lo, hi, n;
+ DviFontRef **map;
+
+ /* do a binary search */
+ lo = 0; hi = dvi->nfonts;
+ map = dvi->fontmap;
+ while(lo < hi) {
+ int sign;
+
+ n = (hi + lo) >> 1;
+ sign = (map[n]->fontid - id);
+ if(sign == 0)
+ break;
+ else if(sign < 0)
+ lo = n;
+ else
+ hi = n;
+ }
+ if(lo >= hi)
+ return NULL;
+ return map[n];
+}
+
diff --git a/dviware/mdvi/lib/fontmap.c b/dviware/mdvi/lib/fontmap.c
new file mode 100644
index 0000000000..8b60a05d8a
--- /dev/null
+++ b/dviware/mdvi/lib/fontmap.c
@@ -0,0 +1,1169 @@
+/* encoding.c - functions to manipulate encodings and fontmaps */
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+#include <kpathsea/expand.h>
+#include <kpathsea/pathsearch.h>
+
+typedef struct _DviFontMap DviFontMap;
+
+struct _DviFontMap {
+ ListHead entries;
+ DviHashTable fonts;
+};
+
+typedef struct _PSFontMap {
+ struct _PSFontMap *next;
+ struct _PSFontMap *prev;
+ char *psname;
+ char *mapname;
+ char *fullname;
+} PSFontMap;
+
+/* these variables control PS font maps */
+static char *pslibdir = NULL; /* path where we look for PS font maps */
+static char *psfontdir = NULL; /* PS font search path */
+static int psinitialized = 0; /* did we expand the path already? */
+
+static ListHead psfonts = MDVI_EMPTY_LIST_HEAD;
+static DviHashTable pstable = MDVI_EMPTY_HASH_TABLE;
+
+static ListHead fontmaps;
+static DviHashTable maptable;
+static int fontmaps_loaded = 0;
+
+#define MAP_HASH_SIZE 57
+#define ENC_HASH_SIZE 31
+#define PSMAP_HASH_SIZE 57
+
+/* this hash table should be big enough to
+ * hold (ideally) one glyph name per bucket */
+#define ENCNAME_HASH_SIZE 131 /* most TeX fonts have 128 glyphs */
+
+static ListHead encodings = MDVI_EMPTY_LIST_HEAD;
+static DviEncoding *tex_text_encoding = NULL;
+static DviEncoding *default_encoding = NULL;
+
+/* we keep two hash tables for encodings: one for their base files (e.g.
+ * "8r.enc"), and another one for their names (e.g. "TeXBase1Encoding") */
+static DviHashTable enctable = MDVI_EMPTY_HASH_TABLE;
+static DviHashTable enctable_file = MDVI_EMPTY_HASH_TABLE;
+
+/* the TeX text encoding, from dvips */
+static char *tex_text_vector[256] = {
+ "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon",
+ "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
+ "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave",
+ "acute", "caron", "breve", "macron", "ring", "cedilla",
+ "germandbls", "ae", "oe", "oslash", "AE", "OE", "Oslash", "space",
+ "exclam", "quotedbl", "numbersign", "dollar", "percent",
+ "ampersand", "quoteright", "parenleft", "parenright", "asterisk",
+ "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two",
+ "three", "four", "five", "six", "seven", "eight", "nine", "colon",
+ "semicolon", "less", "equal", "greater", "question", "at", "A", "B",
+ "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+ "bracketleft", "backslash", "bracketright", "circumflex",
+ "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h",
+ "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
+ "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "tilde",
+ "dieresis", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static void ps_init_default_paths __PROTO((void));
+
+/*
+ * What we do here is allocate one block large enough to hold the entire
+ * file (these files are small) minus the leading comments. This is much
+ * better than allocating up to 256 tiny strings per encoding vector. */
+static int read_encoding(DviEncoding *enc)
+{
+ FILE *in;
+ int curr;
+ char *line;
+ char *name;
+ char *next;
+ struct stat st;
+
+ ASSERT(enc->private == NULL);
+
+ in = fopen(enc->filename, "r");
+ if(in == NULL) {
+ DEBUG((DBG_FMAP, "%s: could not read `%s' (%s)\n",
+ enc->name, enc->filename, strerror(errno)));
+ return -1;
+ }
+ if(fstat(fileno(in), &st) < 0) {
+ /* should not happen */
+ fclose(in);
+ return -1;
+ }
+ st.st_size -= enc->offset;
+
+ /* this will be one big string */
+ enc->private = (char *)malloc(st.st_size + 1);
+ /* setup the hash table */
+ mdvi_hash_create(&enc->nametab, ENCNAME_HASH_SIZE);
+ /* setup the encoding vector */
+ enc->vector = (char **)xmalloc(256 * sizeof(char *));
+
+ /* jump to the beginning of the interesting part */
+ fseek(in, enc->offset, SEEK_SET);
+ /* and read everything */
+ if(fread(enc->private, st.st_size, 1, in) != 1) {
+ fclose(in);
+ xfree(enc->private);
+ enc->private = NULL;
+ return -1;
+ }
+ /* we don't need this anymore */
+ fclose(in);
+ curr = 0;
+
+ next = name = NULL;
+ DEBUG((DBG_FMAP, "%s: reading encoding vector\n", enc->name));
+ for(line = enc->private; *line && curr < 256; line = next) {
+ SKIPSP(line);
+ if(*line == ']') {
+ line++; SKIPSP(line);
+ if(STRNEQ(line, "def", 3))
+ break;
+ }
+ name = getword(line, " \t\n", &next);
+ if(name == NULL)
+ break;
+ /* next > line */
+ if(*name < ' ')
+ continue;
+ if(*name == '%') {
+ while(*next && *next != '\n')
+ next++;
+ if(*next) next++; /* skip \n */
+ continue;
+ }
+
+ /* got a name */
+ if(*next) *next++ = 0;
+
+ if(*name == '/')
+ name++;
+ enc->vector[curr] = name;
+ /* add it to the hash table */
+ if(!STREQ(name, ".notdef")) {
+ mdvi_hash_add(&enc->nametab, MDVI_KEY(name),
+ Int2Ptr(curr + 1), MDVI_HASH_REPLACE);
+ }
+ curr++;
+ }
+ if(curr == 0) {
+ mdvi_hash_reset(&enc->nametab, 0);
+ xfree(enc->private);
+ xfree(enc);
+ return -1;
+ }
+ while(curr < 256)
+ enc->vector[curr++] = NULL;
+ return 0;
+}
+
+static DviEncoding *find_encoding(const char *name)
+{
+ return (DviEncoding *)(encodings.count ?
+ mdvi_hash_lookup(&enctable, MDVI_KEY(name)) : NULL);
+}
+
+static void destroy_encoding(DviEncoding *enc)
+{
+ if(enc == default_encoding) {
+ default_encoding = tex_text_encoding;
+ /* now we use reference counts again */
+ mdvi_release_encoding(enc, 1);
+ }
+ if(enc != tex_text_encoding) {
+ mdvi_hash_reset(&enc->nametab, 0);
+ if(enc->private) {
+ xfree(enc->private);
+ xfree(enc->vector);
+ }
+ if(enc->name)
+ xfree(enc->name);
+ if(enc->filename)
+ xfree(enc->filename);
+ xfree(enc);
+ }
+}
+
+/* this is used for the `enctable_file' hash table */
+static void file_hash_free(DviHashKey key, void *data)
+{
+ xfree(key);
+}
+
+static DviEncoding *register_encoding(const char *basefile, int replace)
+{
+ DviEncoding *enc;
+ FILE *in;
+ char *filename;
+ char *name;
+ Dstring input;
+ char *line;
+ long offset;
+
+ DEBUG((DBG_FMAP, "register_encoding(%s)\n", basefile));
+
+ if(encodings.count) {
+ enc = mdvi_hash_lookup(&enctable_file, MDVI_KEY(basefile));
+ if(enc != NULL) {
+ DEBUG((DBG_FMAP, "%s: already there\n", basefile));
+ return enc; /* no error */
+ }
+ }
+
+ /* try our own files first */
+ filename = kpse_find_file(basefile,
+ kpse_program_text_format, 0);
+
+ /* then try the system-wide ones */
+ if(filename == NULL)
+ filename = kpse_find_file(basefile,
+ kpse_tex_ps_header_format, 0);
+ if(filename == NULL)
+ filename = kpse_find_file(basefile,
+ kpse_dvips_config_format, 0);
+
+ /* finally try the given name */
+ if(filename == NULL)
+ filename = xstrdup(basefile);
+
+ in = fopen(filename, "r");
+ if(in == NULL) {
+ xfree(filename);
+ return NULL;
+ }
+
+ /* just lookup the name of the encoding */
+ name = NULL;
+ dstring_init(&input);
+ while((line = dgets(&input, in)) != NULL) {
+ if(STRNEQ(line, "Encoding=", 9)) {
+ name = getword(line + 9, " \t", &line);
+ if(*line) *line++ = 0;
+ break;
+ } else if(*line == '/') {
+ char *label = getword(line + 1, " \t", &line);
+ if(*line) {
+ *line++ = 0;
+ SKIPSP(line);
+ if(*line == '[') {
+ *line = 0;
+ name = label;
+ break;
+ }
+ }
+ }
+ }
+ offset = ftell(in);
+ fclose(in);
+ if(name == NULL || *name == 0) {
+ DEBUG((DBG_FMAP,
+ "%s: could not determine name of encoding\n",
+ basefile));
+ xfree(filename);
+ return NULL;
+ }
+
+ /* check if the encoding is already there */
+ enc = find_encoding(name);
+ if(enc == tex_text_encoding) {
+ /* A special case: if the vector we found is the static one,
+ * allow the user to override it with an external file */
+ listh_remove(&encodings, LIST(enc));
+ mdvi_hash_remove(&enctable, MDVI_KEY(enc->name));
+ if(enc == default_encoding)
+ default_encoding = NULL;
+ } else if(enc) {
+ /* if the encoding is being used, refuse to remove it */
+ if(enc->links) {
+ xfree(filename);
+ dstring_reset(&input);
+ return NULL;
+ }
+ if(replace) {
+ mdvi_hash_remove(&enctable, MDVI_KEY(name));
+ mdvi_hash_remove(&enctable_file, MDVI_KEY(basefile));
+ listh_remove(&encodings, LIST(enc));
+ if(enc == default_encoding) {
+ default_encoding = NULL;
+ mdvi_release_encoding(enc, 1);
+ }
+ DEBUG((DBG_FMAP, "%s: overriding encoding\n", name));
+ destroy_encoding(enc);
+ } else {
+ xfree(filename);
+ dstring_reset(&input);
+ return enc; /* no error */
+ }
+ }
+ enc = xalloc(DviEncoding);
+ enc->name = xstrdup(name);
+ enc->filename = filename;
+ enc->links = 0;
+ enc->offset = offset;
+ enc->private = NULL;
+ enc->vector = NULL;
+ mdvi_hash_init(&enc->nametab);
+ dstring_reset(&input);
+ if(default_encoding == NULL)
+ default_encoding = enc;
+ mdvi_hash_add(&enctable, MDVI_KEY(enc->name),
+ enc, MDVI_HASH_UNCHECKED);
+ mdvi_hash_add(&enctable_file, MDVI_KEY(xstrdup(basefile)),
+ enc, MDVI_HASH_REPLACE);
+ listh_prepend(&encodings, LIST(enc));
+ DEBUG((DBG_FMAP, "%s: encoding `%s' registered\n",
+ basefile, enc->name));
+ return enc;
+}
+
+DviEncoding *mdvi_request_encoding(const char *name)
+{
+ DviEncoding *enc = find_encoding(name);
+
+ if(enc == NULL) {
+ DEBUG((DBG_FMAP, "%s: encoding not found, returning default `%s'\n",
+ name, default_encoding->name));
+ return default_encoding;
+ }
+ /* we don't keep reference counts for this */
+ if(enc == tex_text_encoding)
+ return enc;
+ if(!enc->private && read_encoding(enc) < 0)
+ return NULL;
+ enc->links++;
+
+ /* if the hash table is empty, rebuild it */
+ if(enc->nametab.nkeys == 0) {
+ int i;
+
+ DEBUG((DBG_FMAP, "%s: rehashing\n", enc->name));
+ for(i = 0; i < 256; i++) {
+ if(enc->vector[i] == NULL)
+ continue;
+ mdvi_hash_add(&enc->nametab,
+ MDVI_KEY(enc->vector[i]),
+ (DviHashKey)Int2Ptr(i),
+ MDVI_HASH_REPLACE);
+ }
+ }
+ return enc;
+}
+
+void mdvi_release_encoding(DviEncoding *enc, int should_free)
+{
+ /* ignore our static encoding */
+ if(enc == tex_text_encoding)
+ return;
+ if(!enc->links || --enc->links > 0 || !should_free)
+ return;
+ DEBUG((DBG_FMAP, "%s: resetting encoding vector\n", enc->name));
+ mdvi_hash_reset(&enc->nametab, 1); /* we'll reuse it */
+}
+
+int mdvi_encode_glyph(DviEncoding *enc, const char *name)
+{
+ void *data;
+
+ data = mdvi_hash_lookup(&enc->nametab, MDVI_KEY(name));
+ if(data == NULL)
+ return -1;
+ /* we added +1 to the hashed index just to distinguish
+ * a failed lookup from a zero index. Adjust it now. */
+ return (Ptr2Int(data) - 1);
+}
+
+/****************
+ * Fontmaps *
+ ****************/
+
+static void parse_spec(DviFontMapEnt *ent, char *spec)
+{
+ char *arg, *command;
+
+ /* this is a ridiculously simple parser, and recognizes only
+ * things of the form <argument> <command>. Of these, only
+ * command=SlantFont, ExtendFont and ReEncodeFont are handled */
+ while(*spec) {
+ arg = getword(spec, " \t", &spec);
+ if(*spec) *spec++ = 0;
+ command = getword(spec, " \t", &spec);
+ if(*spec) *spec++ = 0;
+ if(!arg || !command)
+ continue;
+ if(STREQ(command, "SlantFont")) {
+ double x = 10000 * strtod(arg, 0);
+
+ /* SFROUND evaluates arguments twice */
+ ent->slant = SFROUND(x);
+ } else if(STREQ(command, "ExtendFont")) {
+ double x = 10000 * strtod(arg, 0);
+
+ ent->extend = SFROUND(x);
+ } else if(STREQ(command, "ReEncodeFont")) {
+ if(ent->encoding)
+ xfree(ent->encoding);
+ ent->encoding = xstrdup(arg);
+ }
+ }
+}
+
+#if 0
+static void print_ent(DviFontMapEnt *ent)
+{
+ printf("Entry for `%s':\n", ent->fontname);
+ printf(" PS name: %s\n", ent->psname ? ent->psname : "(none)");
+ printf(" Encoding: %s\n", ent->encoding ? ent->encoding : "(default)");
+ printf(" EncFile: %s\n", ent->encfile ? ent->encfile : "(none)");
+ printf(" FontFile: %s\n", ent->fontfile ? ent->fontfile : "(same)");
+ printf(" Extend: %ld\n", ent->extend);
+ printf(" Slant: %ld\n", ent->slant);
+}
+#endif
+
+DviFontMapEnt *mdvi_load_fontmap(const char *file)
+{
+ char *ptr;
+ FILE *in;
+ int lineno = 1;
+ Dstring input;
+ ListHead list;
+ DviFontMapEnt *ent;
+ DviEncoding *last_encoding;
+ char *last_encfile;
+
+ ptr = kpse_find_file(file, kpse_program_text_format, 0);
+ if(ptr == NULL)
+ ptr = kpse_find_file(file, kpse_tex_ps_header_format, 0);
+ if(ptr == NULL)
+ ptr = kpse_find_file(file, kpse_dvips_config_format, 0);
+ if(ptr == NULL)
+ in = fopen(file, "r");
+ else {
+ in = fopen(ptr, "r");
+ xfree(ptr);
+ }
+ if(in == NULL)
+ return NULL;
+
+ ent = NULL;
+ listh_init(&list);
+ dstring_init(&input);
+ last_encoding = NULL;
+ last_encfile = NULL;
+
+ while((ptr = dgets(&input, in)) != NULL) {
+ char *font_file;
+ char *tex_name;
+ char *ps_name;
+ char *vec_name;
+ int is_encoding;
+ DviEncoding *enc;
+
+ lineno++;
+ SKIPSP(ptr);
+
+ /* we skip what dvips does */
+ if(*ptr <= ' ' || *ptr == '*' || *ptr == '#' ||
+ *ptr == ';' || *ptr == '%')
+ continue;
+
+ font_file = NULL;
+ tex_name = NULL;
+ ps_name = NULL;
+ vec_name = NULL;
+ is_encoding = 0;
+
+ if(ent == NULL) {
+ ent = xalloc(DviFontMapEnt);
+ ent->encoding = NULL;
+ ent->slant = 0;
+ ent->extend = 0;
+ }
+ while(*ptr) {
+ char *hdr_name = NULL;
+
+ while(*ptr && *ptr <= ' ')
+ ptr++;
+ if(*ptr == 0)
+ break;
+ if(*ptr == '"') {
+ char *str;
+
+ str = getstring(ptr, " \t", &ptr);
+ if(*ptr) *ptr++ = 0;
+ parse_spec(ent, str);
+ continue;
+ } else if(*ptr == '<') {
+ ptr++;
+ if(*ptr == '<')
+ ptr++;
+ else if(*ptr == '[') {
+ is_encoding = 1;
+ ptr++;
+ }
+ SKIPSP(ptr);
+ hdr_name = ptr;
+ } else if(!tex_name)
+ tex_name = ptr;
+ else if(!ps_name)
+ ps_name = ptr;
+ else
+ hdr_name = ptr;
+
+ /* get next word */
+ getword(ptr, " \t", &ptr);
+ if(*ptr) *ptr++ = 0;
+
+ if(hdr_name) {
+ const char *ext = file_extension(hdr_name);
+
+ if(is_encoding || (ext && STRCEQ(ext, "enc")))
+ vec_name = hdr_name;
+ else
+ font_file = hdr_name;
+ }
+ }
+
+ if(tex_name == NULL)
+ continue;
+ ent->fontname = xstrdup(tex_name);
+ ent->psname = ps_name ? xstrdup(ps_name) : NULL;
+ ent->fontfile = font_file ? xstrdup(font_file) : NULL;
+ ent->encfile = vec_name ? xstrdup(vec_name) : NULL;
+ ent->fullfile = NULL;
+ enc = NULL; /* we don't have this yet */
+
+ /* if we have an encoding file, register it */
+ if(ent->encfile) {
+ /* register_encoding is smart enough not to load the
+ * same file twice */
+ if(!last_encfile || !STREQ(last_encfile, ent->encfile)) {
+ last_encfile = ent->encfile;
+ last_encoding = register_encoding(ent->encfile, 1);
+ }
+ enc = last_encoding;
+ }
+ if(ent->encfile && enc){
+ if(ent->encoding && !STREQ(ent->encoding, enc->name)) {
+ warning(
+ _("%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n"),
+ file, lineno);
+ } else if(!ent->encoding)
+ ent->encoding = xstrdup(enc->name);
+ }
+
+ /* add it to the list */
+ /*print_ent(ent);*/
+ listh_append(&list, LIST(ent));
+ ent = NULL;
+ }
+ dstring_reset(&input);
+ fclose(in);
+
+ return (DviFontMapEnt *)list.head;
+}
+
+static void free_ent(DviFontMapEnt *ent)
+{
+ ASSERT(ent->fontname != NULL);
+ xfree(ent->fontname);
+ if(ent->psname)
+ xfree(ent->psname);
+ if(ent->fontfile)
+ xfree(ent->fontfile);
+ if(ent->encoding)
+ xfree(ent->encoding);
+ if(ent->encfile)
+ xfree(ent->encfile);
+ if(ent->fullfile)
+ xfree(ent->fullfile);
+ xfree(ent);
+}
+
+void mdvi_install_fontmap(DviFontMapEnt *head)
+{
+ DviFontMapEnt *ent, *next;
+
+ for(ent = head; ent; ent = next) {
+ /* add all the entries, overriding old ones */
+ DviFontMapEnt *old;
+
+ old = (DviFontMapEnt *)
+ mdvi_hash_remove(&maptable, MDVI_KEY(ent->fontname));
+ if(old != NULL) {
+ DEBUG((DBG_FMAP, "%s: overriding fontmap entry\n",
+ old->fontname));
+ listh_remove(&fontmaps, LIST(old));
+ free_ent(old);
+ }
+ next = ent->next;
+ mdvi_hash_add(&maptable, MDVI_KEY(ent->fontname),
+ ent, MDVI_HASH_UNCHECKED);
+ listh_append(&fontmaps, LIST(ent));
+ }
+}
+
+static void init_static_encoding()
+{
+ DviEncoding *encoding;
+ int i;
+
+ DEBUG((DBG_FMAP, "installing static TeX text encoding\n"));
+ encoding = xalloc(DviEncoding);
+ encoding->private = "";
+ encoding->filename = "";
+ encoding->name = "TeXTextEncoding";
+ encoding->vector = tex_text_vector;
+ encoding->links = 1;
+ encoding->offset = 0;
+ mdvi_hash_create(&encoding->nametab, ENCNAME_HASH_SIZE);
+ for(i = 0; i < 256; i++) {
+ if(encoding->vector[i]) {
+ mdvi_hash_add(&encoding->nametab,
+ MDVI_KEY(encoding->vector[i]),
+ (DviHashKey)Int2Ptr(i),
+ MDVI_HASH_UNCHECKED);
+ }
+ }
+ ASSERT_VALUE(encodings.count, 0);
+ mdvi_hash_create(&enctable, ENC_HASH_SIZE);
+ mdvi_hash_create(&enctable_file, ENC_HASH_SIZE);
+ enctable_file.hash_free = file_hash_free;
+ mdvi_hash_add(&enctable, MDVI_KEY(encoding->name),
+ encoding, MDVI_HASH_UNCHECKED);
+ listh_prepend(&encodings, LIST(encoding));
+ tex_text_encoding = encoding;
+ default_encoding = tex_text_encoding;
+}
+
+int mdvi_set_default_encoding(const char *name)
+{
+ DviEncoding *enc, *old;
+
+ enc = find_encoding(name);
+ if(enc == NULL)
+ return -1;
+ if(enc == default_encoding)
+ return 0;
+ /* this will read it from file if necessary,
+ * but it can fail if the file is corrupted */
+ enc = mdvi_request_encoding(name);
+ if(enc == NULL)
+ return -1;
+ old = default_encoding;
+ default_encoding = enc;
+ if(old != tex_text_encoding)
+ mdvi_release_encoding(old, 1);
+ return 0;
+}
+
+int mdvi_init_fontmaps(void)
+{
+ char *file;
+ char *line;
+ FILE *in;
+ Dstring input;
+ int count = 0;
+ char *config;
+
+ if(fontmaps_loaded)
+ return 0;
+ /* we will only try this once */
+ fontmaps_loaded = 1;
+
+ DEBUG((DBG_FMAP, "reading fontmaps\n"));
+
+ /* make sure the static encoding is there */
+ init_static_encoding();
+
+ /* create the fontmap hash table */
+ mdvi_hash_create(&maptable, MAP_HASH_SIZE);
+
+ /* get the name of our configuration file */
+ config = kpse_cnf_get("mdvi-config");
+ if(config == NULL)
+ config = MDVI_DEFAULT_CONFIG;
+ /* let's ask kpathsea for the file first */
+ file = kpse_find_file(config, kpse_program_text_format, 0);
+ if(file == NULL)
+ in = fopen(config, "r");
+ else {
+ in = fopen(file, "r");
+ xfree(file);
+ }
+ if(in == NULL)
+ return -1;
+ dstring_init(&input);
+ while((line = dgets(&input, in)) != NULL) {
+ char *arg;
+
+ SKIPSP(line);
+ if(*line < ' ' || *line == '#' || *line == '%')
+ continue;
+ if(STRNEQ(line, "fontmap", 7)) {
+ DviFontMapEnt *ent;
+
+ arg = getstring(line + 7, " \t", &line); *line = 0;
+ DEBUG((DBG_FMAP, "%s: loading fontmap\n", arg));
+ ent = mdvi_load_fontmap(arg);
+ if(ent == NULL)
+ warning(_("%s: could not load fontmap\n"), arg);
+ else {
+ DEBUG((DBG_FMAP,
+ "%s: installing fontmap\n", arg));
+ mdvi_install_fontmap(ent);
+ count++;
+ }
+ } else if(STRNEQ(line, "encoding", 8)) {
+ arg = getstring(line + 8, " \t", &line); *line = 0;
+ if(arg && *arg)
+ register_encoding(arg, 1);
+ } else if(STRNEQ(line, "default-encoding", 16)) {
+ arg = getstring(line + 16, " \t", &line); *line = 0;
+ if(mdvi_set_default_encoding(arg) < 0)
+ warning(_("%s: could not set as default encoding\n"),
+ arg);
+ } else if(STRNEQ(line, "psfontpath", 10)) {
+ arg = getstring(line + 11, " \t", &line); *line = 0;
+ if(!psinitialized)
+ ps_init_default_paths();
+ if(psfontdir)
+ xfree(psfontdir);
+ psfontdir = kpse_path_expand(arg);
+ } else if(STRNEQ(line, "pslibpath", 9)) {
+ arg = getstring(line + 10, " \t", &line); *line = 0;
+ if(!psinitialized)
+ ps_init_default_paths();
+ if(pslibdir)
+ xfree(pslibdir);
+ pslibdir = kpse_path_expand(arg);
+ } else if(STRNEQ(line, "psfontmap", 9)) {
+ arg = getstring(line + 9, " \t", &line); *line = 0;
+ if(mdvi_ps_read_fontmap(arg) < 0)
+ warning("%s: %s: could not read PS fontmap\n",
+ config, arg);
+ }
+ }
+ fclose(in);
+ dstring_reset(&input);
+ fontmaps_loaded = 1;
+ DEBUG((DBG_FMAP, "%d files installed, %d fontmaps\n",
+ count, fontmaps.count));
+ return count;
+}
+
+int mdvi_query_fontmap(DviFontMapInfo *info, const char *fontname)
+{
+ DviFontMapEnt *ent;
+
+ if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
+ return -1;
+ ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(fontname));
+
+ if(ent == NULL)
+ return -1;
+ info->psname = ent->psname;
+ info->encoding = ent->encoding;
+ info->fontfile = ent->fontfile;
+ info->extend = ent->extend;
+ info->slant = ent->slant;
+ info->fullfile = ent->fullfile;
+
+ return 0;
+}
+
+int mdvi_add_fontmap_file(const char *name, const char *fullpath)
+{
+ DviFontMapEnt *ent;
+
+ if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
+ return -1;
+ ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(name));
+ if(ent == NULL)
+ return -1;
+ if(ent->fullfile)
+ xfree(ent->fullfile);
+ ent->fullfile = xstrdup(fullpath);
+ return 0;
+}
+
+
+void mdvi_flush_encodings(void)
+{
+ DviEncoding *enc;
+
+ if(enctable.nbucks == 0)
+ return;
+
+ DEBUG((DBG_FMAP, "flushing %d encodings\n", encodings.count));
+ /* asked to remove all encodings */
+ for(; (enc = (DviEncoding *)encodings.head); ) {
+ encodings.head = LIST(enc->next);
+ if((enc != tex_text_encoding && enc->links) || enc->links > 1) {
+ warning(_("encoding vector `%s' is in use\n"),
+ enc->name);
+ }
+ destroy_encoding(enc);
+ }
+ /* destroy the static encoding */
+ if(tex_text_encoding->nametab.buckets)
+ mdvi_hash_reset(&tex_text_encoding->nametab, 0);
+ mdvi_hash_reset(&enctable, 0);
+ mdvi_hash_reset(&enctable_file, 0);
+}
+
+void mdvi_flush_fontmaps(void)
+{
+ DviFontMapEnt *ent;
+
+ if(!fontmaps_loaded)
+ return;
+
+ DEBUG((DBG_FMAP, "flushing %d fontmaps\n", fontmaps.count));
+ for(; (ent = (DviFontMapEnt *)fontmaps.head); ) {
+ fontmaps.head = LIST(ent->next);
+ free_ent(ent);
+ }
+ mdvi_hash_reset(&maptable, 0);
+ fontmaps_loaded = 0;
+}
+
+/* reading of PS fontmaps */
+
+void ps_init_default_paths(void)
+{
+ char *kppath = mdvi_getenv("MDVI_PS_LIBPATH");
+ char *kfpath = mdvi_getenv("MDVI_PS_FONTPATH");
+
+ ASSERT(psinitialized == 0);
+ if(kppath == NULL)
+ kppath = getenv("GS_LIB");
+ if(kfpath == NULL)
+ kfpath = getenv("GS_FONTPATH");
+ if(kppath != NULL)
+ pslibdir = kpse_path_expand(kppath);
+ if(kfpath != NULL)
+ psfontdir = kpse_path_expand(kfpath);
+ listh_init(&psfonts);
+ mdvi_hash_create(&pstable, PSMAP_HASH_SIZE);
+ psinitialized = 1;
+}
+
+int mdvi_ps_read_fontmap(const char *name)
+{
+ char *fullname;
+ FILE *in;
+ Dstring dstr;
+ char *line;
+ int count = 0;
+
+ if(!psinitialized)
+ ps_init_default_paths();
+ if(pslibdir)
+ fullname = kpse_path_search(pslibdir, name, 1);
+ else
+ fullname = (char *)name;
+ in = fopen(fullname, "r");
+ if(in == NULL) {
+ if(fullname != name)
+ xfree(fullname);
+ return -1;
+ }
+ dstring_init(&dstr);
+
+ while((line = dgets(&dstr, in)) != NULL) {
+ char *name;
+ char *mapname;
+ const char *ext;
+ PSFontMap *ps;
+
+ SKIPSP(line);
+ /* we're looking for lines of the form
+ * /FONT-NAME (fontfile)
+ * /FONT-NAME /FONT-ALIAS
+ */
+ if(*line != '/')
+ continue;
+ name = getword(line + 1, " \t", &line);
+ if(*line) *line++ = 0;
+ mapname = getword(line, " \t", &line);
+ if(*line) *line++ = 0;
+
+ if(!name || !mapname || !*name)
+ continue;
+ if(*mapname == '(') {
+ char *end;
+
+ mapname++;
+ for(end = mapname; *end && *end != ')'; end++);
+ *end = 0;
+ }
+ if(!*mapname)
+ continue;
+ /* dont add `.gsf' fonts, which require a full blown
+ * PostScript interpreter */
+ ext = file_extension(mapname);
+ if(ext && STREQ(ext, "gsf")) {
+ DEBUG((DBG_FMAP, "(ps) %s: font `%s' ignored\n",
+ name, mapname));
+ continue;
+ }
+ ps = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(name));
+ if(ps != NULL) {
+ if(STREQ(ps->mapname, mapname))
+ continue;
+ DEBUG((DBG_FMAP,
+ "(ps) replacing font `%s' (%s) by `%s'\n",
+ name, ps->mapname, mapname));
+ xfree(ps->mapname);
+ ps->mapname = xstrdup(mapname);
+ if(ps->fullname) {
+ xfree(ps->fullname);
+ ps->fullname = NULL;
+ }
+ } else {
+ DEBUG((DBG_FMAP, "(ps) adding font `%s' as `%s'\n",
+ name, mapname));
+ ps = xalloc(PSFontMap);
+ ps->psname = xstrdup(name);
+ ps->mapname = xstrdup(mapname);
+ ps->fullname = NULL;
+ listh_append(&psfonts, LIST(ps));
+ mdvi_hash_add(&pstable, MDVI_KEY(ps->psname),
+ ps, MDVI_HASH_UNCHECKED);
+ count++;
+ }
+ }
+ fclose(in);
+ dstring_reset(&dstr);
+
+ DEBUG((DBG_FMAP, "(ps) %s: %d PostScript fonts registered\n",
+ fullname, count));
+ return 0;
+}
+
+void mdvi_ps_flush_fonts(void)
+{
+ PSFontMap *map;
+
+ if(!psinitialized)
+ return;
+ DEBUG((DBG_FMAP, "(ps) flushing PS font map (%d) entries\n",
+ psfonts.count));
+ mdvi_hash_reset(&pstable, 0);
+ for(; (map = (PSFontMap *)psfonts.head); ) {
+ psfonts.head = LIST(map->next);
+ xfree(map->psname);
+ xfree(map->mapname);
+ if(map->fullname)
+ xfree(map->fullname);
+ xfree(map);
+ }
+ listh_init(&psfonts);
+ if(pslibdir) {
+ xfree(pslibdir);
+ pslibdir = NULL;
+ }
+ if(psfontdir) {
+ xfree(psfontdir);
+ psfontdir = NULL;
+ }
+ psinitialized = 0;
+}
+
+char *mdvi_ps_find_font(const char *psname)
+{
+ PSFontMap *map, *smap;
+ char *filename;
+ int recursion_limit = 32;
+
+ DEBUG((DBG_FMAP, "(ps) resolving PS font `%s'\n", psname));
+ if(!psinitialized)
+ return NULL;
+ map = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(psname));
+ if(map == NULL)
+ return NULL;
+ if(map->fullname)
+ return xstrdup(map->fullname);
+
+ /* is it an alias? */
+ smap = map;
+ while(recursion_limit-- > 0 && smap && *smap->mapname == '/')
+ smap = (PSFontMap *)mdvi_hash_lookup(&pstable,
+ MDVI_KEY(smap->mapname + 1));
+ if(smap == NULL) {
+ if(recursion_limit == 0)
+ DEBUG((DBG_FMAP,
+ "(ps) %s: possible loop in PS font map\n",
+ psname));
+ return NULL;
+ }
+
+ if(psfontdir)
+ filename = kpse_path_search(psfontdir, smap->mapname, 1);
+ else if(file_exists(map->mapname))
+ filename = xstrdup(map->mapname);
+ else
+ filename = NULL;
+ if(filename)
+ map->fullname = xstrdup(filename);
+
+ return filename;
+}
+
+/*
+ * To get metric info for a font, we proceed as follows:
+ * - We try to find NAME.<tfm,ofm,afm>.
+ * - We query the fontmap for NAME.
+ * - We get back a PSNAME, and use to find the file in the PS font map.
+ * - We get the PSFONT file name, replace its extension by "afm" and
+ * lookup the file in GS's font search path.
+ * - We finally read the data, transform it as specified in our font map,
+ * and return it to the caller. The new data is left in the font metrics
+ * cache, so the next time it will be found at the first step (when we look
+ * up NAME.afm).
+ *
+ * The name `_ps_' in this function is not meant to imply that it can be
+ * used for Type1 fonts only. It should be usable for TrueType fonts as well.
+ *
+ * The returned metric info is subjected to the same caching mechanism as
+ * all the other metric data, as returned by get_font_metrics(). One should
+ * not modify the returned data at all, and it should be disposed with
+ * free_font_metrics().
+ */
+TFMInfo *mdvi_ps_get_metrics(const char *fontname)
+{
+ TFMInfo *info;
+ DviFontMapInfo map;
+ char buffer[64]; /* to avoid mallocs */
+ char *psfont;
+ char *basefile;
+ char *afmfile;
+ char *ext;
+ int baselen;
+ int nc;
+ TFMChar *ch;
+ double efactor;
+ double sfactor;
+
+ DEBUG((DBG_FMAP, "(ps) %s: looking for metric data\n", fontname));
+ info = get_font_metrics(fontname, DviFontAny, NULL);
+ if(info != NULL)
+ return info;
+
+ /* query the fontmap */
+ if(mdvi_query_fontmap(&map, fontname) < 0 || !map.psname)
+ return NULL;
+
+ /* get the PS font */
+ psfont = mdvi_ps_find_font(map.psname);
+ if(psfont == NULL)
+ return NULL;
+ DEBUG((DBG_FMAP, "(ps) %s: found as PS font `%s'\n",
+ fontname, psfont));
+ /* replace its extension */
+ basefile = strrchr(psfont, '/');
+ if(basefile == NULL)
+ basefile = psfont;
+ baselen = strlen(basefile);
+ ext = strrchr(basefile, '.');
+ if(ext != NULL)
+ *ext = 0;
+ if(baselen + 4 < 64)
+ afmfile = &buffer[0];
+ else
+ afmfile = xmalloc(baselen + 5);
+ strcpy(afmfile, basefile);
+ strcpy(afmfile + baselen, ".afm");
+ /* we don't need this anymore */
+ xfree(psfont);
+ DEBUG((DBG_FMAP, "(ps) %s: looking for `%s'\n",
+ fontname, afmfile));
+ /* lookup the file */
+ psfont = kpse_path_search(psfontdir, afmfile, 1);
+ /* don't need this anymore */
+ if(afmfile != &buffer[0])
+ xfree(afmfile);
+ if(psfont != NULL) {
+ info = get_font_metrics(fontname, DviFontAFM, psfont);
+ xfree(psfont);
+ } else
+ info = NULL;
+ if(info == NULL || (!map.extend && !map.slant))
+ return info;
+
+ /*
+ * transform the data as prescribed -- keep in mind that `info'
+ * points to CACHED data, so we're modifying the metric cache
+ * in place.
+ */
+
+#define DROUND(x) ((x) >= 0 ? floor((x) + 0.5) : ceil((x) - 0.5))
+#define TRANSFORM(x,y) DROUND(efactor * (x) + sfactor * (y))
+
+ efactor = (double)map.extend / 10000.0;
+ sfactor = (double)map.slant / 10000.0;
+ DEBUG((DBG_FMAP, "(ps) %s: applying extend=%f, slant=%f\n",
+ efactor, sfactor));
+
+ nc = info->hic - info->loc + 1;
+ for(ch = info->chars; ch < info->chars + nc; ch++) {
+ /* the AFM bounding box is:
+ * wx = ch->advance
+ * llx = ch->left
+ * lly = -ch->depth
+ * urx = ch->right
+ * ury = ch->height
+ * what we do here is transform wx, llx, and urx by
+ * newX = efactor * oldX + sfactor * oldY
+ * where for `wx' oldY = 0. Also, these numbers are all in
+ * TFM units (i.e. TFM's fix-words, which is just the actual
+ * number times 2^20, no need to do anything to it).
+ */
+ if(ch->present) {
+ ch->advance = TRANSFORM(ch->advance, 0);
+ ch->left = TRANSFORM(ch->left, -ch->depth);
+ ch->right = TRANSFORM(ch->right, ch->height);
+ }
+ }
+
+ return info;
+}
diff --git a/dviware/mdvi/lib/fontsrch.c b/dviware/mdvi/lib/fontsrch.c
new file mode 100644
index 0000000000..f7d4a45a9b
--- /dev/null
+++ b/dviware/mdvi/lib/fontsrch.c
@@ -0,0 +1,370 @@
+/* fontsearch.c -- implements the font lookup mechanism in MDVI */
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * How this works:
+ * Fonts are divided into MAX_CLASS priority classes. The first
+ * MAX_CLASS-1 ones correspond to `real' fonts (pk, gf, vf, type1, truetype,
+ * etc). The last one corresponds to `metric' fonts that are used as a last
+ * resort (tfm, afm, ofm, ...). When a font is looked up, it is tried in a
+ * `high' priority class (0 being the highest priority). The priority is
+ * lowered until it reaches MAX_CLASS-1. Then the whole thing is repeated
+ * for the fallback font. When the search reaches MAX_CLASS-1, we lookup the
+ * original font, and then the fallback font. The search can be done
+ * incrementally, with several calls to mdvi_lookup_font(). If this function
+ * is called again to continue a search, the function assumes the previous
+ * font it returned was not valid, and it goes on to the next step.
+ *
+ * Reason for this:
+ * Some font types are quite expensive to load (e.g. Type1), so loading
+ * them is deferred until the last possible moment. This means that a font that
+ * was supposed to exist may have to be discarded. Until now, MDVI had no ability to
+ * "resume" a search, so in this case it would have produced an error, regardless
+ * of whether the offending font existed in other formats.
+ * Also, given the large number of font types supported by MDVI, some mechanism
+ * was necessary to bring some order into the chaos.
+ *
+ * This mechanism fixes these two problems. For the first one, a search can
+ * be "resumed" and all the font formats tried for the missing font, and
+ * again for the fallback font (see above). As for the second, the
+ * hierarchical division in classes gives a lot of flexibility in how the
+ * fonts are configured.
+ */
+
+#include "mdvi.h"
+
+#define HAVE_PROTOTYPES 1
+#include <kpathsea/tex-file.h>
+#include <kpathsea/tex-glyph.h>
+
+struct _DviFontClass {
+ DviFontClass *next;
+ DviFontClass *prev;
+ DviFontInfo info;
+ int links;
+ int id;
+};
+
+extern char *_mdvi_fallback_font;
+
+/* this leaves classes 0 and 1 for `real' fonts */
+#define MAX_CLASS 3
+static ListHead font_classes[MAX_CLASS];
+static int initialized = 0;
+
+static void init_font_classes(void)
+{
+ int i;
+
+ for(i = 0; i < MAX_CLASS; i++)
+ listh_init(&font_classes[i]);
+ initialized = 1;
+}
+
+int mdvi_get_font_classes(void)
+{
+ return (MAX_CLASS - 2);
+}
+
+char **mdvi_list_font_class(int klass)
+{
+ char **list;
+ int i, n;
+ DviFontClass *fc;
+
+ if(klass == -1)
+ klass = MAX_CLASS-1;
+ if(klass < 0 || klass >= MAX_CLASS)
+ return NULL;
+ n = font_classes[klass].count;
+ list = xnalloc(char *, n + 1);
+ fc = (DviFontClass *)font_classes[klass].head;
+ for(i = 0; i < n; fc = fc->next, i++) {
+ list[i] = xstrdup(fc->info.name);
+ }
+ list[i] = NULL;
+ return list;
+}
+
+int mdvi_register_font_type(DviFontInfo *info, int klass)
+{
+ DviFontClass *fc;
+
+ if(klass == -1)
+ klass = MAX_CLASS-1;
+ if(klass < 0 || klass >= MAX_CLASS)
+ return -1;
+ if(!initialized)
+ init_font_classes();
+ fc = xalloc(struct _DviFontClass);
+ fc->links = 0;
+ fc->id = klass;
+ fc->info.name = xstrdup(info->name);
+ fc->info.scalable = info->scalable;
+ fc->info.load = info->load;
+ fc->info.getglyph = info->getglyph;
+ fc->info.shrink0 = info->shrink0;
+ fc->info.shrink1 = info->shrink1;
+ fc->info.freedata = info->freedata;
+ fc->info.reset = info->reset;
+ fc->info.lookup = info->lookup;
+ fc->info.kpse_type = info->kpse_type;
+ listh_append(&font_classes[klass], LIST(fc));
+ return 0;
+}
+
+int mdvi_unregister_font_type(const char *name, int klass)
+{
+ DviFontClass *fc;
+ int k;
+
+ if(klass == -1)
+ klass = MAX_CLASS - 1;
+
+ if(klass >= 0 && klass < MAX_CLASS) {
+ k = klass;
+ LIST_FOREACH(fc, DviFontClass, &font_classes[k]) {
+ if(STREQ(fc->info.name, name))
+ break;
+ }
+ } else if(klass < 0) {
+ for(k = 0; k < MAX_CLASS; k++) {
+ LIST_FOREACH(fc, DviFontClass, &font_classes[k]) {
+ if(STREQ(fc->info.name, name))
+ break;
+ }
+ if(fc) break;
+ }
+ } else
+ return -1;
+
+ if(fc == NULL || fc->links)
+ return -1;
+ /* remove it */
+ listh_remove(&font_classes[k], LIST(fc));
+
+ /* and destroy it */
+ xfree(fc->info.name);
+ xfree(fc);
+ return 0;
+}
+
+static char *lookup_font(DviFontClass *ptr, const char *name, Ushort *h, Ushort *v)
+{
+ char *filename;
+
+ /*
+ * If the font type registered a function to do the lookup, use that.
+ * Otherwise we use kpathsea.
+ */
+ if(ptr->info.lookup)
+ filename = ptr->info.lookup(name, h, v);
+ else if(ptr->info.kpse_type <= kpse_any_glyph_format) {
+ kpse_glyph_file_type type;
+
+ filename = kpse_find_glyph(name, Max(*h, *v),
+ ptr->info.kpse_type, &type);
+ /* if kpathsea returned a fallback font, reject it */
+ if(filename && type.source == kpse_glyph_source_fallback) {
+ xfree(filename);
+ filename = NULL;
+ } else if(filename)
+ *h = *v = type.dpi;
+ } else
+ filename = kpse_find_file(name, ptr->info.kpse_type, 1);
+ return filename;
+}
+
+/*
+ * Class MAX_CLASS-1 is special: it consists of `metric' fonts that should
+ * be tried as a last resort
+ */
+char *mdvi_lookup_font(DviFontSearch *search)
+{
+ int kid;
+ int k;
+ DviFontClass *ptr;
+ DviFontClass *last;
+ char *filename = NULL;
+ const char *name;
+ Ushort hdpi, vdpi;
+
+ if(search->id < 0)
+ return NULL;
+
+ if(search->curr == NULL) {
+ /* this is the initial search */
+ name = search->wanted_name;
+ hdpi = search->hdpi;
+ vdpi = search->vdpi;
+ kid = 0;
+ last = NULL;
+ } else {
+ name = search->actual_name;
+ hdpi = search->actual_hdpi;
+ vdpi = search->actual_vdpi;
+ kid = search->id;
+ last = search->curr;
+ }
+
+ ptr = NULL;
+again:
+ /* try all classes except MAX_CLASS-1 */
+ for(k = kid; !filename && k < MAX_CLASS-1; k++) {
+ if(last == NULL)
+ ptr = (DviFontClass *)font_classes[k].head;
+ else
+ ptr = last->next;
+ while(ptr) {
+ DEBUG((DBG_FONTS, "%d: trying `%s' at (%d,%d)dpi as `%s'\n",
+ k, name, hdpi, vdpi, ptr->info.name));
+ /* lookup the font in this class */
+ filename = lookup_font(ptr, name, &hdpi, &vdpi);
+ if(filename)
+ break;
+ ptr = ptr->next;
+ }
+ last = NULL;
+ }
+ if(filename != NULL) {
+ search->id = k-1;
+ search->curr = ptr;
+ search->actual_name = name;
+ search->actual_hdpi = hdpi;
+ search->actual_vdpi = vdpi;
+ search->info = &ptr->info;
+ ptr->links++;
+ return filename;
+ }
+
+ if(kid < MAX_CLASS - 1 && !STREQ(name, _mdvi_fallback_font)) {
+ warning("font `%s' at %dx%d not found, trying `%s' instead\n",
+ name, hdpi, vdpi, _mdvi_fallback_font);
+ name = _mdvi_fallback_font;
+ kid = 0;
+ goto again;
+ }
+
+ /* we tried the fallback font, and all the `real' classes. Let's
+ * try the `metric' class now */
+ name = search->wanted_name;
+ hdpi = search->hdpi;
+ vdpi = search->vdpi;
+ if(kid == MAX_CLASS-1) {
+ /* we were looking into this class from the beginning */
+ if(last == NULL) {
+ /* no more fonts to try */
+ return NULL;
+ }
+ ptr = last->next;
+ } else {
+ warning("font `%s' not found, trying metric files instead\n",
+ name);
+ ptr = (DviFontClass *)font_classes[MAX_CLASS-1].head;
+ }
+
+metrics:
+ while(ptr) {
+ DEBUG((DBG_FONTS, "metric: trying `%s' at (%d,%d)dpi as `%s'\n",
+ name, hdpi, vdpi, ptr->info.name));
+ filename = lookup_font(ptr, name, &hdpi, &vdpi);
+ if(filename)
+ break;
+ ptr = ptr->next;
+ }
+ if(filename != NULL) {
+ if(STREQ(name, _mdvi_fallback_font))
+ search->id = MAX_CLASS;
+ else
+ search->id = MAX_CLASS - 1;
+ search->curr = ptr;
+ search->actual_name = name;
+ search->actual_hdpi = hdpi;
+ search->actual_vdpi = vdpi;
+ search->info = &ptr->info;
+ ptr->links++;
+ return filename;
+ }
+ if(!STREQ(name, _mdvi_fallback_font)) {
+ warning("metric file for `%s' not found, trying `%s' instead\n",
+ name, _mdvi_fallback_font);
+ name = _mdvi_fallback_font;
+ ptr = (DviFontClass *)font_classes[MAX_CLASS-1].head;
+ goto metrics;
+ }
+
+ search->id = -1;
+ search->actual_name = NULL;
+
+ /* tough luck, nothing found */
+ return NULL;
+}
+
+/* called by `font_reference' to do the initial lookup */
+DviFont *mdvi_add_font(const char *name, Int32 sum,
+ int hdpi, int vdpi, Int32 scale)
+{
+ DviFont *font;
+
+ font = xalloc(DviFont);
+ font->fontname = xstrdup(name);
+ SEARCH_INIT(font->search, font->fontname, hdpi, vdpi);
+ font->filename = mdvi_lookup_font(&font->search);
+ if(font->filename == NULL) {
+ /* this answer is final */
+ xfree(font->fontname);
+ xfree(font);
+ return NULL;
+ }
+ font->hdpi = font->search.actual_hdpi;
+ font->vdpi = font->search.actual_vdpi;
+ font->scale = scale;
+ font->design = 0;
+ font->checksum = sum;
+ font->type = 0;
+ font->links = 0;
+ font->loc = 0;
+ font->hic = 0;
+ font->in = NULL;
+ font->chars = NULL;
+ font->subfonts = NULL;
+
+ return font;
+}
+
+int mdvi_font_retry(DviParams *params, DviFont *font)
+{
+ /* try the search again */
+ char *filename;
+
+ ASSERT(font->search.curr != NULL);
+ /* we won't be using this class anymore */
+ font->search.curr->links--;
+
+ filename = mdvi_lookup_font(&font->search);
+ if(filename == NULL)
+ return -1;
+ xfree(font->filename);
+ font->filename = filename;
+ /* copy the new information */
+ font->hdpi = font->search.actual_hdpi;
+ font->vdpi = font->search.actual_vdpi;
+
+ return 0;
+}
diff --git a/dviware/mdvi/lib/gf.c b/dviware/mdvi/lib/gf.c
new file mode 100644
index 0000000000..459e428ece
--- /dev/null
+++ b/dviware/mdvi/lib/gf.c
@@ -0,0 +1,394 @@
+/* gf.c - GF font support */
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* functions to read GF fonts */
+
+#include <string.h>
+#include "common.h"
+#include "mdvi.h"
+#include "private.h"
+
+/* opcodes */
+
+#define GF_PAINT0 0
+#define GF_PAINT1 64
+#define GF_PAINT2 65
+#define GF_PAINT3 66
+#define GF_BOC 67
+#define GF_BOC1 68
+#define GF_EOC 69
+#define GF_SKIP0 70
+#define GF_SKIP1 71
+#define GF_SKIP2 72
+#define GF_SKIP3 73
+#define GF_NEW_ROW_0 74
+#define GF_NEW_ROW_1 75
+#define GF_NEW_ROW_MAX 238
+#define GF_XXX1 239
+#define GF_XXX2 240
+#define GF_XXX3 241
+#define GF_XXX4 242
+#define GF_YYY 243
+#define GF_NOOP 244
+#define GF_LOC 245
+#define GF_LOC0 246
+#define GF_PRE 247
+#define GF_POST 248
+#define GF_POST_POST 249
+
+#define GF_ID 131
+#define GF_TRAILER 223
+
+#define BLACK 1
+#define WHITE 0
+
+static int gf_load_font __PROTO((DviParams *, DviFont *));
+static int gf_font_get_glyph __PROTO((DviParams *, DviFont *, int));
+
+/* only symbol exported by this file */
+DviFontInfo gf_font_info = {
+ "GF",
+ 0, /* scaling not supported natively */
+ gf_load_font,
+ gf_font_get_glyph,
+ mdvi_shrink_glyph,
+ mdvi_shrink_glyph_grey,
+ NULL, /* free */
+ NULL, /* reset */
+ NULL, /* lookup */
+ kpse_gf_format,
+ NULL
+};
+
+static int gf_read_bitmap(FILE *p, DviFontChar *ch)
+{
+ int op;
+ int min_n, max_n;
+ int min_m, max_m;
+ int paint_switch;
+ int x, y;
+ int bpl;
+ Int32 par;
+ BmUnit *line;
+ BITMAP *map;
+
+ fseek(p, (long)ch->offset, SEEK_SET);
+ op = fuget1(p);
+ if(op == GF_BOC) {
+ /* skip character code */
+ fuget4(p);
+ /* skip pointer */
+ fuget4(p);
+ min_m = fsget4(p);
+ max_m = fsget4(p);
+ min_n = fsget4(p);
+ max_n = fsget4(p);
+ } else if(op == GF_BOC1) {
+ /* skip character code */
+ fuget1(p);
+ min_m = fuget1(p); /* this is max_m - min_m */
+ max_m = fuget1(p);
+ min_n = fuget1(p); /* this is max_n - min_n */
+ max_n = fuget1(p);
+ min_m = max_m - min_m;
+ min_n = max_n - min_n;
+ } else {
+ error(_("GF: invalid opcode %d in character %d\n"),
+ op, ch->code);
+ return -1;
+ }
+
+ ch->x = -min_m;
+ ch->y = max_n;
+ ch->width = max_m - min_m + 1;
+ ch->height = max_n - min_n + 1;
+ map = bitmap_alloc(ch->width, ch->height);
+
+ ch->glyph.data = map;
+ ch->glyph.x = ch->x;
+ ch->glyph.y = ch->y;
+ ch->glyph.w = ch->width;
+ ch->glyph.h = ch->height;
+
+#define COLOR(x) ((x) ? "BLACK" : "WHITE")
+
+ paint_switch = WHITE;
+ x = y = 0;
+ line = map->data;
+ bpl = map->stride;
+ DEBUG((DBG_BITMAPS, "(gf) reading character %d\n", ch->code));
+ while((op = fuget1(p)) != GF_EOC) {
+ Int32 n;
+
+ if(feof(p))
+ break;
+ if(op == GF_PAINT0) {
+ DEBUG((DBG_BITMAPS, "(gf) Paint0 %s -> %s\n",
+ COLOR(paint_switch), COLOR(!paint_switch)));
+ paint_switch = !paint_switch;
+ } else if(op <= GF_PAINT3) {
+ if(op < GF_PAINT1)
+ par = op;
+ else
+ par = fugetn(p, op - GF_PAINT1 + 1);
+ if(y >= ch->height || x + par >= ch->width)
+ goto toobig;
+ /* paint everything between columns x and x + par - 1 */
+ DEBUG((DBG_BITMAPS, "(gf) Paint %d %s from (%d,%d)\n",
+ par, COLOR(paint_switch), x, y));
+ if(paint_switch == BLACK)
+ bitmap_paint_bits(line + (x / BITMAP_BITS),
+ x % BITMAP_BITS, par);
+ paint_switch = !paint_switch;
+ x += par;
+ } else if(op >= GF_NEW_ROW_0 && op <= GF_NEW_ROW_MAX) {
+ y++;
+ line = bm_offset(line, bpl);
+ x = op - GF_NEW_ROW_0;
+ paint_switch = BLACK;
+ DEBUG((DBG_BITMAPS, "(gf) new_row_%d\n", x));
+ } else switch(op) {
+ case GF_SKIP0:
+ y++;
+ line = bm_offset(line, bpl);
+ x = 0;
+ paint_switch = WHITE;
+ DEBUG((DBG_BITMAPS, "(gf) skip_0\n"));
+ break;
+ case GF_SKIP1:
+ case GF_SKIP2:
+ case GF_SKIP3:
+ par = fugetn(p, op - GF_SKIP1 + 1);
+ y += par + 1;
+ line = bm_offset(line, (par + 1) * bpl);
+ x = 0;
+ paint_switch = WHITE;
+ DEBUG((DBG_BITMAPS, "(gf) skip_%d\n", op - GF_SKIP1));
+ break;
+ case GF_XXX1:
+ case GF_XXX2:
+ case GF_XXX3:
+ case GF_XXX4: {
+#ifndef NODEBUG
+ char *s;
+
+ s = read_string(p, op - GF_XXX1 + 1, NULL, 0);
+ DEBUG((DBG_SPECIAL, "(gf) Character %d: Special \"%s\"\n",
+ ch->code, s));
+ xfree(s);
+#else
+ n = fugetn(p, op - GF_XXX1 + 1);
+ fseek(p, (long)n, SEEK_CUR);
+#endif
+ break;
+ }
+ case GF_YYY:
+ n = fuget4(p);
+ DEBUG((DBG_SPECIAL, "(gf) Character %d: MF special %u\n",
+ ch->code, n));
+ break;
+ case GF_NOOP:
+ DEBUG((DBG_BITMAPS, "(gf) no_op\n"));
+ break;
+ default:
+ error(_("(gf) Character %d: invalid opcode %d\n"),
+ ch->code, op);
+ goto error;
+ }
+ /* chech that we're still inside the bitmap */
+ if(x > ch->width || y > ch->height)
+ goto toobig;
+ DEBUG((DBG_BITMAPS, "(gf) curr_loc @ (%d,%d)\n", x, y));
+ }
+
+ if(op != GF_EOC)
+ goto error;
+ DEBUG((DBG_BITMAPS, "(gf) end of character %d\n", ch->code));
+ return 0;
+
+toobig:
+ error(_("(gf) character %d has an incorrect bounding box\n"),
+ ch->code);
+error:
+ bitmap_destroy(map);
+ ch->glyph.data = NULL;
+ return -1;
+}
+
+static int gf_load_font(DviParams *unused, DviFont *font)
+{
+ int i;
+ int n;
+ int loc;
+ int hic;
+ FILE *p;
+ Int32 word;
+ int op;
+ long alpha, beta, z;
+#ifndef NODEBUG
+ char s[256];
+#endif
+
+ p = font->in;
+
+ /* check preamble */
+ loc = fuget1(p); hic = fuget1(p);
+ if(loc != GF_PRE || hic != GF_ID)
+ goto badgf;
+ loc = fuget1(p);
+#ifndef NODEBUG
+ for(i = 0; i < loc; i++)
+ s[i] = fuget1(p);
+ s[i] = 0;
+ DEBUG((DBG_FONTS, "(gf) %s: %s\n", font->fontname, s));
+#else
+ fseek(p, (long)loc, SEEK_CUR);
+#endif
+ /* now read character locators in postamble */
+ if(fseek(p, (long)-1, SEEK_END) == -1)
+ return -1;
+
+ n = 0;
+ while((op = fuget1(p)) == GF_TRAILER) {
+ if(fseek(p, (long)-2, SEEK_CUR) < 0)
+ break;
+ n++;
+ }
+ if(op != GF_ID || n < 4)
+ goto badgf;
+ /* get the pointer to the postamble */
+ fseek(p, (long)-5, SEEK_CUR);
+ op = fuget4(p);
+ /* jump to it */
+ fseek(p, (long)op, SEEK_SET);
+ if(fuget1(p) != GF_POST)
+ goto badgf;
+ /* skip pointer to last EOC */
+ fuget4(p);
+ /* get the design size */
+ font->design = fuget4(p);
+ /* the checksum */
+ word = fuget4(p);
+ if(word && font->checksum && font->checksum != word) {
+ warning(_("%s: bad checksum (expected %u, found %u)\n"),
+ font->fontname, font->checksum, word);
+ } else if(!font->checksum)
+ font->checksum = word;
+ /* skip pixels per point ratio */
+ fuget4(p);
+ fuget4(p);
+ font->chars = xnalloc(DviFontChar, 256);
+ for(loc = 0; loc < 256; loc++)
+ font->chars[loc].offset = 0;
+ /* skip glyph "bounding box" */
+ fseek(p, (long)16, SEEK_CUR);
+ loc = 256;
+ hic = -1;
+ TFMPREPARE(font->scale, z, alpha, beta);
+ while((op = fuget1(p)) != GF_POST_POST) {
+ DviFontChar *ch;
+ int cc;
+
+ /* get the character code */
+ cc = fuget1(p);
+ if(cc < loc)
+ loc = cc;
+ if(cc > hic)
+ hic = cc;
+ ch = &font->chars[cc];
+ switch(op) {
+ case GF_LOC:
+ fsget4(p); /* skip dx */
+ fsget4(p); /* skip dy */
+ break;
+ case GF_LOC0:
+ fuget1(p); /* skip dx */
+ /* dy assumed 0 */
+ break;
+ default:
+ error(_("%s: junk in postamble\n"), font->fontname);
+ goto error;
+ }
+ ch->code = cc;
+ ch->tfmwidth = fuget4(p);
+ ch->tfmwidth = TFMSCALE(ch->tfmwidth, z, alpha, beta);
+ ch->offset = fuget4(p);
+ if(ch->offset == -1)
+ ch->offset = 0;
+ /* initialize the rest of the glyph information */
+ ch->x = 0;
+ ch->y = 0;
+ ch->width = 0;
+ ch->height = 0;
+ ch->glyph.data = NULL;
+ ch->shrunk.data = NULL;
+ ch->grey.data = NULL;
+ ch->flags = 0;
+ ch->loaded = 0;
+ }
+
+ if(op != GF_POST_POST)
+ goto badgf;
+
+ if(loc > 0 || hic < 255) {
+ /* shrink to optimal size */
+ memmove(font->chars, font->chars + loc,
+ (hic - loc + 1) * sizeof(DviFontChar));
+ font->chars = xresize(font->chars,
+ DviFontChar, hic - loc + 1);
+ }
+ font->loc = loc;
+ font->hic = hic;
+
+ return 0;
+
+badgf:
+ error(_("%s: File corrupted, or not a GF file\n"), font->fontname);
+error:
+ if(font->chars) {
+ xfree(font->chars);
+ font->chars = NULL;
+ }
+ font->loc = font->hic = 0;
+ return -1;
+}
+
+static int gf_font_get_glyph(DviParams *params, DviFont *font, int code)
+{
+ DviFontChar *ch;
+
+ if(code < font->loc || code > font->hic || !font->chars)
+ return -1;
+ ch = &font->chars[code - font->loc];
+
+ if(!ch->loaded) {
+ if(ch->offset == 0)
+ return -1;
+ DEBUG((DBG_GLYPHS, "(gf) %s: loading GF glyph for character %d\n",
+ font->fontname, code));
+ if(font->in == NULL && font_reopen(font) < 0)
+ return -1;
+ if(fseek(font->in, ch->offset, SEEK_SET) == -1)
+ return -1;
+ if(gf_read_bitmap(font->in, ch) < 0)
+ return -1;
+ ch->loaded = 1;
+ }
+ return 0;
+}
diff --git a/dviware/mdvi/lib/hash.c b/dviware/mdvi/lib/hash.c
new file mode 100644
index 0000000000..5487bed59d
--- /dev/null
+++ b/dviware/mdvi/lib/hash.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "mdvi.h"
+
+/* simple hash tables for MDVI */
+
+
+struct _DviHashBucket {
+ DviHashBucket *next;
+ DviHashKey key;
+ Ulong hvalue;
+ void *data;
+};
+
+static Ulong hash_string(DviHashKey key)
+{
+ Uchar *p;
+ Ulong h, g;
+
+ for(h = 0, p = (Uchar *)key; *p; p++) {
+ h = (h << 4UL) + *p;
+ if((g = h & 0xf0000000L) != 0) {
+ h ^= (g >> 24UL);
+ h ^= g;
+ }
+ }
+
+ return h;
+}
+
+static int hash_compare(DviHashKey k1, DviHashKey k2)
+{
+ return strcmp((char *)k1, (char *)k2);
+}
+
+void mdvi_hash_init(DviHashTable *hash)
+{
+ hash->buckets = NULL;
+ hash->nbucks = 0;
+ hash->nkeys = 0;
+ hash->hash_func = NULL;
+ hash->hash_comp = NULL;
+ hash->hash_free = NULL;
+}
+
+void mdvi_hash_create(DviHashTable *hash, int size)
+{
+ int i;
+
+ hash->nbucks = size;
+ hash->buckets = xnalloc(DviHashBucket *, size);
+ for(i = 0; i < size; i++)
+ hash->buckets[i] = NULL;
+ hash->hash_func = hash_string;
+ hash->hash_comp = hash_compare;
+ hash->hash_free = NULL;
+ hash->nkeys = 0;
+}
+
+static DviHashBucket *hash_find(DviHashTable *hash, DviHashKey key)
+{
+ Ulong hval;
+ DviHashBucket *buck;
+
+ hval = (hash->hash_func(key) % hash->nbucks);
+
+ for(buck = hash->buckets[hval]; buck; buck = buck->next)
+ if(hash->hash_comp(buck->key, key) == 0)
+ break;
+ return buck;
+}
+
+/* Neither keys nor data are duplicated */
+int mdvi_hash_add(DviHashTable *hash, DviHashKey key, void *data, int rep)
+{
+ DviHashBucket *buck = NULL;
+ Ulong hval;
+
+ if(rep != MDVI_HASH_UNCHECKED) {
+ buck = hash_find(hash, key);
+ if(buck != NULL) {
+ if(buck->data == data)
+ return 0;
+ if(rep == MDVI_HASH_UNIQUE)
+ return -1;
+ if(hash->hash_free != NULL)
+ hash->hash_free(buck->key, buck->data);
+ }
+ }
+ if(buck == NULL) {
+ buck = xalloc(DviHashBucket);
+ buck->hvalue = hash->hash_func(key);
+ hval = (buck->hvalue % hash->nbucks);
+ buck->next = hash->buckets[hval];
+ hash->buckets[hval] = buck;
+ hash->nkeys++;
+ }
+
+ /* save key and data */
+ buck->key = key;
+ buck->data = data;
+
+ return 0;
+}
+
+void *mdvi_hash_lookup(DviHashTable *hash, DviHashKey key)
+{
+ DviHashBucket *buck = hash_find(hash, key);
+
+ return buck ? buck->data : NULL;
+}
+
+static DviHashBucket *hash_remove(DviHashTable *hash, DviHashKey key)
+{
+ DviHashBucket *buck, *last;
+ Ulong hval;
+
+ hval = hash->hash_func(key);
+ hval %= hash->nbucks;
+
+ for(last = NULL, buck = hash->buckets[hval]; buck; buck = buck->next) {
+ if(hash->hash_comp(buck->key, key) == 0)
+ break;
+ last = buck;
+ }
+ if(buck == NULL)
+ return NULL;
+ if(last)
+ last->next = buck->next;
+ else
+ hash->buckets[hval] = buck->next;
+ hash->nkeys--;
+ return buck;
+}
+
+void *mdvi_hash_remove(DviHashTable *hash, DviHashKey key)
+{
+ DviHashBucket *buck = hash_remove(hash, key);
+ void *data = NULL;
+
+ if(buck) {
+ data = buck->data;
+ xfree(buck);
+ }
+ return data;
+}
+
+void *mdvi_hash_remove_ptr(DviHashTable *hash, DviHashKey key)
+{
+ DviHashBucket *buck, *last;
+ Ulong hval;
+ void *ptr;
+
+ hval = hash->hash_func(key);
+ hval %= hash->nbucks;
+
+ for(last = NULL, buck = hash->buckets[hval]; buck; buck = buck->next) {
+ if(buck->key == key)
+ break;
+ last = buck;
+ }
+ if(buck == NULL)
+ return NULL;
+ if(last)
+ last->next = buck->next;
+ else
+ hash->buckets[hval] = buck->next;
+ hash->nkeys--;
+ /* destroy the bucket */
+ ptr = buck->data;
+ xfree(buck);
+ return ptr;
+}
+
+int mdvi_hash_destroy_key(DviHashTable *hash, DviHashKey key)
+{
+ DviHashBucket *buck = hash_remove(hash, key);
+
+ if(buck == NULL)
+ return -1;
+ if(hash->hash_free)
+ hash->hash_free(buck->key, buck->data);
+ xfree(buck);
+ return 0;
+}
+
+void mdvi_hash_reset(DviHashTable *hash, int reuse)
+{
+ int i;
+ DviHashBucket *buck;
+
+ /* remove all keys in the hash table */
+ for(i = 0; i < hash->nbucks; i++) {
+ for(; (buck = hash->buckets[i]); ) {
+ hash->buckets[i] = buck->next;
+ if(hash->hash_free)
+ hash->hash_free(buck->key, buck->data);
+ xfree(buck);
+ }
+ }
+ hash->nkeys = 0;
+ if(!reuse && hash->buckets) {
+ xfree(hash->buckets);
+ hash->buckets = NULL;
+ hash->nbucks = 0;
+ } /* otherwise, it is left empty, ready to be reused */
+}
diff --git a/dviware/mdvi/lib/list.c b/dviware/mdvi/lib/list.c
new file mode 100644
index 0000000000..c434e2b197
--- /dev/null
+++ b/dviware/mdvi/lib/list.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "common.h"
+
+void listh_init(ListHead *head)
+{
+ head->head = head->tail = NULL;
+ head->count = 0;
+}
+
+void listh_prepend(ListHead *head, List *list)
+{
+ list->prev = NULL;
+ list->next = head->head;
+ if(head->head)
+ head->head->prev = list;
+ head->head = list;
+ if(!head->tail)
+ head->tail = list;
+ head->count++;
+}
+
+void listh_append(ListHead *head, List *list)
+{
+ list->next = NULL;
+ list->prev = head->tail;
+ if(head->tail)
+ head->tail->next = list;
+ else
+ head->head = list;
+ head->tail = list;
+ head->count++;
+}
+
+void listh_add_before(ListHead *head, List *at, List *list)
+{
+ if(at == head->head || head->head == NULL)
+ listh_prepend(head, list);
+ else {
+ list->next = at;
+ list->prev = at->prev;
+ at->prev = list;
+ head->count++;
+ }
+}
+
+void listh_add_after(ListHead *head, List *at, List *list)
+{
+ if(at == head->tail || !head->tail)
+ listh_append(head, list);
+ else {
+ list->prev = at;
+ list->next = at->next;
+ at->next = list;
+ head->count++;
+ }
+}
+
+void listh_remove(ListHead *head, List *list)
+{
+ if(list == head->head) {
+ head->head = list->next;
+ if(head->head)
+ head->head->prev = NULL;
+ } else if(list == head->tail) {
+ head->tail = list->prev;
+ if(head->tail)
+ head->tail->next = NULL;
+ } else {
+ list->next->prev = list->prev;
+ list->prev->next = list->next;
+ }
+ if(--head->count == 0)
+ head->head = head->tail = NULL;
+}
+
+void listh_concat(ListHead *h1, ListHead *h2)
+{
+ if(h2->head == NULL)
+ ; /* do nothing */
+ else if(h1->tail == NULL)
+ h1->head = h2->head;
+ else {
+ h1->tail->next = h2->head;
+ h2->head->prev = h1->tail;
+ }
+ h1->tail = h2->tail;
+ h1->count += h2->count;
+}
+
+void listh_catcon(ListHead *h1, ListHead *h2)
+{
+ if(h2->head == NULL)
+ ; /* do nothing */
+ else if(h1->head == NULL)
+ h1->tail = h2->tail;
+ else {
+ h1->head->prev = h2->tail;
+ h2->tail->next = h1->head;
+ }
+ h1->head = h2->head;
+ h1->count += h2->count;
+}
diff --git a/dviware/mdvi/lib/pagesel.c b/dviware/mdvi/lib/pagesel.c
new file mode 100644
index 0000000000..7fc610a468
--- /dev/null
+++ b/dviware/mdvi/lib/pagesel.c
@@ -0,0 +1,490 @@
+/* pagesel.c -- Page selection mechanism */
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+char *program_name = "page";
+
+struct _DviPageSpec {
+ DviRange *ranges;
+ int nranges;
+};
+
+DviRange *mdvi_parse_range(const char *format, DviRange *limit, int *nitems, char **endptr)
+{
+ int quoted;
+ int size;
+ int curr;
+ int done;
+ int lower;
+ int upper;
+ int type;
+ char * cp;
+ char * copy;
+ char * text;
+ DviRange one;
+ DviRange *range;
+
+ quoted = (*format == '{');
+ if(quoted) format++;
+
+ size = 0;
+ curr = 0;
+ range = NULL;
+ copy = xstrdup(format);
+ done = 0;
+ lower = 0;
+ upper = 0;
+ type = MDVI_RANGE_UNBOUNDED;
+
+ if(limit) {
+ switch(limit->type) {
+ case MDVI_RANGE_BOUNDED:
+ lower = limit->from;
+ upper = limit->to;
+ break;
+ case MDVI_RANGE_UPPER:
+ lower = INT_MIN;
+ upper = limit->to;
+ break;
+ case MDVI_RANGE_LOWER:
+ lower = limit->from;
+ upper = INT_MAX;
+ break;
+ case MDVI_RANGE_UNBOUNDED:
+ lower = INT_MIN;
+ upper = INT_MAX;
+ break;
+ }
+ type = limit->type;
+ } else {
+ lower = INT_MIN;
+ upper = INT_MAX;
+ type = MDVI_RANGE_UNBOUNDED;
+ }
+ one.type = type;
+ one.from = lower;
+ one.to = upper;
+ one.step = 1;
+ for(cp = text = copy; !done; cp++) {
+ char *p;
+ int f, t, s;
+ int ch;
+ int this_type;
+ int lower_given = 0;
+ int upper_given = 0;
+
+ if(*cp == 0 || *cp == '.' || (*cp == '}' && quoted))
+ done = 1;
+ else if(*cp != ',')
+ continue;
+
+ if(text == cp)
+ continue;
+ ch = *cp;
+ *cp = 0;
+ f = lower;
+ t = upper;
+ s = 1;
+
+ p = strchr(text, ':');
+ if(p) *p++ = 0;
+ if(*text) {
+ lower_given = 1;
+ f = strtol(text, NULL, 0);
+ }
+ if(p == NULL) {
+ if(lower_given) {
+ upper_given = 1;
+ t = f; s = 1;
+ }
+ goto finish;
+ }
+ text = p;
+ p = strchr(text, ':');
+ if(p) *p++ = 0;
+ if(*text) {
+ upper_given = 1;
+ t = strtol(text, NULL, 0);
+ }
+ if(p == NULL)
+ goto finish;
+ text = p;
+ if(*text)
+ s = strtol(text, NULL, 0);
+finish:
+ if(lower_given && upper_given)
+ this_type = MDVI_RANGE_BOUNDED;
+ else if(lower_given) {
+ if(!RANGE_HAS_UPPER(type))
+ this_type = MDVI_RANGE_LOWER;
+ else
+ this_type = MDVI_RANGE_BOUNDED;
+ t = upper;
+ } else if(upper_given) {
+ if(RANGE_HAS_UPPER(one.type)) {
+ one.to++;
+ this_type = MDVI_RANGE_BOUNDED;
+ } else {
+ one.to = lower;
+ if(!RANGE_HAS_LOWER(type))
+ this_type = MDVI_RANGE_UPPER;
+ else
+ this_type = MDVI_RANGE_BOUNDED;
+ }
+ f = one.to;
+ } else {
+ this_type = type;
+ f = lower;
+ t = upper;
+ }
+ one.type = this_type;
+ one.to = t;
+ one.from = f;
+ one.step = s;
+
+ if(curr == size) {
+ size += 8;
+ range = xrealloc(range, size * sizeof(DviRange));
+ }
+ memcpy(&range[curr++], &one, sizeof(DviRange));
+ *cp = ch;
+ text = cp + 1;
+ }
+ if(done)
+ cp--;
+ if(quoted && *cp == '}')
+ cp++;
+ if(endptr)
+ *endptr = (char *)format + (cp - copy);
+ if(curr && curr < size)
+ range = xrealloc(range, curr * sizeof(DviRange));
+ *nitems = curr;
+ xfree(copy);
+ return range;
+}
+
+DviPageSpec *mdvi_parse_page_spec(const char *format)
+{
+ /*
+ * a page specification looks like this:
+ * '{'RANGE_SPEC'}' for a DVI spec
+ * '{'RANGE_SPEC'}' '.' ... for a TeX spec
+ */
+ DviPageSpec *spec;
+ DviRange *range;
+ int count;
+ int i;
+ char *ptr;
+
+ spec = xnalloc(struct _DviPageSpec *, 11);
+ for(i = 0; i < 11; i++)
+ spec[i] = NULL;
+
+ /* check what kind of spec we're parsing */
+ if(*format != '*') {
+ range = mdvi_parse_range(format, NULL, &count, &ptr);
+ if(ptr == format) {
+ if(range) xfree(range);
+ error(_("invalid page specification `%s'\n"), format);
+ return NULL;
+ }
+ } else
+ range = NULL;
+
+ if(*format == 'D' || *format == 'd' || *ptr != '.')
+ i = 0;
+ else
+ i = 1;
+
+ if(range) {
+ spec[i] = xalloc(struct _DviPageSpec);
+ spec[i]->ranges = range;
+ spec[i]->nranges = count;
+ } else
+ spec[i] = NULL;
+
+ if(*ptr != '.') {
+ if(*ptr)
+ warning(_("garbage after DVI page specification ignored\n"));
+ return spec;
+ }
+
+ for(i++; *ptr == '.' && i <= 10; i++) {
+ ptr++;
+ if(*ptr == '*') {
+ ptr++;
+ range = NULL;
+ } else {
+ char *end;
+
+ range = mdvi_parse_range(ptr, NULL, &count, &end);
+ if(end == ptr) {
+ if(range) xfree(range);
+ range = NULL;
+ } else
+ ptr = end;
+ }
+ if(range != NULL) {
+ spec[i] = xalloc(struct _DviPageSpec);
+ spec[i]->ranges = range;
+ spec[i]->nranges = count;
+ } else
+ spec[i] = NULL;
+ }
+
+ if(i > 10)
+ warning(_("more than 10 counters in page specification\n"));
+ else if(*ptr)
+ warning(_("garbage after TeX page specification ignored\n"));
+
+ return spec;
+}
+
+/* returns non-zero if the given page is included by `spec' */
+int mdvi_page_selected(DviPageSpec *spec, PageNum page, int dvipage)
+{
+ int i;
+ int not_found;
+
+ if(spec == NULL)
+ return 1;
+ if(spec[0]) {
+ not_found = mdvi_in_range(spec[0]->ranges,
+ spec[0]->nranges, dvipage);
+ if(not_found < 0)
+ return 0;
+ }
+ for(i = 1; i <= 10; i++) {
+ if(spec[i] == NULL)
+ continue;
+ not_found = mdvi_in_range(spec[i]->ranges,
+ spec[i]->nranges, (int)page[i]);
+ if(not_found < 0)
+ return 0;
+ }
+ return 1;
+}
+
+void mdvi_free_page_spec(DviPageSpec *spec)
+{
+ int i;
+
+ for(i = 0; i < 11; i++)
+ if(spec[i]) {
+ xfree(spec[i]->ranges);
+ xfree(spec[i]);
+ }
+ xfree(spec);
+}
+
+int mdvi_in_range(DviRange *range, int nitems, int value)
+{
+ DviRange *r;
+
+ for(r = range; r < range + nitems; r++) {
+ int cond;
+
+ switch(r->type) {
+ case MDVI_RANGE_BOUNDED:
+ if(value == r->from)
+ return (r - range);
+ if(r->step < 0)
+ cond = (value <= r->from) && (value >= r->to);
+ else
+ cond = (value <= r->to) && (value >= r->from);
+ if(cond && ((value - r->from) % r->step) == 0)
+ return (r - range);
+ break;
+ case MDVI_RANGE_LOWER:
+ if(value == r->from)
+ return (r - range);
+ if(r->step < 0)
+ cond = (value < r->from);
+ else
+ cond = (value > r->from);
+ if(cond && ((value - r->from) % r->step) == 0)
+ return (r - range);
+ break;
+ case MDVI_RANGE_UPPER:
+ if(value == r->to)
+ return (r - range);
+ if(r->step < 0)
+ cond = (value > r->to);
+ else
+ cond = (value < r->to);
+ if(cond && ((value - r->to) % r->step) == 0)
+ return (r - range);
+ break;
+ case MDVI_RANGE_UNBOUNDED:
+ if((value % r->step) == 0)
+ return (r - range);
+ break;
+ }
+ }
+ return -1;
+}
+
+int mdvi_range_length(DviRange *range, int nitems)
+{
+ int count = 0;
+ DviRange *r;
+
+ for(r = range; r < range + nitems; r++) {
+ int n;
+
+ if(r->type != MDVI_RANGE_BOUNDED)
+ return -2;
+ n = (r->to - r->from) / r->step;
+ if(n < 0)
+ n = 0;
+ count += n + 1;
+ }
+ return count;
+}
+
+#ifdef TEST
+
+void print_range(DviRange *range)
+{
+ switch(range->type) {
+ case MDVI_RANGE_BOUNDED:
+ printf("From %d to %d, step %d\n",
+ range->from, range->to, range->step);
+ break;
+ case MDVI_RANGE_LOWER:
+ printf("From %d, step %d\n",
+ range->from, range->step);
+ break;
+ case MDVI_RANGE_UPPER:
+ printf("From %d, step -%d\n",
+ range->to, range->step);
+ break;
+ case MDVI_RANGE_UNBOUNDED:
+ printf("From 0, step %d and %d\n",
+ range->step, -range->step);
+ break;
+ }
+}
+
+int main()
+{
+#if 0
+ char buf[256];
+ DviRange limit;
+
+ limit.from = 0;
+ limit.to = 100;
+ limit.step = 2;
+ limit.type = MDVI_RANGE_UNBOUNDED;
+ while(1) {
+ DviRange *range;
+ char *end;
+ int count;
+ int i;
+
+ printf("Range> "); fflush(stdout);
+ if(fgets(buf, 256, stdin) == NULL)
+ break;
+ if(buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = 0;
+ if(buf[0] == 0)
+ continue;
+ end = NULL;
+ range = mdvi_parse_range(buf, &limit, &count, &end);
+ if(range == NULL) {
+ printf("range is empty\n");
+ continue;
+ }
+
+ for(i = 0; i < count; i++) {
+ printf("Range %d (%d elements):\n",
+ i, mdvi_range_length(&range[i], 1));
+ print_range(&range[i]);
+ }
+ if(end && *end)
+ printf("Tail: [%s]\n", end);
+ printf("range has %d elements\n",
+ mdvi_range_length(range, count));
+#if 1
+ while(1) {
+ int v;
+
+ printf("Value: "); fflush(stdout);
+ if(fgets(buf, 256, stdin) == NULL)
+ break;
+ if(buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = 0;
+ if(buf[0] == 0)
+ break;
+ v = atoi(buf);
+ i = mdvi_in_range(range, count, v);
+ if(i == -1)
+ printf("%d not in range\n", v);
+ else {
+ printf("%d in range: ", v);
+ print_range(&range[i]);
+ }
+ }
+#endif
+ if(range) xfree(range);
+ }
+#else
+ DviPageSpec *spec;
+ char buf[256];
+
+ while(1) {
+ printf("Spec> "); fflush(stdout);
+ if(fgets(buf, 256, stdin) == NULL)
+ break;
+ if(buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = 0;
+ if(buf[0] == 0)
+ continue;
+ spec = mdvi_parse_page_spec(buf);
+ if(spec == NULL)
+ printf("no spec parsed\n");
+ else {
+ int i;
+
+ printf("spec = ");
+ for(i = 0; i < 11; i++) {
+ printf("Counter %d:\n", i);
+ if(spec[i]) {
+ int k;
+
+ for(k = 0; k < spec[i]->nranges; k++)
+ print_range(&spec[i]->ranges[k]);
+ } else
+ printf("\t*\n");
+ }
+ mdvi_free_page_spec(spec);
+ }
+ }
+#endif
+ exit(0);
+
+}
+#endif /* TEST */
diff --git a/dviware/mdvi/lib/paper.c b/dviware/mdvi/lib/paper.c
new file mode 100644
index 0000000000..b98f5e09d7
--- /dev/null
+++ b/dviware/mdvi/lib/paper.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "common.h"
+#include "mdvi.h"
+#include "private.h"
+
+static const DviPaperSpec papers[] = {
+ {"ISO", 0, 0},
+ {"4A0", "1682mm", "2378mm"},
+ {"2A0", "1189mm", "1682mm"},
+ {"A0", "841mm", "1189mm"},
+ {"A1", "594mm", "841mm"},
+ {"A2", "420mm", "594mm"},
+ {"A3", "297mm", "420mm"},
+ {"A4", "210mm", "297mm"},
+ {"A5", "148mm", "210mm"},
+ {"A6", "105mm", "148mm"},
+ {"A7", "74mm", "105mm"},
+ {"A8", "52mm", "74mm"},
+ {"A9", "37mm", "52mm"},
+ {"A10", "26mm", "37mm"},
+ {"B0", "1000mm", "1414mm"},
+ {"B1", "707mm", "1000mm"},
+ {"B2", "500mm", "707mm"},
+ {"B3", "353mm", "500mm"},
+ {"B4", "250mm", "353mm"},
+ {"B5", "176mm", "250mm"},
+ {"B6", "125mm", "176mm"},
+ {"B7", "88mm", "125mm"},
+ {"B8", "62mm", "88mm"},
+ {"B9", "44mm", "62mm"},
+ {"B10", "31mm", "44mm"},
+ {"C0", "917mm", "1297mm"},
+ {"C1", "648mm", "917mm"},
+ {"C2", "458mm", "648mm"},
+ {"C3", "324mm", "458mm"},
+ {"C4", "229mm", "324mm"},
+ {"C5", "162mm", "229mm"},
+ {"C6", "114mm", "162mm"},
+ {"C7", "81mm", "114mm"},
+ {"C8", "57mm", "81mm"},
+ {"C9", "40mm", "57mm"},
+ {"C10", "28mm", "40mm"},
+ {"US", 0, 0},
+ {"archA", "9in", "12in"},
+ {"archB", "12in", "18in"},
+ {"archC", "18in", "24in"},
+ {"archD", "24in", "36in"},
+ {"archE", "36in", "48in"},
+ {"executive", "7.5in", "10in"},
+ {"flsa", "8.5in", "13in"},
+ {"flse", "8.5in", "13in"},
+ {"halfletter", "5.5in", "8.5in"},
+ {"letter", "8.5in", "11in"},
+ {"legal", "8.5in", "14in"},
+ {"ledger", "17in", "11in"},
+ {"note", "7.5in", "10in"},
+ {"tabloid", "11in", "17in"},
+ {"statement", "5.5in", "8.5in"},
+ {0, 0, 0}
+};
+
+static DviPaperClass str2class(const char *name)
+{
+ if(STRCEQ(name, "ISO"))
+ return MDVI_PAPER_CLASS_ISO;
+ else if(STRCEQ(name, "US"))
+ return MDVI_PAPER_CLASS_US;
+ return MDVI_PAPER_CLASS_CUSTOM;
+}
+
+int mdvi_get_paper_size(const char *name, DviPaper *paper)
+{
+ const DviPaperSpec *sp;
+ double a, b;
+ char c, d, e, f;
+ char buf[32];
+
+ paper->pclass = MDVI_PAPER_CLASS_CUSTOM;
+ if(sscanf(name, "%lfx%lf%c%c", &a, &b, &c, &d) == 4) {
+ sprintf(buf, "%12.16f%c%c", a, c, d);
+ paper->inches_wide = unit2pix_factor(buf);
+ sprintf(buf, "%12.16f%c%c", b, c, d);
+ paper->inches_tall = unit2pix_factor(buf);
+ paper->name = _("custom");
+ return 0;
+ } else if(sscanf(name, "%lf%c%c,%lf%c%c", &a, &c, &d, &b, &e, &f) == 6) {
+ sprintf(buf, "%12.16f%c%c", a, c, d);
+ paper->inches_wide = unit2pix_factor(buf);
+ sprintf(buf, "%12.16f%c%c", b, e, f);
+ paper->inches_tall = unit2pix_factor(buf);
+ paper->name = _("custom");
+ return 0;
+ }
+
+ for(sp = &papers[0]; sp->name; sp++) {
+ if(!sp->width || !sp->height) {
+ paper->pclass = str2class(sp->name);
+ continue;
+ }
+ if(strcasecmp(sp->name, name) == 0) {
+ paper->inches_wide = unit2pix_factor(sp->width);
+ paper->inches_tall = unit2pix_factor(sp->height);
+ paper->name = sp->name;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+DviPaperSpec *mdvi_get_paper_specs(DviPaperClass pclass)
+{
+ int i;
+ int first, count;
+ DviPaperSpec *spec, *ptr;
+
+ first = -1;
+ count = 0;
+ if(pclass == MDVI_PAPER_CLASS_ANY ||
+ pclass == MDVI_PAPER_CLASS_CUSTOM) {
+ first = 0;
+ count = (sizeof(papers) / sizeof(papers[0])) - 3;
+ } else for(i = 0; papers[i].name; i++) {
+ if(papers[i].width == NULL) {
+ if(str2class(papers[i].name) == pclass)
+ first = i;
+ else if(first >= 0)
+ break;
+ } else if(first >= 0)
+ count++;
+ }
+ ptr = spec = xnalloc(DviPaperSpec, count + 1);
+ for(i = first; papers[i].name&& count > 0; i++) {
+ if(papers[i].width) {
+ ptr->name = papers[i].name;
+ ptr->width = papers[i].width;
+ ptr->height = papers[i].height;
+ ptr++;
+ count--;
+ }
+ }
+ ptr->name = NULL;
+ ptr->width = NULL;
+ ptr->height = NULL;
+
+ return spec;
+}
+
+void mdvi_free_paper_specs(DviPaperSpec *spec)
+{
+ xfree(spec);
+}
diff --git a/dviware/mdvi/lib/pk.c b/dviware/mdvi/lib/pk.c
new file mode 100644
index 0000000000..7c1d13a29e
--- /dev/null
+++ b/dviware/mdvi/lib/pk.c
@@ -0,0 +1,569 @@
+
+/* Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * History:
+ *
+ * 11/3/2000:
+ * - First working version
+ * 11/4/2000:
+ * - FIXED: entirely white/black rows were missed.
+ * 11/8/2000:
+ * - TESTED: Glyphs are rendered correctly in different byte orders.
+ * - Made bitmap code much more efficient and compact.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+#define PK_ID 89
+#define PK_CMD_START 240
+#define PK_X1 240
+#define PK_X2 241
+#define PK_X3 242
+#define PK_X4 243
+#define PK_Y 244
+#define PK_POST 245
+#define PK_NOOP 246
+#define PK_PRE 247
+
+#define PK_DYN_F(x) (((x) >> 4) & 0xf)
+#define PK_PACKED(x) (PK_DYN_F(x) != 14)
+
+static int pk_load_font __PROTO((DviParams *, DviFont *));
+static int pk_font_get_glyph __PROTO((DviParams *, DviFont *, int));
+
+static int pk_auto_generate = 1; /* this is ON by default */
+
+typedef struct {
+ char currbyte;
+ char nybpos;
+ int dyn_f;
+} pkread;
+
+static char *pk_lookup __PROTO((const char *, Ushort *, Ushort *));
+static char *pk_lookupn __PROTO((const char *, Ushort *, Ushort *));
+
+/* only symbols exported by this file */
+DviFontInfo pk_font_info = {
+ "PK",
+ 0, /* scaling not supported natively */
+ pk_load_font,
+ pk_font_get_glyph,
+ mdvi_shrink_glyph,
+ mdvi_shrink_glyph_grey,
+ NULL, /* free */
+ NULL, /* reset */
+ pk_lookup, /* lookup */
+ kpse_pk_format,
+ NULL
+};
+
+DviFontInfo pkn_font_info = {
+ "PKN",
+ 0, /* scaling not supported natively */
+ pk_load_font,
+ pk_font_get_glyph,
+ mdvi_shrink_glyph,
+ mdvi_shrink_glyph_grey,
+ NULL, /* free */
+ NULL, /* reset */
+ pk_lookupn, /* lookup */
+ kpse_pk_format,
+ NULL
+};
+
+static char *pk_lookup(const char *name, Ushort *hdpi, Ushort *vdpi)
+{
+ kpse_glyph_file_type type;
+ char *filename;
+
+ if(pk_auto_generate == 0) {
+ kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
+ pk_auto_generate = 1;
+ }
+ filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
+ kpse_pk_format, &type);
+ if(filename && type.source == kpse_glyph_source_fallback) {
+ xfree(filename);
+ filename = NULL;
+ } else if(filename) {
+ *hdpi = *vdpi = type.dpi;
+ }
+ return filename;
+}
+
+static char *pk_lookupn(const char *name, Ushort *hdpi, Ushort *vdpi)
+{
+ kpse_glyph_file_type type;
+ char *filename;
+
+ if(pk_auto_generate) {
+ kpse_set_program_enabled(kpse_pk_format, 0, kpse_src_cmdline);
+ pk_auto_generate = 0;
+ }
+ filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
+ kpse_pk_format, &type);
+ if(filename && type.source == kpse_glyph_source_fallback) {
+ xfree(filename);
+ filename = NULL;
+ } else if(filename) {
+ *hdpi = *vdpi = type.dpi;
+ }
+ return filename;
+}
+
+static inline int pk_get_nyb(FILE *p, pkread *pk)
+{
+ unsigned t;
+ int nb;
+ char c;
+
+ t = c = pk->currbyte;
+ nb = pk->nybpos;
+
+ switch(nb) {
+ case 0:
+ c = pk->currbyte = fuget1(p);
+ t = (c >> 4);
+ break;
+ case 1:
+ t = c;
+ break;
+ }
+ pk->nybpos = !nb;
+ return (t & 0xf);
+}
+
+/*
+ * this is a bit cumbersome because we have to pass around
+ * the `pkread' data...
+ */
+static int pk_packed_num(FILE *p, pkread *pkr, int *repeat)
+{
+ int i, j;
+ int dyn_f = pkr->dyn_f;
+
+ i = pk_get_nyb(p, pkr);
+ if(i == 0) {
+ do {
+ j = pk_get_nyb(p, pkr);
+ i++;
+ } while(j == 0);
+ while(i-- > 0)
+ j = (j << 4) + pk_get_nyb(p, pkr);
+ return (j - 15 + ((13 - dyn_f) << 4) +
+ dyn_f);
+ } else if(i <= dyn_f)
+ return i;
+ else if(i < 14)
+ return ((i - dyn_f - 1) << 4) +
+ pk_get_nyb(p, pkr) + dyn_f + 1;
+ else {
+ *repeat = 1;
+ if(i == 14)
+ *repeat = pk_packed_num(p, pkr, repeat);
+ return pk_packed_num(p, pkr, repeat);
+ }
+}
+
+#define ROUND(x,y) (((x) + (y) - 1) / (y))
+
+static BITMAP *get_bitmap(FILE *p, int w, int h, int flags)
+{
+ int i, j;
+ BmUnit *ptr;
+ BITMAP *bm;
+ int bitpos;
+ int currch;
+
+ flags = 0; /* shut up that compiler */
+ bitpos = -1;
+ if((bm = bitmap_alloc(w, h)) == NULL)
+ return NULL;
+ DEBUG((DBG_BITMAPS, "get_bitmap(%d,%d,%d): reading raw bitmap\n",
+ w, h, flags));
+ ptr = bm->data;
+ currch = 0;
+ for(i = 0; i < h; i++) {
+ BmUnit mask;
+
+ mask = FIRSTMASK;
+ for(j = 0; j < w; j++) {
+ if(bitpos < 0) {
+ currch = fuget1(p);
+ bitpos = 7;
+ }
+ if(currch & (1 << bitpos))
+ *ptr |= mask;
+ bitpos--;
+ if(mask == LASTMASK) {
+ ptr++;
+ mask = FIRSTMASK;
+ } else
+ NEXTMASK(mask);
+ }
+ ptr = bm_offset(ptr, bm->stride);
+ }
+ return bm;
+}
+
+static BITMAP *get_packed(FILE *p, int w, int h, int flags)
+{
+ int inrow, count;
+ int row;
+ BITMAP *bm;
+ int repeat_count;
+ int paint;
+ pkread pkr;
+
+ pkr.nybpos = 0;
+ pkr.currbyte = 0;
+ pkr.dyn_f = PK_DYN_F(flags);
+ paint = !!(flags & 0x8);
+
+ repeat_count = 0;
+ row = 0;
+ inrow = w;
+ if((bm = bitmap_alloc(w, h)) == NULL)
+ return NULL;
+ DEBUG((DBG_BITMAPS, "get_packed(%d,%d,%d): reading packed glyph\n",
+ w, h, flags));
+ while(row < h) {
+ int i = 0;
+
+ count = pk_packed_num(p, &pkr, &i);
+ if(i > 0) {
+ if(repeat_count)
+ fprintf(stderr, "second repeat count for this row (had %d and got %d)\n",
+ repeat_count, i);
+ repeat_count = i;
+ }
+
+ if(count >= inrow) {
+ Uchar *r, *t;
+ BmUnit *a, mask;
+
+ /* first finish current row */
+ if(paint)
+ bitmap_set_row(bm, row, w - inrow, inrow, paint);
+ /* now copy it as many times as required */
+ r = (Uchar *)bm->data + row * bm->stride;
+ while(repeat_count-- > 0) {
+ t = r + bm->stride;
+ /* copy entire lines */
+ memcpy(t, r, bm->stride);
+ r = t;
+ row++;
+ }
+ repeat_count = 0;
+ /* count first row we drew */
+ row++;
+ /* update run count */
+ count -= inrow;
+ /* now r points to the beginning of the last row we finished */
+ if(paint)
+ mask = ~((BmUnit)0);
+ else
+ mask = 0;
+ /* goto next row */
+ a = (BmUnit *)(r + bm->stride);
+ /* deal with entirely with/black rows */
+ while(count >= w) {
+ /* count number of atoms in a row */
+ i = ROUND(w, BITMAP_BITS);
+ while(i-- > 0)
+ *a++ = mask;
+ count -= w;
+ row++;
+ }
+ inrow = w;
+ }
+ if(count > 0)
+ bitmap_set_row(bm, row, w - inrow, count, paint);
+ inrow -= count;
+ paint = !paint;
+ }
+ if(row != h || inrow != w) {
+ error(_("Bad PK file: More bits than required\n"));
+ bitmap_destroy(bm);
+ return NULL;
+ }
+ return bm;
+}
+
+static BITMAP *get_char(FILE *p, int w, int h, int flags)
+{
+ /* check if dyn_f == 14 */
+ if(((flags >> 4) & 0xf) == 14)
+ return get_bitmap(p, w, h, flags);
+ else
+ return get_packed(p, w, h, flags);
+}
+
+/* supports any number of characters in a font */
+static int pk_load_font(DviParams *unused, DviFont *font)
+{
+ int i;
+ int flag_byte;
+ int loc, hic, maxch;
+ Int32 checksum;
+ FILE *p;
+#ifndef NODEBUG
+ char s[256];
+#endif
+ long alpha, beta, z;
+
+ font->chars = xnalloc(DviFontChar, 256);
+ p = font->in;
+ memzero(font->chars, 256 * sizeof(DviFontChar));
+ for(i = 0; i < 256; i++)
+ font->chars[i].offset = 0;
+
+ /* check the preamble */
+ loc = fuget1(p); hic = fuget1(p);
+ if(loc != PK_PRE || hic != PK_ID)
+ goto badpk;
+ i = fuget1(p);
+#ifndef NODEBUG
+ for(loc = 0; loc < i; loc++)
+ s[loc] = fuget1(p);
+ s[loc] = 0;
+ DEBUG((DBG_FONTS, "(pk) %s: %s\n", font->fontname, s));
+#else
+ fseek(in, (long)i, SEEK_CUR);
+#endif
+ /* get the design size */
+ font->design = fuget4(p);
+ /* get the checksum */
+ checksum = fuget4(p);
+ if(checksum && font->checksum && font->checksum != checksum) {
+ warning(_("%s: checksum mismatch (expected %u, got %u)\n"),
+ font->fontname, font->checksum, checksum);
+ } else if(!font->checksum)
+ font->checksum = checksum;
+ /* skip pixel per point ratios */
+ fuget4(p);
+ fuget4(p);
+ if(feof(p))
+ goto badpk;
+
+ /* now start reading the font */
+ loc = 256; hic = -1; maxch = 256;
+
+ /* initialize alpha and beta for TFM width computation */
+ TFMPREPARE(font->scale, z, alpha, beta);
+
+ while((flag_byte = fuget1(p)) != PK_POST) {
+ if(feof(p))
+ break;
+ if(flag_byte >= PK_CMD_START) {
+ switch(flag_byte) {
+ case PK_X1:
+ case PK_X2:
+ case PK_X3:
+ case PK_X4: {
+#ifndef NODEBUG
+ char *t;
+ int n;
+
+ i = fugetn(p, flag_byte - PK_X1 + 1);
+ if(i < 256)
+ t = &s[0];
+ else
+ t = xmalloc(i + 1);
+ for(n = 0; n < i; n++)
+ t[n] = fuget1(p);
+ t[n] = 0;
+ DEBUG((DBG_SPECIAL, "(pk) %s: Special \"%s\"\n",
+ font->fontname, t));
+ if(t != &s[0])
+ xfree(t);
+#else
+ i = fugetn(p, flag_byte - PK_X1 + 1);
+ while(i-- > 0)
+ fuget1(p);
+#endif
+ break;
+ }
+ case PK_Y:
+ i = fuget4(p);
+ DEBUG((DBG_SPECIAL, "(pk) %s: MF special %u\n",
+ font->fontname, (unsigned)i));
+ break;
+ case PK_POST:
+ case PK_NOOP:
+ break;
+ case PK_PRE:
+ error(_("%s: unexpected preamble\n"), font->fontname);
+ goto error;
+ }
+ } else {
+ int pl;
+ int cc;
+ int w, h;
+ int x, y;
+ int offset;
+ long tfm;
+
+ switch(flag_byte & 0x7) {
+ case 7:
+ pl = fuget4(p);
+ cc = fuget4(p);
+ offset = ftell(p) + pl;
+ tfm = fuget4(p);
+ fsget4(p); /* skip dx */
+ fsget4(p); /* skip dy */
+ w = fuget4(p);
+ h = fuget4(p);
+ x = fsget4(p);
+ y = fsget4(p);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ pl = (flag_byte % 4) * 65536 + fuget2(p);
+ cc = fuget1(p);
+ offset = ftell(p) + pl;
+ tfm = fuget3(p);
+ fsget2(p); /* skip dx */
+ /* dy assumed 0 */
+ w = fuget2(p);
+ h = fuget2(p);
+ x = fsget2(p);
+ y = fsget2(p);
+ break;
+ default:
+ pl = (flag_byte % 4) * 256 + fuget1(p);
+ cc = fuget1(p);
+ offset = ftell(p) + pl;
+ tfm = fuget3(p);
+ fsget1(p); /* skip dx */
+ /* dy assumed 0 */
+ w = fuget1(p);
+ h = fuget1(p);
+ x = fsget1(p);
+ y = fsget1(p);
+ }
+ if(feof(p))
+ break;
+ if(cc < loc)
+ loc = cc;
+ if(cc > hic)
+ hic = cc;
+ if(cc > maxch) {
+ font->chars = xresize(font->chars,
+ DviFontChar, cc + 16);
+ for(i = maxch; i < cc + 16; i++)
+ font->chars[i].offset = 0;
+ maxch = cc + 16;
+ }
+ font->chars[cc].code = cc;
+ font->chars[cc].flags = flag_byte;
+ font->chars[cc].offset = ftell(p);
+ font->chars[cc].width = w;
+ font->chars[cc].height = h;
+ font->chars[cc].glyph.data = NULL;
+ font->chars[cc].x = x;
+ font->chars[cc].y = y;
+ font->chars[cc].glyph.x = x;
+ font->chars[cc].glyph.y = y;
+ font->chars[cc].glyph.w = w;
+ font->chars[cc].glyph.h = h;
+ font->chars[cc].grey.data = NULL;
+ font->chars[cc].shrunk.data = NULL;
+ font->chars[cc].tfmwidth = TFMSCALE(z, tfm, alpha, beta);
+ font->chars[cc].loaded = 0;
+ fseek(p, (long)offset, SEEK_SET);
+ }
+ }
+ if(flag_byte != PK_POST) {
+ error(_("%s: unexpected end of file (no postamble)\n"),
+ font->fontname);
+ goto error;
+ }
+ while((flag_byte = fuget1(p)) != EOF) {
+ if(flag_byte != PK_NOOP) {
+ error(_("invalid PK file! (junk in postamble)\n"));
+ goto error;
+ }
+ }
+
+ /* resize font char data */
+ if(loc > 0 || hic < maxch-1) {
+ memmove(font->chars, font->chars + loc,
+ (hic - loc + 1) * sizeof(DviFontChar));
+ font->chars = xresize(font->chars,
+ DviFontChar, hic - loc + 1);
+ }
+ font->loc = loc;
+ font->hic = hic;
+ return 0;
+
+badpk:
+ error(_("%s: File corrupted, or not a PK file\n"), font->fontname);
+error:
+ xfree(font->chars);
+ font->chars = NULL;
+ font->loc = font->hic = 0;
+ return -1;
+}
+
+static int pk_font_get_glyph(DviParams *params, DviFont *font, int code)
+{
+ DviFontChar *ch;
+
+ if((ch = FONTCHAR(font, code)) == NULL)
+ return -1;
+
+ if(ch->offset == 0)
+ return -1;
+ DEBUG((DBG_GLYPHS, "(pk) loading glyph for character %d (%dx%d) in font `%s'\n",
+ code, ch->width, ch->height, font->fontname));
+ if(font->in == NULL && font_reopen(font) < 0)
+ return -1;
+ if(!ch->width || !ch->height) {
+ /* this happens for ` ' (ASCII 32) in some fonts */
+ ch->glyph.x = ch->x;
+ ch->glyph.y = ch->y;
+ ch->glyph.w = ch->width;
+ ch->glyph.h = ch->height;
+ ch->glyph.data = NULL;
+ return 0;
+ }
+ if(fseek(font->in, ch->offset, SEEK_SET) == -1)
+ return -1;
+ ch->glyph.data = get_char(font->in,
+ ch->width, ch->height, ch->flags);
+ if(ch->glyph.data) {
+ /* restore original settings */
+ ch->glyph.x = ch->x;
+ ch->glyph.y = ch->y;
+ ch->glyph.w = ch->width;
+ ch->glyph.h = ch->height;
+ } else
+ return -1;
+ ch->loaded = 1;
+ return 0;
+}
diff --git a/dviware/mdvi/lib/po/CVS/Entries b/dviware/mdvi/lib/po/CVS/Entries
new file mode 100644
index 0000000000..e6aca75262
--- /dev/null
+++ b/dviware/mdvi/lib/po/CVS/Entries
@@ -0,0 +1,7 @@
+/Makefile.in/1.1.1.1/Tue Mar 20 09:25:29 2001//
+/cat-id-tbl.c/1.1.1.1/Tue Mar 20 09:25:30 2001//
+/es.gmo/1.1.1.1/Tue Mar 20 09:25:29 2001//
+/es.po/1.1.1.1/Tue Mar 20 09:25:29 2001//
+/mdvi.pot/1.1.1.1/Tue Mar 20 09:25:29 2001//
+/stamp-cat-id/1.1.1.1/Tue Mar 20 09:25:29 2001//
+D
diff --git a/dviware/mdvi/lib/po/CVS/Repository b/dviware/mdvi/lib/po/CVS/Repository
new file mode 100644
index 0000000000..fe4f6751df
--- /dev/null
+++ b/dviware/mdvi/lib/po/CVS/Repository
@@ -0,0 +1 @@
+mdvi/lib/po
diff --git a/dviware/mdvi/lib/po/CVS/Root b/dviware/mdvi/lib/po/CVS/Root
new file mode 100644
index 0000000000..164e86eed7
--- /dev/null
+++ b/dviware/mdvi/lib/po/CVS/Root
@@ -0,0 +1 @@
+agiacom@cvs.mdvi.sourceforge.net:/cvsroot/mdvi
diff --git a/dviware/mdvi/lib/po/Makefile b/dviware/mdvi/lib/po/Makefile
new file mode 100644
index 0000000000..429a2f036d
--- /dev/null
+++ b/dviware/mdvi/lib/po/Makefile
@@ -0,0 +1,18 @@
+# Generated automatically from Makefile.in by configure.
+
+srcdir = .
+
+include ../../config.mk
+
+PACKAGE = mdvi
+SUBDIR = lib
+LINGUAS = es
+
+POT_SOURCES = afmparse.c assoc.c bitmap.c common.c dvimisc.c dviread.c \
+ files.c font.c fontmap.c fontsrch.c gf.c hash.c list.c pagesel.c \
+ paper.c pk.c setup.c sp-epsf.c special.c t1.c tfm.c tfmfile.c \
+ util.c vf.c
+
+DISTCLEANABLE += Makefile
+
+include $(TOPDIR)/nls.mk
diff --git a/dviware/mdvi/lib/po/Makefile.in b/dviware/mdvi/lib/po/Makefile.in
new file mode 100644
index 0000000000..f603e41efa
--- /dev/null
+++ b/dviware/mdvi/lib/po/Makefile.in
@@ -0,0 +1,18 @@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include ../../config.mk
+
+PACKAGE = mdvi
+SUBDIR = lib
+LINGUAS = es
+
+POT_SOURCES = afmparse.c assoc.c bitmap.c common.c dvimisc.c dviread.c \
+ files.c font.c fontmap.c fontsrch.c gf.c hash.c list.c pagesel.c \
+ paper.c pk.c setup.c sp-epsf.c special.c t1.c tfm.c tfmfile.c \
+ util.c vf.c
+
+DISTCLEANABLE += Makefile
+
+include $(TOPDIR)/nls.mk
diff --git a/dviware/mdvi/lib/po/cat-id-tbl.c b/dviware/mdvi/lib/po/cat-id-tbl.c
new file mode 100644
index 0000000000..31167514c7
--- /dev/null
+++ b/dviware/mdvi/lib/po/cat-id-tbl.c
@@ -0,0 +1,103 @@
+/* Automatically generated by po2tbl.sed from mdvi.pot. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libgettext.h"
+
+const struct _msg_ent _msg_tbl[] = {
+ {"", 1},
+ {"unexpected EOF\n", 2},
+ {"could not load font `%s'\n", 3},
+ {"could not reload `%s'\n", 4},
+ {"%s: unsupported DVI format (version %u)\n", 5},
+ {"no pages selected\n", 6},
+ {"%s: File corrupted, or not a DVI file\n", 7},
+ {"%s: vf macro had errors\n", 8},
+ {"%s: stack not empty after vf macro\n", 9},
+ {"%s: could not reopen file (%s)\n", 10},
+ {"%s: page %d out of range\n", 11},
+ {"%s: bad offset at page %d\n", 12},
+ {"stack not empty at end of page\n", 13},
+ {"no default font set yet\n", 14},
+ {"requested character %d does not exist in `%s'\n", 15},
+ {"enlarging stack\n", 16},
+ {"stack underflow\n", 17},
+ {"font %d is not defined\n", 18},
+ {"font %d is not defined in postamble\n", 19},
+ {"unexpected opcode %d\n", 20},
+ {"undefined opcode %d\n", 21},
+ {"%s: no fonts defined\n", 22},
+ {"%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n", 23},
+ {"%s: could not load fontmap\n", 24},
+ {"%s: could not set as default encoding\n", 25},
+ {"encoding vector `%s' is in use\n", 26},
+ {"GF: invalid opcode %d in character %d\n", 27},
+ {"(gf) Character %d: invalid opcode %d\n", 28},
+ {"(gf) character %d has an incorrect bounding box\n", 29},
+ {"%s: bad checksum (expected %u, found %u)\n", 30},
+ {"%s: junk in postamble\n", 31},
+ {"%s: File corrupted, or not a GF file\n", 32},
+ {"invalid page specification `%s'\n", 33},
+ {"garbage after DVI page specification ignored\n", 34},
+ {"more than 10 counters in page specification\n", 35},
+ {"garbage after TeX page specification ignored\n", 36},
+ {"custom", 37},
+ {"Bad PK file: More bits than required\n", 38},
+ {"%s: checksum mismatch (expected %u, got %u)\n", 39},
+ {"%s: unexpected preamble\n", 40},
+ {"%s: unexpected end of file (no postamble)\n", 41},
+ {"invalid PK file! (junk in postamble)\n", 42},
+ {"%s: File corrupted, or not a PK file\n", 43},
+ {"unknown orientation `%s'\n", 44},
+ {"variable %s should be an integer\n", 45},
+ {"variable %s should be a floating-point number\n", 46},
+ {"%s: unknown paper `%s', using %s\n", 47},
+ {"DPI must be a positive integer\n", 48},
+ {"magnification must be a positive number\n", 49},
+ {"pixel density must be between 0 and 100\n", 50},
+ {"no fallback font specified, using `%s'\n", 51},
+ {"%s: malformed value for key `%s'\n", 52},
+ {"%s: unknown key `%s' ignored\n", 53},
+ {"%s: no argument for key `%s', using defaults\n", 54},
+ {"%s: argument `%s' ignored for key `%s'\n", 55},
+ {"%s: tried to pop top level layer\n", 56},
+ {"(t1) failed to reset device resolution\n", 57},
+ {"%s: could not encode font\n", 58},
+ {"(t1) unsupported bitmap pad size %d\n", 59},
+ {"%s: Checksum mismatch (got %u, expected %u)\n", 60},
+ {"%s: Error reading AFM data\n", 61},
+ {"Warning: TFM file `%s' has suspicious size\n", 62},
+ {"%s: font coding scheme truncated to 40 bytes\n", 63},
+ {"%s: File corrupted, or not a TFM file\n", 64},
+ {"Ooops!", 65},
+ {"Aieeeee!!", 66},
+ {"Ouch!", 67},
+ {"Houston, we have a problem", 68},
+ {"3.. 2.. 1.. BOOM!", 69},
+ {"I'm history", 70},
+ {"I'm going down", 71},
+ {"I smell a rat", 72},
+ {"Crashing", 73},
+ {"%s: Error: ", 74},
+ {"Error", 75},
+ {"%s: Warning: ", 76},
+ {"Warning", 77},
+ {"%s: Fatal: ", 78},
+ {"Fatal", 79},
+ {"out of memory allocating %u bytes\n", 80},
+ {"attempted to reallocate with zero size\n", 81},
+ {"failed to reallocate %u bytes\n", 82},
+ {"attempted to callocate 0 members\n", 83},
+ {"attempted to callocate %u members with size 0\n", 84},
+ {"failed to allocate %ux%u bytes\n", 85},
+ {"attempted to free NULL pointer\n", 86},
+ {"%s: Checksum mismatch (expected %u, got %u)\n", 87},
+ {"(vf) %s: could not load font `%s'\n", 88},
+ {"(vf) %s: character %d redefined\n", 89},
+ {"(vf) %s: no postamble\n", 90},
+ {"%s: File corrupted, or not a VF file.\n", 91},
+};
+
+int _msg_tbl_length = 91;
diff --git a/dviware/mdvi/lib/po/es.gmo b/dviware/mdvi/lib/po/es.gmo
new file mode 100644
index 0000000000..3184e74625
--- /dev/null
+++ b/dviware/mdvi/lib/po/es.gmo
Binary files differ
diff --git a/dviware/mdvi/lib/po/es.po b/dviware/mdvi/lib/po/es.po
new file mode 100644
index 0000000000..bff94ad8c4
--- /dev/null
+++ b/dviware/mdvi/lib/po/es.po
@@ -0,0 +1,595 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: mdvi 0.2\n"
+"POT-Creation-Date: 2001-03-19 04:03-0500\n"
+"PO-Revision-Date: 2001-03-13 04:20-0500\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+#. this is EOF
+#: ../dviread.c:205
+msgid "unexpected EOF\n"
+msgstr "fin de archivo inesperado\n"
+
+#: ../dviread.c:426
+#, c-format
+msgid "could not load font `%s'\n"
+msgstr "no pude cargar la fuente `%s'\n"
+
+#: ../dviread.c:480
+#, c-format
+msgid "could not reload `%s'\n"
+msgstr "no pude releer `%s'\n"
+
+#: ../dviread.c:712
+#, c-format
+msgid "%s: unsupported DVI format (version %u)\n"
+msgstr "%s: formato DVI desconocido (version %u)\n"
+
+#: ../dviread.c:874
+msgid "no pages selected\n"
+msgstr "ninguna pagina seleccionada\n"
+
+#: ../dviread.c:910
+#, c-format
+msgid "%s: File corrupted, or not a DVI file\n"
+msgstr "%s: Archivo no valido, o no es un DVI\n"
+
+#: ../dviread.c:992
+#, c-format
+msgid "%s: vf macro had errors\n"
+msgstr "%s: errores en la macro vf\n"
+
+#: ../dviread.c:995
+#, c-format
+msgid "%s: stack not empty after vf macro\n"
+msgstr "%s: pila no vacia despues de macro vf\n"
+
+#: ../dviread.c:1020
+#, c-format
+msgid "%s: could not reopen file (%s)\n"
+msgstr "%s: no pude reabrir el archivo (%s)\n"
+
+#: ../dviread.c:1037
+#, c-format
+msgid "%s: page %d out of range\n"
+msgstr "%s: la pagina %d no existe\n"
+
+#: ../dviread.c:1044
+#, c-format
+msgid "%s: bad offset at page %d\n"
+msgstr "%s: puntero no valido en la pagina %d\n"
+
+#: ../dviread.c:1107
+msgid "stack not empty at end of page\n"
+msgstr "pila no vacial al termino de pagina\n"
+
+#: ../dviread.c:1251
+msgid "no default font set yet\n"
+msgstr "no hay una fuente seleccionada\n"
+
+#: ../dviread.c:1261
+#, c-format
+msgid "requested character %d does not exist in `%s'\n"
+msgstr "el caracter requerido %d no existe en `%s'\n"
+
+#: ../dviread.c:1333
+msgid "enlarging stack\n"
+msgstr "aumentando el espacio de pila\n"
+
+#: ../dviread.c:1351
+msgid "stack underflow\n"
+msgstr "desdoblamiento de pila\n"
+
+#: ../dviread.c:1465 ../dviread.c:1487
+#, c-format
+msgid "font %d is not defined\n"
+msgstr "la fuente %d no esta definida\n"
+
+#: ../dviread.c:1527
+#, c-format
+msgid "font %d is not defined in postamble\n"
+msgstr "la fuente %d no fue definida en postambulo\n"
+
+#: ../dviread.c:1539
+#, c-format
+msgid "unexpected opcode %d\n"
+msgstr "codigo %d inesperado\n"
+
+#: ../dviread.c:1545
+#, c-format
+msgid "undefined opcode %d\n"
+msgstr "codigo %d no definido\n"
+
+#: ../fontmap.c:579
+#, c-format
+msgid "%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n"
+msgstr "%s: %d: [%s] el codigo `%s' no corresponde al vector `%s'\n"
+
+#: ../fontmap.c:740
+#, c-format
+msgid "%s: could not load fontmap\n"
+msgstr "%s: no pude cargar el mapa de fuentes\n"
+
+#: ../fontmap.c:754
+#, c-format
+msgid "%s: could not set as default encoding\n"
+msgstr "%s: no pude fijar el codigo predeterminado\n"
+
+#: ../fontmap.c:833
+#, c-format
+msgid "encoding vector `%s' is in use\n"
+msgstr "el vector de codigo `%s' esta siendo usado\n"
+
+#: ../font.c:497
+#, c-format
+msgid "%s: no fonts defined\n"
+msgstr "%s: ninguna fuente definidas\n"
+
+#: ../gf.c:111
+#, c-format
+msgid "GF: invalid opcode %d in character %d\n"
+msgstr "GF: codigo %d no valido en caracter %d\n"
+
+#: ../gf.c:209
+#, c-format
+msgid "(gf) Character %d: invalid opcode %d\n"
+msgstr "(gf) caracter %d: codigo %d no valido\n"
+
+#: ../gf.c:225
+#, c-format
+msgid "(gf) character %d has an incorrect bounding box\n"
+msgstr "(gf) caracter %d tiene una caja minima incorrecta\n"
+
+#: ../gf.c:288
+#, c-format
+msgid "%s: bad checksum (expected %u, found %u)\n"
+msgstr "%s: sumas de verificacion no concuerdan (%u != %u)\n"
+
+#: ../gf.c:324
+#, c-format
+msgid "%s: junk in postamble\n"
+msgstr "%s: basura en postambulo\n"
+
+#: ../gf.c:361
+#, c-format
+msgid "%s: File corrupted, or not a GF file\n"
+msgstr "%s: Archivo no valido, o no es un GF\n"
+
+#: ../pagesel.c:211
+#, c-format
+msgid "invalid page specification `%s'\n"
+msgstr "la especificacion de pagina `%s' no es valida\n"
+
+#: ../pagesel.c:231
+msgid "garbage after DVI page specification ignored\n"
+msgstr "basura al final de especificacion de pagina DVI ignorada\n"
+
+#: ../pagesel.c:259
+msgid "more than 10 counters in page specification\n"
+msgstr "mas de 10 contadores in especificacion de pagina\n"
+
+#: ../pagesel.c:261
+msgid "garbage after TeX page specification ignored\n"
+msgstr "basura al final de especificacion de pagina TeX ignorada\n"
+
+#: ../paper.c:103 ../paper.c:110
+msgid "custom"
+msgstr "usuario"
+
+#: ../pk.c:249
+msgid "Bad PK file: More bits than required\n"
+msgstr "Archivo PK no valido: mas bits de los necesarios\n"
+
+#: ../pk.c:302
+#, c-format
+msgid "%s: checksum mismatch (expected %u, got %u)\n"
+msgstr "%s: sumas de verificacion no concuerdan (%u != %u)\n"
+
+#: ../pk.c:359
+#, c-format
+msgid "%s: unexpected preamble\n"
+msgstr "%s: preambulo inseperado\n"
+
+#: ../pk.c:442
+#, c-format
+msgid "%s: unexpected end of file (no postamble)\n"
+msgstr "%s: fin de archivo inesperado (falta postambulo)\n"
+
+#: ../pk.c:448
+msgid "invalid PK file! (junk in postamble)\n"
+msgstr "archivo PK no valido (basura en postambulo)\n"
+
+#: ../pk.c:465
+#, c-format
+msgid "%s: File corrupted, or not a PK file\n"
+msgstr "%s: Archivo no valido, o no es un PK\n"
+
+#: ../setup.c:138
+#, c-format
+msgid "unknown orientation `%s'\n"
+msgstr "orientacion `%s' desconocida\n"
+
+#: ../setup.c:198
+#, c-format
+msgid "variable %s should be an integer\n"
+msgstr "la variable `%s' debe ser un entero\n"
+
+#: ../setup.c:231
+#, c-format
+msgid "variable %s should be a floating-point number\n"
+msgstr "la variable `%s' debe ser un numero decimal\n"
+
+#: ../setup.c:293
+#, c-format
+msgid "%s: unknown paper `%s', using %s\n"
+msgstr "%s: papel `%s' desconocido, usando %s\n"
+
+#: ../setup.c:300
+msgid "DPI must be a positive integer\n"
+msgstr "DPI debe ser un entero positivo\n"
+
+#: ../setup.c:310
+msgid "magnification must be a positive number\n"
+msgstr "la magnificacion debe ser positiva\n"
+
+#: ../setup.c:314
+msgid "pixel density must be between 0 and 100\n"
+msgstr "la densidad de pixeles debe ser >= 0 y <= 100\n"
+
+#: ../setup.c:324
+#, c-format
+msgid "no fallback font specified, using `%s'\n"
+msgstr "no hay fuente predeterminada definida, usando `%s'\n"
+
+#: ../special.c:242
+#, c-format
+msgid "%s: tried to pop top level layer\n"
+msgstr "%s: `layer pop' sin push\n"
+
+#: ../sp-epsf.c:148
+#, c-format
+msgid "%s: malformed value for key `%s'\n"
+msgstr "%s: el valor para la clave `%s' no es valido\n"
+
+#: ../sp-epsf.c:159
+#, c-format
+msgid "%s: unknown key `%s' ignored\n"
+msgstr "%s: clave `%s' desconocida, ignorada\n"
+
+#: ../sp-epsf.c:164
+#, c-format
+msgid "%s: no argument for key `%s', using defaults\n"
+msgstr "%s: falta argumento para clave `%s', usando valor predeterminado\n"
+
+#: ../sp-epsf.c:168
+#, c-format
+msgid "%s: argument `%s' ignored for key `%s'\n"
+msgstr "%s: argumento `%s' ignorado para la clave `%s'\n"
+
+#: ../t1.c:181
+msgid "(t1) failed to reset device resolution\n"
+msgstr "(t1) no pude fijar la resolucion\n"
+
+#: ../t1.c:209
+#, c-format
+msgid "%s: could not encode font\n"
+msgstr "%s: no pude codificar la fuente\n"
+
+#: ../t1.c:447
+#, c-format
+msgid "(t1) unsupported bitmap pad size %d\n"
+msgstr "(t1) unsupported bitmap pad size %d\n"
+
+#: ../tfm.c:174
+#, c-format
+msgid "%s: Checksum mismatch (got %u, expected %u)\n"
+msgstr "%s: sumas de verificacion no concuerdan (%u != %u)\n"
+
+#: ../tfmfile.c:88
+#, c-format
+msgid "%s: Error reading AFM data\n"
+msgstr "%s: Error leyendo informacion AFM\n"
+
+#: ../tfmfile.c:178
+#, c-format
+msgid "Warning: TFM file `%s' has suspicious size\n"
+msgstr "Atencion: archivo TFM `%s' tiene taman~o sospechoso\n"
+
+#: ../tfmfile.c:228 ../tfmfile.c:509
+#, c-format
+msgid "%s: font coding scheme truncated to 40 bytes\n"
+msgstr "%s: esquema de codigo truncado a 40 bytes\n"
+
+#: ../tfmfile.c:288 ../tfmfile.c:588
+#, c-format
+msgid "%s: File corrupted, or not a TFM file\n"
+msgstr "%s: Archivo no valido, o no es un TFM\n"
+
+#: ../tt.c:132
+#, c-format
+msgid "(tt) %s: could not load face: %s\n"
+msgstr "(tt) %s: no pude cargar la fuente: %s\n"
+
+#: ../tt.c:140
+#, c-format
+msgid "(tt) %s: could not create face: %s\n"
+msgstr "(tt) %s: no pude crear la fuente: %s\n"
+
+#: ../tt.c:149
+#, c-format
+msgid "(tt) %s: could not create glyph: %s\n"
+msgstr "(tt) %s: no pude crear un glifo: %s\n"
+
+#: ../tt.c:182
+#, c-format
+msgid "(tt) %s: no acceptable map found, using #0\n"
+msgstr "(tt) %s: ninguna tabla de mapeo aceptable, usando #0\n"
+
+#: ../tt.c:195
+#, c-format
+msgid "(tt) %s: could not set resolution: %s\n"
+msgstr "(tt) %s: no pude fijar la resolucion: %s\n"
+
+#: ../tt.c:202
+#, c-format
+msgid "(tt) %s: could not set point size: %s\n"
+msgstr "(tt) %s: no pude fijar el taman~o de la fuente: %s\n"
+
+#: ../tt.c:221
+#, c-format
+msgid "(tt) %s: could not load PS name table\n"
+msgstr "(tt) %s: no pude cargar la tabla de nombres PS\n"
+
+#: ../tt.c:246
+#, c-format
+msgid "%s: no encoding vector found, expect bad output\n"
+msgstr ""
+"%s: no hay vector de codigos para esta fuente, la imagen puede ser "
+"incorrecta\n"
+
+#: ../tt.c:306
+#, fuzzy, c-format
+msgid "(tt) %s: no font metric data\n"
+msgstr "(tt) %s: no hay informacion metrica\n"
+
+#: ../util.c:32
+msgid "Ooops!"
+msgstr "Oooops!"
+
+#: ../util.c:33
+msgid "Aieeeee!!"
+msgstr "Aaaargh!!"
+
+#: ../util.c:34
+msgid "Ouch!"
+msgstr "Ayy!"
+
+#: ../util.c:35
+msgid "Houston, we have a problem"
+msgstr "Hay olor a muerto"
+
+#: ../util.c:36
+msgid "3.. 2.. 1.. BOOM!"
+msgstr "Adios mundo cruel"
+
+#: ../util.c:37
+msgid "I'm history"
+msgstr "Estoy frito"
+
+#: ../util.c:38
+msgid "I'm going down"
+msgstr ""
+
+#: ../util.c:39
+msgid "I smell a rat"
+msgstr ""
+
+#: ../util.c:144
+#, fuzzy
+msgid "Crashing"
+msgstr "Abortando: "
+
+#: ../util.c:154
+#, c-format
+msgid "%s: Error: "
+msgstr "%s: Error: "
+
+#: ../util.c:161
+#, fuzzy
+msgid "Error"
+msgstr "Error: "
+
+#: ../util.c:170
+#, c-format
+msgid "%s: Warning: "
+msgstr "%s: Atencion: "
+
+#: ../util.c:177
+#, fuzzy
+msgid "Warning"
+msgstr "Atencion: "
+
+#: ../util.c:186
+#, c-format
+msgid "%s: Fatal: "
+msgstr "%s: Fatal: "
+
+#: ../util.c:193
+#, fuzzy
+msgid "Fatal"
+msgstr "Fatal: "
+
+#: ../util.c:207
+#, c-format
+msgid "out of memory allocating %u bytes\n"
+msgstr "se acabo la memoria al requerir %u bytes\n"
+
+#: ../util.c:217
+msgid "attempted to reallocate with zero size\n"
+msgstr "intento de realloc() a taman~o cero\n"
+
+# FALTA
+#: ../util.c:220
+#, c-format
+msgid "failed to reallocate %u bytes\n"
+msgstr "failed to reallocate %u bytes\n"
+
+#: ../util.c:229
+msgid "attempted to callocate 0 members\n"
+msgstr "intento de calloc() 0 miembros\n"
+
+#: ../util.c:231
+#, c-format
+msgid "attempted to callocate %u members with size 0\n"
+msgstr "intento de calloc() %u miembros de taman~o 0\n"
+
+#: ../util.c:235
+#, c-format
+msgid "failed to allocate %ux%u bytes\n"
+msgstr "se acabo la memoria al requerir %ux%u bytes\n"
+
+#: ../util.c:243
+msgid "attempted to free NULL pointer\n"
+msgstr "intento de liberar puntero nulo\n"
+
+#: ../vf.c:79
+#, c-format
+msgid "%s: Checksum mismatch (expected %u, got %u)\n"
+msgstr "%s: sumas de verificacion no concuerdan (%u != %u)\n"
+
+#: ../vf.c:127
+#, c-format
+msgid "(vf) %s: could not load font `%s'\n"
+msgstr "(vf) %s: no pude cargar la fuente `%s'\n"
+
+#: ../vf.c:177
+#, c-format
+msgid "(vf) %s: character %d redefined\n"
+msgstr "(vf) %s: caracter %d redefinido\n"
+
+#: ../vf.c:200
+#, c-format
+msgid "(vf) %s: no postamble\n"
+msgstr "(vf) %s: falta postambulo\n"
+
+#: ../vf.c:226
+#, c-format
+msgid "%s: File corrupted, or not a VF file.\n"
+msgstr "%s: Archivo no valido, o no es un VF\n"
+
+#~ msgid "ISO paper types"
+#~ msgstr "Tipos de papel ISO"
+
+#~ msgid "US paper types"
+#~ msgstr "Tipos de papel US"
+
+#~ msgid "%s: I don't know about that\n"
+#~ msgstr "%s: No se que nada se\n"
+
+#~ msgid "resolution must be a positive integer\n"
+#~ msgstr "la resolucion debe ser positiva\n"
+
+#~ msgid "Known topics\n"
+#~ msgstr "Topicos conocidos\n"
+
+#~ msgid "magnification must be positive\n"
+#~ msgstr "la magnificacion debe ser positiva\n"
+
+#~ msgid "page number must be a positive integer\n"
+#~ msgstr "el numero de pagina debe ser un entero positivo\n"
+
+#~ msgid "shrinking factor must be a non-negative number\n"
+#~ msgstr "el factor de escala debe ser un entero no negativo, o -1\n"
+
+#~ msgid "unknown sorting type `%s'\n"
+#~ msgstr "tipo de ordenamiento `%s' desconocido\n"
+
+#~ msgid "pixel density must be a non-negative number\n"
+#~ msgstr "la densidad de pixeles debe ser no negativa\n"
+
+#~ msgid "pixel density should be less than 100\n"
+#~ msgstr "la densidad de pixeles debe ser <= 100\n"
+
+#~ msgid "tex-page must be an integer\n"
+#~ msgstr "tex-page debe ser un entero\n"
+
+#, fuzzy
+#~ msgid "%s: no DVI file specified\n"
+#~ msgstr "%s: ninguna fuente definidas\n"
+
+#, fuzzy
+#~ msgid "Try `%s --help' for more information\n"
+#~ msgstr "Ver `%s --help' para mas detalles\n"
+
+#~ msgid "Selected starting page out of range, showing first page instead\n"
+#~ msgstr "La pagina seleccionada no existe, voy a mostrar la primera\n"
+
+#~ msgid "%s: magnification must be positive\n"
+#~ msgstr "%s: la magnificacion debe ser positiva\n"
+
+#~ msgid "%s: no font metrics file, font ignored\n"
+#~ msgstr "%s: no hay informacion metrica, fuente ignorada\n"
+
+#~ msgid "connection to X server failed\n"
+#~ msgstr "no pude conectarme a un servidor X\n"
+
+#~ msgid "%s: could not find display font `%s'\n"
+#~ msgstr "%s: no pude cargar la fuente de pantalla `%s'\n"
+
+#~ msgid "invalid color name `%s', using black\n"
+#~ msgstr "el color `%s' no existe, usando negro\n"
+
+#~ msgid "failed to allocate color `%s', using black\n"
+#~ msgstr "no pude crear el color `%s', usando negro\n"
+
+#~ msgid "could not find a TFM file for the fallback font `%s'\n"
+#~ msgstr "no pude encontrar un TFM para la fuente predeterminada `%s'\n"
+
+#~ msgid "TFM file for font `%s' not fount, trying `%s'\n"
+#~ msgstr "Archivo TFM no existe para la fuente `%s', tratando `%s'\n"
+
+#~ msgid "font `%s' not found\n"
+#~ msgstr "la fuente `%s' no existe\n"
+
+#~ msgid "fallback font `%s' not found, trying TFM\n"
+#~ msgstr "la fuente predeterminada `%s' no existe, tratando TFM\n"
+
+#~ msgid "font `%s' at %ddpi not found, trying `%s' at %ddpi instead\n"
+#~ msgstr ""
+#~ "la fuente `%s' a %ddpi no existe, tratando `%s' a %ddpi en su lugar\n"
+
+#~ msgid "font `%s' at %ddpi not found, trying TFM\n"
+#~ msgstr "la fuente `%s' a %ddpi no existe, tratando TFM\n"
+
+#~ msgid "font `%s' at %ddpi not found. Using `%s' at %ddpi instead\n"
+#~ msgstr "la fuente `%s' a %ddpi no existe. Usando `%s' a %ddpi en su lugar\n"
+
+#~ msgid "%s: unsuported format %d\n"
+#~ msgstr "%s: formato %d desconocido\n"
+
+#~ msgid "could not initialize graphics output\n"
+#~ msgstr "no pude iniciar el sistema grafico\n"
+
+#~ msgid "(ft) %s: could not load face: %s\n"
+#~ msgstr "(ft) %s: no pude cargar la fuente: %s\n"
+
+#~ msgid "(ft) %s: could not create face\n"
+#~ msgstr "(ft) %s: no pude crear la fuente\n"
+
+#~ msgid "encoding vectors not supported for TrueType fonts\n"
+#~ msgstr "vectores de codigo ignorados para fuentes TrueType\n"
+
+#~ msgid "(ft) %s: could not set face size to %dpt\n"
+#~ msgstr "(ft) %s: no pude fijar el tamano de la fuente a %dpt\n"
+
+#~ msgid "(ft) %s: no font metrics data\n"
+#~ msgstr "(ft) %s: no hay informacion metrica para esta fuente\n"
diff --git a/dviware/mdvi/lib/po/mdvi.pot b/dviware/mdvi/lib/po/mdvi.pot
new file mode 100644
index 0000000000..cafa33a43f
--- /dev/null
+++ b/dviware/mdvi/lib/po/mdvi.pot
@@ -0,0 +1,435 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2001-03-20 03:32-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+#. this is EOF
+#: ../dviread.c:205
+msgid "unexpected EOF\n"
+msgstr ""
+
+#: ../dviread.c:426
+#, c-format
+msgid "could not load font `%s'\n"
+msgstr ""
+
+#: ../dviread.c:480
+#, c-format
+msgid "could not reload `%s'\n"
+msgstr ""
+
+#: ../dviread.c:712
+#, c-format
+msgid "%s: unsupported DVI format (version %u)\n"
+msgstr ""
+
+#: ../dviread.c:874
+msgid "no pages selected\n"
+msgstr ""
+
+#: ../dviread.c:910
+#, c-format
+msgid "%s: File corrupted, or not a DVI file\n"
+msgstr ""
+
+#: ../dviread.c:992
+#, c-format
+msgid "%s: vf macro had errors\n"
+msgstr ""
+
+#: ../dviread.c:995
+#, c-format
+msgid "%s: stack not empty after vf macro\n"
+msgstr ""
+
+#: ../dviread.c:1020
+#, c-format
+msgid "%s: could not reopen file (%s)\n"
+msgstr ""
+
+#: ../dviread.c:1037
+#, c-format
+msgid "%s: page %d out of range\n"
+msgstr ""
+
+#: ../dviread.c:1044
+#, c-format
+msgid "%s: bad offset at page %d\n"
+msgstr ""
+
+#: ../dviread.c:1107
+msgid "stack not empty at end of page\n"
+msgstr ""
+
+#: ../dviread.c:1251
+msgid "no default font set yet\n"
+msgstr ""
+
+#: ../dviread.c:1261
+#, c-format
+msgid "requested character %d does not exist in `%s'\n"
+msgstr ""
+
+#: ../dviread.c:1333
+msgid "enlarging stack\n"
+msgstr ""
+
+#: ../dviread.c:1351
+msgid "stack underflow\n"
+msgstr ""
+
+#: ../dviread.c:1465 ../dviread.c:1487
+#, c-format
+msgid "font %d is not defined\n"
+msgstr ""
+
+#: ../dviread.c:1527
+#, c-format
+msgid "font %d is not defined in postamble\n"
+msgstr ""
+
+#: ../dviread.c:1539
+#, c-format
+msgid "unexpected opcode %d\n"
+msgstr ""
+
+#: ../dviread.c:1545
+#, c-format
+msgid "undefined opcode %d\n"
+msgstr ""
+
+#: ../font.c:497
+#, c-format
+msgid "%s: no fonts defined\n"
+msgstr ""
+
+#: ../fontmap.c:587
+#, c-format
+msgid "%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n"
+msgstr ""
+
+#: ../fontmap.c:748
+#, c-format
+msgid "%s: could not load fontmap\n"
+msgstr ""
+
+#: ../fontmap.c:762
+#, c-format
+msgid "%s: could not set as default encoding\n"
+msgstr ""
+
+#: ../fontmap.c:841
+#, c-format
+msgid "encoding vector `%s' is in use\n"
+msgstr ""
+
+#: ../gf.c:112
+#, c-format
+msgid "GF: invalid opcode %d in character %d\n"
+msgstr ""
+
+#: ../gf.c:210
+#, c-format
+msgid "(gf) Character %d: invalid opcode %d\n"
+msgstr ""
+
+#: ../gf.c:226
+#, c-format
+msgid "(gf) character %d has an incorrect bounding box\n"
+msgstr ""
+
+#: ../gf.c:289
+#, c-format
+msgid "%s: bad checksum (expected %u, found %u)\n"
+msgstr ""
+
+#: ../gf.c:325
+#, c-format
+msgid "%s: junk in postamble\n"
+msgstr ""
+
+#: ../gf.c:362
+#, c-format
+msgid "%s: File corrupted, or not a GF file\n"
+msgstr ""
+
+#: ../pagesel.c:211
+#, c-format
+msgid "invalid page specification `%s'\n"
+msgstr ""
+
+#: ../pagesel.c:231
+msgid "garbage after DVI page specification ignored\n"
+msgstr ""
+
+#: ../pagesel.c:259
+msgid "more than 10 counters in page specification\n"
+msgstr ""
+
+#: ../pagesel.c:261
+msgid "garbage after TeX page specification ignored\n"
+msgstr ""
+
+#: ../paper.c:103 ../paper.c:110
+msgid "custom"
+msgstr ""
+
+#: ../pk.c:309
+msgid "Bad PK file: More bits than required\n"
+msgstr ""
+
+#: ../pk.c:362
+#, c-format
+msgid "%s: checksum mismatch (expected %u, got %u)\n"
+msgstr ""
+
+#: ../pk.c:419
+#, c-format
+msgid "%s: unexpected preamble\n"
+msgstr ""
+
+#: ../pk.c:502
+#, c-format
+msgid "%s: unexpected end of file (no postamble)\n"
+msgstr ""
+
+#: ../pk.c:508
+msgid "invalid PK file! (junk in postamble)\n"
+msgstr ""
+
+#: ../pk.c:525
+#, c-format
+msgid "%s: File corrupted, or not a PK file\n"
+msgstr ""
+
+#: ../setup.c:138
+#, c-format
+msgid "unknown orientation `%s'\n"
+msgstr ""
+
+#: ../setup.c:198
+#, c-format
+msgid "variable %s should be an integer\n"
+msgstr ""
+
+#: ../setup.c:231
+#, c-format
+msgid "variable %s should be a floating-point number\n"
+msgstr ""
+
+#: ../setup.c:295
+#, c-format
+msgid "%s: unknown paper `%s', using %s\n"
+msgstr ""
+
+#: ../setup.c:302
+msgid "DPI must be a positive integer\n"
+msgstr ""
+
+#: ../setup.c:312
+msgid "magnification must be a positive number\n"
+msgstr ""
+
+#: ../setup.c:316
+msgid "pixel density must be between 0 and 100\n"
+msgstr ""
+
+#: ../setup.c:326
+#, c-format
+msgid "no fallback font specified, using `%s'\n"
+msgstr ""
+
+#: ../sp-epsf.c:148
+#, c-format
+msgid "%s: malformed value for key `%s'\n"
+msgstr ""
+
+#: ../sp-epsf.c:159
+#, c-format
+msgid "%s: unknown key `%s' ignored\n"
+msgstr ""
+
+#: ../sp-epsf.c:164
+#, c-format
+msgid "%s: no argument for key `%s', using defaults\n"
+msgstr ""
+
+#: ../sp-epsf.c:168
+#, c-format
+msgid "%s: argument `%s' ignored for key `%s'\n"
+msgstr ""
+
+#: ../special.c:242
+#, c-format
+msgid "%s: tried to pop top level layer\n"
+msgstr ""
+
+#: ../t1.c:182
+msgid "(t1) failed to reset device resolution\n"
+msgstr ""
+
+#: ../t1.c:210
+#, c-format
+msgid "%s: could not encode font\n"
+msgstr ""
+
+#: ../t1.c:448
+#, c-format
+msgid "(t1) unsupported bitmap pad size %d\n"
+msgstr ""
+
+#: ../tfm.c:177
+#, c-format
+msgid "%s: Checksum mismatch (got %u, expected %u)\n"
+msgstr ""
+
+#: ../tfmfile.c:88
+#, c-format
+msgid "%s: Error reading AFM data\n"
+msgstr ""
+
+#: ../tfmfile.c:178
+#, c-format
+msgid "Warning: TFM file `%s' has suspicious size\n"
+msgstr ""
+
+#: ../tfmfile.c:228 ../tfmfile.c:509
+#, c-format
+msgid "%s: font coding scheme truncated to 40 bytes\n"
+msgstr ""
+
+#: ../tfmfile.c:288 ../tfmfile.c:588
+#, c-format
+msgid "%s: File corrupted, or not a TFM file\n"
+msgstr ""
+
+#: ../util.c:32
+msgid "Ooops!"
+msgstr ""
+
+#: ../util.c:33
+msgid "Aieeeee!!"
+msgstr ""
+
+#: ../util.c:34
+msgid "Ouch!"
+msgstr ""
+
+#: ../util.c:35
+msgid "Houston, we have a problem"
+msgstr ""
+
+#: ../util.c:36
+msgid "3.. 2.. 1.. BOOM!"
+msgstr ""
+
+#: ../util.c:37
+msgid "I'm history"
+msgstr ""
+
+#: ../util.c:38
+msgid "I'm going down"
+msgstr ""
+
+#: ../util.c:39
+msgid "I smell a rat"
+msgstr ""
+
+#: ../util.c:144
+msgid "Crashing"
+msgstr ""
+
+#: ../util.c:154
+#, c-format
+msgid "%s: Error: "
+msgstr ""
+
+#: ../util.c:161
+msgid "Error"
+msgstr ""
+
+#: ../util.c:170
+#, c-format
+msgid "%s: Warning: "
+msgstr ""
+
+#: ../util.c:177
+msgid "Warning"
+msgstr ""
+
+#: ../util.c:186
+#, c-format
+msgid "%s: Fatal: "
+msgstr ""
+
+#: ../util.c:193
+msgid "Fatal"
+msgstr ""
+
+#: ../util.c:207
+#, c-format
+msgid "out of memory allocating %u bytes\n"
+msgstr ""
+
+#: ../util.c:217
+msgid "attempted to reallocate with zero size\n"
+msgstr ""
+
+#: ../util.c:220
+#, c-format
+msgid "failed to reallocate %u bytes\n"
+msgstr ""
+
+#: ../util.c:229
+msgid "attempted to callocate 0 members\n"
+msgstr ""
+
+#: ../util.c:231
+#, c-format
+msgid "attempted to callocate %u members with size 0\n"
+msgstr ""
+
+#: ../util.c:235
+#, c-format
+msgid "failed to allocate %ux%u bytes\n"
+msgstr ""
+
+#: ../util.c:243
+msgid "attempted to free NULL pointer\n"
+msgstr ""
+
+#: ../vf.c:81
+#, c-format
+msgid "%s: Checksum mismatch (expected %u, got %u)\n"
+msgstr ""
+
+#: ../vf.c:129
+#, c-format
+msgid "(vf) %s: could not load font `%s'\n"
+msgstr ""
+
+#: ../vf.c:179
+#, c-format
+msgid "(vf) %s: character %d redefined\n"
+msgstr ""
+
+#: ../vf.c:202
+#, c-format
+msgid "(vf) %s: no postamble\n"
+msgstr ""
+
+#: ../vf.c:228
+#, c-format
+msgid "%s: File corrupted, or not a VF file.\n"
+msgstr ""
diff --git a/dviware/mdvi/lib/po/stamp-cat-id b/dviware/mdvi/lib/po/stamp-cat-id
new file mode 100644
index 0000000000..9788f70238
--- /dev/null
+++ b/dviware/mdvi/lib/po/stamp-cat-id
@@ -0,0 +1 @@
+timestamp
diff --git a/dviware/mdvi/lib/setup.c b/dviware/mdvi/lib/setup.c
new file mode 100644
index 0000000000..c2436d8727
--- /dev/null
+++ b/dviware/mdvi/lib/setup.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+char *_mdvi_fallback_font = NULL;
+
+int mdvi_get_pagesort(const char *spec)
+{
+ if(STRCEQ(spec, "up"))
+ return MDVI_PAGE_SORT_UP;
+ else if(STRCEQ(spec, "down"))
+ return MDVI_PAGE_SORT_DOWN;
+ else if(STRCEQ(spec, "random"))
+ return MDVI_PAGE_SORT_RANDOM;
+ else if(STRCEQ(spec, "dviup"))
+ return MDVI_PAGE_SORT_DVI_UP;
+ else if(STRCEQ(spec, "dvidown"))
+ return MDVI_PAGE_SORT_DVI_DOWN;
+ else if(STRCEQ(spec, "none"))
+ return MDVI_PAGE_SORT_NONE;
+ return -1;
+}
+
+int mdvi_get_debugmask(const char *spec)
+{
+ const char *ptr, *text;
+ static char *masks[] = {
+ "opcodes", "fonts",
+ "files", "dvi",
+ "params", "special",
+ "device", "glyphs",
+ "bitmaps", "paths",
+ "search", "vars",
+ "bitops", "bitdata",
+ "type1", "tt",
+ "ft2", "fontmaps"
+ };
+ int done = 0;
+ int mask = 0;
+ int i;
+
+ for(ptr = text = spec; !done; ptr++) {
+ int len;
+
+ if(*ptr && *ptr != '|' && *ptr != ',')
+ continue;
+ if(*ptr == 0)
+ done = 1;
+ len = ptr - text;
+ if(len == 0)
+ continue;
+ for(i = 0; masks[i]; i++) {
+ if(STRNEQ(masks[i], text, len)) {
+ mask |= (1 << i);
+ break;
+ }
+ }
+ if(!masks[i] && STRNEQ(text, "silent", len))
+ mask |= DBG_SILENT;
+ text = ptr + 1;
+ }
+ return mask;
+}
+
+DviOrientation mdvi_getorient(const char *s)
+{
+ if(STRCEQ(s, "TBLR") ||
+ STRCEQ(s, "Portrait") ||
+ STRCEQ(s, "TopLeft") ||
+ STRCEQ(s, "top-left") ||
+ STRCEQ(s, "tl"))
+ return MDVI_ORIENT_TBLR;
+
+ if(STRCEQ(s, "TBRL") ||
+ STRCEQ(s, "TopRight") ||
+ STRCEQ(s, "top-right") ||
+ STRCEQ(s, "tr"))
+ return MDVI_ORIENT_TBRL;
+
+ if(STRCEQ(s, "BTLR") ||
+ STRCEQ(s, "BottomLeft") ||
+ STRCEQ(s, "bottom-left") ||
+ STRCEQ(s, "bl"))
+ return MDVI_ORIENT_BTLR;
+
+ if(STRCEQ(s, "BTRL") ||
+ STRCEQ(s, "BottomRight") ||
+ STRCEQ(s, "bottom-right") ||
+ STRCEQ(s, "br"))
+ return MDVI_ORIENT_BTRL;
+
+ if(STRCEQ(s, "RM90") ||
+ STRCEQ(s, "Landscape") ||
+ STRCEQ(s, "rotated-clockwise") ||
+ STRCEQ(s, "rcw"))
+ return MDVI_ORIENT_RM90;
+
+ if(STRCEQ(s, "RP90") ||
+ STRCEQ(s, "Seascape") ||
+ STRCEQ(s, "rotated-counter-clockwise") ||
+ STRCEQ(s, "rccw"))
+ return MDVI_ORIENT_RP90;
+
+ if(STRCEQ(s, "IRP90") ||
+ STRCEQ(s, "FlipSeascape") ||
+ STRCEQ(s, "flipped-seascape") ||
+ STRCEQ(s, "frccw"))
+ return MDVI_ORIENT_IRP90;
+
+ if(STRCEQ(s, "IRM90") ||
+ STRCEQ(s, "FlipLandscape") ||
+ STRCEQ(s, "flipped-landscape") ||
+ STRCEQ(s, "frcw"))
+ return MDVI_ORIENT_IRM90;
+
+ warning(_("unknown orientation `%s'\n"), s);
+ return MDVI_ORIENT_TBLR;
+}
+
+/*
+ * this will try $NAME, and then `NAME' in texmf.cnf, with
+ * letters converted to lowercase, and _ replaced by -
+ * (so MDVI_HDRIFT -> mdvi-hdrift)
+ */
+char *mdvi_getenv(const char *name)
+{
+ static char kname[64];
+ const char *ptr;
+ int i;
+
+ if((ptr = getenv(name)) != NULL)
+ return (char *)ptr;
+ for(i = 0, ptr = name; *ptr; i++, ptr++)
+ kname[i] = (*ptr == '_' ? '-' : tolower(*ptr));
+ kname[i] = 0;
+ return kpse_cnf_get(kname);
+}
+
+int mdvi_getint(const char *name, long *value)
+{
+ long x;
+ char *end;
+
+ errno = 0;
+ x = strtol(name, &end, 0);
+ if(errno || *end)
+ return -1;
+ if(value) *value = x;
+ return 0;
+}
+
+int mdvi_getfloat(const char *name, double *value)
+{
+ long x;
+ char *end;
+
+ errno = 0;
+ x = strtod(name, &end);
+ if(errno || *end)
+ return -1;
+ if(value) *value = x;
+ return 0;
+}
+
+int mdvi_getenv_int(const char *name, int dflt)
+{
+ char *var = mdvi_getenv(name);
+ long x;
+
+ if(var == NULL) {
+ DEBUG((DBG_VARS, "getenv_int: %s -> (nil)\n",
+ name));
+ return dflt;
+ }
+ if(mdvi_getint(var, &x) == -1) {
+ warning(_("variable %s should be an integer\n"), name);
+ x = dflt;
+ }
+ DEBUG((DBG_VARS, "getenv_int: $%s -> %ld (\"%s\")\n",
+ name, x, var));
+ return (int)x;
+}
+
+char *mdvi_getenv_string(const char *name, char *dflt)
+{
+ char *var = mdvi_getenv(name);
+
+ if(var == NULL) {
+ DEBUG((DBG_VARS, "getenv_string: %s -> (nil)\n",
+ name));
+ return dflt;
+ }
+ DEBUG((DBG_VARS, "getenv_string: $%s -> \"%s\"\n",
+ name, var));
+ return var;
+}
+
+double mdvi_getenv_double(const char *name, double dflt)
+{
+ char *var = mdvi_getenv(name);
+ double x;
+
+ if(var == NULL) {
+ DEBUG((DBG_VARS, "getenv_double: %s -> (nil)\n",
+ name));
+ return dflt;
+ }
+ if(mdvi_getfloat(var, &x) == -1) {
+ warning(_("variable %s should be a floating-point number\n"),
+ name);
+ x = dflt;
+ }
+ DEBUG((DBG_VARS, "getenv_double: $%s -> %g (\"%s\")\n",
+ name, x, var));
+ return x;
+}
+
+DviAppConfig *mdvi_init_app(const char *program, const char *progid)
+{
+ DviAppConfig *app;
+ char *value;
+
+ /* get kpathsea going -- we need it here */
+ kpse_set_program_name(program, progid);
+
+ app = xalloc(DviAppConfig);
+
+ app->program = (char *)program;
+ value = strrchr(app->program, '/');
+ if(value)
+ app->program = value + 1;
+
+ /* get defaults from the environment */
+ app->params.dpi = mdvi_getenv_int("MDVI_DPI", MDVI_DPI);
+ app->params.vdpi = mdvi_getenv_int("MDVI_VDPI", MDVI_VDPI);
+ app->params.mag = mdvi_getenv_double("MDVI_MAGNIFICATION", MDVI_MAGNIFICATION);
+ app->params.density = mdvi_getenv_int("MDVI_PIXEL_DENSITY", MDVI_DEFAULT_DENSITY);
+ app->params.gamma = mdvi_getenv_double("MDVI_GAMMA", MDVI_DEFAULT_GAMMA);
+ app->params.flags = MDVI_PARAM_ANTIALIASED;
+ app->params.hdrift = mdvi_getenv_int("MDVI_HDRIFT", -1);
+ app->params.vdrift = mdvi_getenv_int("MDVI_VDRIFT", -1);
+ app->params.hshrink = mdvi_getenv_int("MDVI_HSHRINK", -1);
+ app->params.vshrink = mdvi_getenv_int("MDVI_VSHRINK", -1);
+ value = mdvi_getenv_string("MDVI_ORIENTATION", MDVI_ORIENTATION);
+ app->params.orientation = mdvi_getorient(value);
+ app->fontspec = mdvi_getenv_string("MDVI_FONTSPEC", NULL);
+ app->fontunspec = mdvi_getenv_string("MDVI_FONTOMIT", NULL);
+ app->fgcolor = mdvi_getenv_string("MDVI_FOREGROUND", MDVI_FOREGROUND);
+ app->bgcolor = mdvi_getenv_string("MDVI_BACKGROUND", MDVI_BACKGROUND);
+ app->hmargin = mdvi_getenv_string("MDVI_HMARGIN", MDVI_HMARGIN);
+ app->vmargin = mdvi_getenv_string("MDVI_VMARGIN", MDVI_VMARGIN);
+ app->hrule_units = mdvi_getenv_string("MDVI_HRUNIT", MDVI_HRUNITS);
+ app->vrule_units = mdvi_getenv_string("MDVI_VRUNIT", MDVI_VRUNITS);
+ app->paper.name = mdvi_getenv_string("MDVI_PAPER", MDVI_PAPERNAME);
+ app->fallback_font = mdvi_getenv_string("MDVI_FALLBACK_FONT", MDVI_FALLBACK_FONT);
+ app->mfmode = mdvi_getenv_string("MDVI_MFMODE", MDVI_MFMODE);
+ app->page_sort = MDVI_PAGE_SORT_NONE;
+ app->page_ranges = NULL;
+
+ if(app->params.hshrink == -1 && app->params.vshrink == -1) {
+ app->params.hshrink =
+ app->params.vshrink = mdvi_getenv_int("MDVI_SHRINKING",
+ MDVI_DEFAULT_SHRINKING);
+ }
+ return app;
+}
+
+int mdvi_check_config(DviAppConfig *app)
+{
+ /* Check all the values */
+
+ if(mdvi_get_paper_size(app->paper.name, &app->paper) == -1) {
+ warning(_("%s: unknown paper `%s', using %s\n"),
+ app->program, app->paper.name,
+ MDVI_PAPERNAME);
+ mdvi_get_paper_size(MDVI_PAPERNAME, &app->paper);
+ }
+
+ if(app->params.dpi == (Uint)-1) {
+ error(_("DPI must be a positive integer\n"));
+ return -1;
+ }
+ if(app->params.vdpi == (Uint)-1)
+ app->params.vdpi = app->params.dpi;
+ if(app->params.hshrink == -1)
+ app->params.hshrink = MDVI_SHRINK_FROM_DPI(app->params.dpi);
+ if(app->params.vshrink == -1)
+ app->params.vshrink = MDVI_SHRINK_FROM_DPI(app->params.dpi);
+ if(app->params.mag <= 0) {
+ error(_("magnification must be a positive number\n"));
+ return -1;
+ }
+ if(app->params.density < 0 || app->params.density > 100) {
+ warning(_("pixel density must be between 0 and 100\n"));
+ app->params.density = (app->params.density < 0) ? 0 : 100;
+ }
+ if(app->fgcolor == NULL)
+ app->fgcolor = "black";
+ if(app->bgcolor == NULL)
+ app->bgcolor = "white";
+
+ /* we must have a fallback font */
+ if(app->fallback_font == NULL) {
+ warning(_("no fallback font specified, using `%s'\n"),
+ MDVI_FALLBACK_FONT);
+ app->fallback_font = MDVI_FALLBACK_FONT;
+ }
+
+ /* finish initializing kpathsea */
+ kpse_init_prog(app->program, app->params.dpi,
+ app->mfmode, NULL);
+ kpse_set_program_enabled(kpse_any_glyph_format, 1, kpse_src_compile);
+ kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_compile);
+ kpse_set_program_enabled(kpse_tfm_format, 1, kpse_src_compile);
+ kpse_set_program_enabled(kpse_ofm_format, 1, kpse_src_compile);
+ if(_mdvi_debug_mask & DBG_PATHS)
+ KPSE_DEBUG_SET(KPSE_DEBUG_PATHS);
+ if(_mdvi_debug_mask & DBG_VARS)
+ KPSE_DEBUG_SET(KPSE_DEBUG_VARS);
+ if(_mdvi_debug_mask & DBG_SEARCH)
+ KPSE_DEBUG_SET(KPSE_DEBUG_SEARCH);
+
+ return 0;
+}
+
+void mdvi_init_kpathsea(const char *program,
+ const char *mfmode, const char *font, int dpi)
+{
+ const char *p;
+
+
+ p = strrchr(program, '/');
+ p = (p ? p + 1 : program);
+ kpse_set_program_name(program, p);
+ kpse_init_prog(p, dpi, mfmode, font);
+ kpse_set_program_enabled(kpse_any_glyph_format,
+ 1, kpse_src_compile);
+ kpse_set_program_enabled(kpse_pk_format,
+ 1, kpse_src_compile);
+ kpse_set_program_enabled(kpse_tfm_format,
+ 1, kpse_src_compile);
+ kpse_set_program_enabled(kpse_ofm_format,
+ 1, kpse_src_compile);
+}
+
+void mdvi_set_fallback_font(const char *name)
+{
+ if(_mdvi_fallback_font) {
+ xfree(_mdvi_fallback_font);
+ _mdvi_fallback_font = NULL;
+ }
+ if(name)
+ _mdvi_fallback_font = xstrdup(name);
+}
+
+char *mdvi_get_fallback_font(void)
+{
+ return _mdvi_fallback_font ? xstrdup(_mdvi_fallback_font) : NULL;
+}
diff --git a/dviware/mdvi/lib/sp-epsf.c b/dviware/mdvi/lib/sp-epsf.c
new file mode 100644
index 0000000000..52fed74c82
--- /dev/null
+++ b/dviware/mdvi/lib/sp-epsf.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* postscript specials */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+typedef struct {
+ double ox;
+ double oy;
+ double bw;
+ double bh;
+ double angle;
+} EpsfBox;
+
+#define LLX 0
+#define LLY 1
+#define URX 2
+#define URY 3
+#define RWI 4
+#define RHI 5
+#define HOFF 6
+#define VOFF 7
+#define HSIZE 8
+#define VSIZE 9
+#define HSCALE 10
+#define VSCALE 11
+#define ANGLE 12
+#define CLIP 13
+
+/* Note: the given strings are modified in place */
+static char *parse_epsf_special(EpsfBox *box, char **ret,
+ char *prefix, char *arg)
+{
+ static struct {
+ char *name;
+ int has_arg;
+ char *value;
+ } keys[] = {
+ {"llx", 1, "0"},
+ {"lly", 1, "0"},
+ {"urx", 1, "0"},
+ {"ury", 1, "0"},
+ {"rwi", 1, "0"},
+ {"rhi", 1, "0"},
+ {"hoffset", 1, "0"},
+ {"voffset", 1, "0"},
+ {"hsize", 1, "612"},
+ {"vsize", 1, "792"},
+ {"hscale", 1, "100"},
+ {"vscale", 1, "100"},
+ {"angle", 1, "0"},
+ {"clip", 0, "0"}
+ };
+#define NKEYS (sizeof(keys) / sizeof(keys[0]))
+ char *ptr;
+ char *filename;
+ int quoted;
+ double value[NKEYS];
+ Uchar present[NKEYS];
+ Buffer buffer;
+ char *name;
+ int i;
+ double originx;
+ double originy;
+ double hsize;
+ double vsize;
+ double hscale;
+ double vscale;
+
+ /* this special has the form
+ * ["]file.ps["] [key=valye]*
+ */
+
+ /* scan the filename */
+ while(*arg == ' ' || *arg == '\t')
+ arg++;
+
+ /* make a copy of the string */
+ ptr = arg;
+
+ if(*ptr == '"')
+ for(name = ++ptr; *ptr && *ptr != '"'; ptr++);
+ else
+ for(name = ptr; *ptr && *ptr != ' ' && *ptr != '\t'; ptr++);
+ if(ptr == name)
+ return NULL;
+ *ptr++ = 0;
+ filename = name;
+
+ /* reset values to defaults */
+ for(i = 0; i < NKEYS; i++) {
+ value[i] = atof(keys[i].value);
+ present[i] = 0;
+ }
+
+ buff_init(&buffer);
+ buff_add(&buffer, "@beginspecial ", 0);
+
+ quoted = 0;
+ while(*ptr) {
+ const char *keyname;
+ char *val;
+ char *p;
+
+ while(*ptr == ' ' || *ptr == '\t')
+ ptr++;
+ keyname = ptr;
+
+ /* get the whole key=value pair */
+ for(; *ptr && *ptr != ' ' && *ptr != '\t'; ptr++);
+
+ if(*ptr) *ptr++ = 0;
+ /* now we shouldn't touch `ptr' anymore */
+
+ /* now work on this pair */
+ p = strchr(keyname, '=');
+ if(p == NULL)
+ val = NULL;
+ else {
+ *p++ = 0;
+ if(*p == '"') {
+ val = ++p;
+ /* skip until closing quote */
+ while(*p && *p != '"')
+ p++;
+ if(*p != '"')
+ warning(
+ _("%s: malformed value for key `%s'\n"),
+ filename, keyname);
+ } else
+ val = p;
+ }
+
+ /* lookup the key */
+ for(i = 0; i < NKEYS; i++)
+ if(STRCEQ(keys[i].name, keyname))
+ break;
+ if(i == NKEYS) {
+ warning(_("%s: unknown key `%s' ignored\n"),
+ filename, keyname);
+ continue;
+ }
+ if(keys[i].has_arg && val == NULL) {
+ warning(_("%s: no argument for key `%s', using defaults\n"),
+ filename, keyname);
+ val = keys[i].value;
+ } else if(!keys[i].has_arg && val) {
+ warning(_("%s: argument `%s' ignored for key `%s'\n"),
+ filename, val, keyname);
+ val = NULL;
+ }
+ if(val)
+ value[i] = atof(val);
+
+ /* put the argument */
+ buff_add(&buffer, val, 0);
+ buff_add(&buffer, " @", 2);
+ buff_add(&buffer, keyname, 0);
+ buff_add(&buffer, " ", 1);
+
+ /* remember that this option was given */
+ present[i] = 0xff;
+ }
+ buff_add(&buffer, " @setspecial", 0);
+
+ /* now compute the bounding box (code comes from dvips) */
+ originx = 0;
+ originy = 0;
+ hscale = 1;
+ vscale = 1;
+ hsize = 0;
+ vsize = 0;
+
+ if(present[HSIZE])
+ hsize = value[HSIZE];
+ if(present[VSIZE])
+ vsize = value[VSIZE];
+ if(present[HOFF])
+ originx = value[HOFF];
+ if(present[VOFF])
+ originy = value[VOFF];
+ if(present[HSCALE])
+ hscale = value[HSCALE] / 100.0;
+ if(present[VSCALE])
+ vscale = value[VSCALE] / 100.0;
+ if(present[URX] && present[LLX])
+ hsize = value[URX] - value[LLX];
+ if(present[URY] && present[LLY])
+ vsize = value[URY] - value[LLY];
+ if(present[RWI] || present[RHI]) {
+ if(present[RWI] && !present[RHI])
+ hscale = vscale = value[RWI] / (10.0 * hsize);
+ else if(present[RHI] && !present[RWI])
+ hscale = vscale = value[RHI] / (10.0 * vsize);
+ else {
+ hscale = value[RWI] / (10.0 * hsize);
+ vscale = value[RHI] / (10.0 * vsize);
+ }
+ }
+
+ box->ox = originx;
+ box->oy = originy;
+ box->bw = hsize * hscale;
+ box->bh = vsize * vscale;
+ box->angle = value[ANGLE];
+
+ *ret = buffer.data;
+
+ return filename;
+}
+
+void epsf_special(DviContext *dvi, char *prefix, char *arg)
+{
+ char *file;
+ char *special;
+ EpsfBox box;
+ int x, y;
+ int w, h;
+ double xf, vf;
+
+ file = parse_epsf_special(&box, &special, prefix, arg);
+ if(file != NULL)
+ xfree(special);
+ /*
+ * draw the bounding box. Notice that it is in PostScript units,
+ * so we have to convert it into pixels
+ */
+ xf = dvi->params.dpi * dvi->params.mag / (72.0 * dvi->params.hshrink);
+ vf = dvi->params.vdpi * dvi->params.mag / (72.0 * dvi->params.vshrink);
+ x = FROUND(box.ox * xf);
+ y = FROUND(box.oy * vf);
+ w = FROUND(box.bw * xf);
+ h = FROUND(box.bh * vf);
+ dvi->device.draw_rule(dvi, dvi->pos.hh + x, dvi->pos.vv + y - h + 1, w, h, 0);
+}
diff --git a/dviware/mdvi/lib/special.c b/dviware/mdvi/lib/special.c
new file mode 100644
index 0000000000..7188bd8ed5
--- /dev/null
+++ b/dviware/mdvi/lib/special.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+#if defined(WITH_REGEX_SPECIALS) && defined(HAVE_REGEX_H)
+#include <regex.h>
+#endif
+
+typedef struct _DviSpecial {
+ struct _DviSpecial *next;
+ struct _DviSpecial *prev;
+ char *label;
+ char *prefix;
+ size_t plen;
+#ifdef WITH_REGEX_SPECIALS
+ regex_t reg;
+ int has_reg;
+#endif
+ DviSpecialHandler handler;
+} DviSpecial;
+
+static ListHead specials = {NULL, NULL, 0};
+
+#define SPECIAL(x) \
+ void x __PROTO((DviContext *, const char *, const char *))
+
+static SPECIAL(sp_layer);
+extern SPECIAL(epsf_special);
+extern SPECIAL(do_color_special);
+
+static struct {
+ char *label;
+ char *prefix;
+ char *regex;
+ DviSpecialHandler handler;
+} builtins[] = {
+ {"Layers", "layer", NULL, sp_layer},
+ {"EPSF", "psfile", NULL, epsf_special}
+};
+#define NSPECIALS (sizeof(builtins) / sizeof(builtins[0]))
+static int registered_builtins = 0;
+
+static void register_builtin_specials(void)
+{
+ int i;
+
+ ASSERT(registered_builtins == 0);
+ for(i = 0; i < NSPECIALS; i++)
+ mdvi_register_special(
+ builtins[i].label,
+ builtins[i].prefix,
+ builtins[i].regex,
+ builtins[i].handler,
+ 1 /* replace if exists */);
+ registered_builtins = 1;
+}
+
+static DviSpecial *find_special_prefix(const char *prefix)
+{
+ DviSpecial *sp;
+
+ /* should have a hash table here, but I'm so lazy */
+ for(sp = (DviSpecial *)specials.head; sp; sp = sp->next) {
+ if(STRCEQ(sp->prefix, prefix))
+ break;
+ }
+ return sp;
+}
+
+int mdvi_register_special(const char *label, const char *prefix,
+ const char *regex, DviSpecialHandler handler, int replace)
+{
+ DviSpecial *sp;
+ int newsp = 0;
+
+ if(!registered_builtins)
+ register_builtin_specials();
+
+ sp = find_special_prefix(prefix);
+ if(sp == NULL) {
+ sp = xalloc(DviSpecial);
+ sp->prefix = xstrdup(prefix);
+ newsp = 1;
+ } else if(!replace)
+ return -1;
+ else {
+ xfree(sp->label);
+ sp->label = NULL;
+ }
+
+#ifdef WITH_REGEX_SPECIALS
+ if(!newsp && sp->has_reg) {
+ regfree(&sp->reg);
+ sp->has_reg = 0;
+ }
+ if(regex && regcomp(&sp->reg, regex, REG_NOSUB) != 0) {
+ if(newsp) {
+ xfree(sp->prefix);
+ xfree(sp);
+ }
+ return -1;
+ }
+ sp->has_reg = (regex != NULL);
+#endif
+ sp->handler = handler;
+ sp->label = xstrdup(label);
+ sp->plen = strlen(prefix);
+ if(newsp)
+ listh_prepend(&specials, LIST(sp));
+ DEBUG((DBG_SPECIAL,
+ "New \\special handler `%s' with prefix `%s'\n",
+ label, prefix));
+ return 0;
+}
+
+int mdvi_unregister_special(const char *prefix)
+{
+ DviSpecial *sp;
+
+ sp = find_special_prefix(prefix);
+ if(sp == NULL)
+ return -1;
+ xfree(sp->prefix);
+#ifdef WITH_REGEX_SPECIALS
+ if(sp->has_reg)
+ regfree(&sp->reg);
+#endif
+ listh_remove(&specials, LIST(sp));
+ xfree(sp);
+ return 0;
+}
+
+#define IS_PREFIX_DELIMITER(x) (strchr(" \t\n:=", (x)) != NULL)
+
+int mdvi_do_special(DviContext *dvi, char *string)
+{
+ char *prefix;
+ char *ptr;
+ DviSpecial *sp;
+
+ if(!registered_builtins) {
+ }
+
+ if(!string || !*string)
+ return 0;
+
+ /* skip leading spaces */
+ while(*string && isspace(*string))
+ string++;
+
+ DEBUG((DBG_SPECIAL, "Looking for a handler for `%s'\n", string));
+
+ /* now try to find a match */
+ ptr = string;
+ for(sp = (DviSpecial *)specials.head; sp; sp = sp->next) {
+#ifdef WITH_REGEX_SPECIALS
+ if(sp->has_reg && !regexec(&sp->reg, ptr, 0, 0, 0))
+ break;
+#endif
+ /* check the prefix */
+ if(STRNCEQ(sp->prefix, ptr, sp->plen)) {
+ ptr += sp->plen;
+ break;
+ }
+ }
+
+ if(sp == NULL) {
+ DEBUG((DBG_SPECIAL, "None found\n"));
+ return -1;
+ }
+
+ /* extract the prefix */
+ if(ptr == string) {
+ prefix = NULL;
+ DEBUG((DBG_SPECIAL,
+ "REGEX match with `%s' (arg `%s')\n",
+ sp->label, ptr));
+ } else {
+ if(*ptr) *ptr++ = 0;
+ prefix = string;
+ DEBUG((DBG_SPECIAL,
+ "PREFIX match with `%s' (prefix `%s', arg `%s')\n",
+ sp->label, prefix, ptr));
+ }
+
+ /* invoke the handler */
+ sp->handler(dvi, prefix, ptr);
+
+ return 0;
+}
+
+void mdvi_flush_specials(void)
+{
+ DviSpecial *sp, *list;
+
+
+ for(list = (DviSpecial *)specials.head; (sp = list); ) {
+ list = sp->next;
+ if(sp->prefix) xfree(sp->prefix);
+ if(sp->label) xfree(sp->label);
+#ifdef WITH_REGEX_SPECIALS
+ if(sp->has_reg)
+ regfree(&sp->reg);
+#endif
+ xfree(sp);
+ }
+ specials.head = NULL;
+ specials.tail = NULL;
+ specials.count = 0;
+}
+
+/* some builtin specials */
+
+void sp_layer(DviContext *dvi, const char *prefix, const char *arg)
+{
+ if(STREQ("push", arg))
+ dvi->curr_layer++;
+ else if(STREQ("pop", arg)) {
+ if(dvi->curr_layer)
+ dvi->curr_layer--;
+ else
+ warning(_("%s: tried to pop top level layer\n"),
+ dvi->filename);
+ } else if(STREQ("reset", arg))
+ dvi->curr_layer = 0;
+ DEBUG((DBG_SPECIAL, "Layer level: %d\n", dvi->curr_layer));
+}
+
diff --git a/dviware/mdvi/lib/t1.c b/dviware/mdvi/lib/t1.c
new file mode 100644
index 0000000000..bc2900b204
--- /dev/null
+++ b/dviware/mdvi/lib/t1.c
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Type1 font support for MDVI
+ *
+ * We use T1lib only as a rasterizer, not to draw glyphs.
+ */
+
+#include "mdvi.h"
+
+#ifdef WITH_TYPE1_FONTS
+
+#include <stdio.h>
+#include <t1lib.h>
+#include "private.h"
+
+static int t1lib_initialized = 0;
+
+typedef struct t1info {
+ struct t1info *next;
+ struct t1info *prev;
+ char *fontname; /* (short) name of this font */
+ int t1id; /* T1lib's id for this font */
+ int hasmetrics; /* have we processed this font? */
+ TFMInfo *tfminfo; /* TFM data is shared */
+ DviFontMapInfo mapinfo;
+ DviEncoding *encoding;
+} T1Info;
+
+static void t1_font_remove __PROTO((T1Info *));
+static int t1_load_font __PROTO((DviParams *, DviFont *));
+static int t1_font_get_glyph __PROTO((DviParams *, DviFont *, int));
+static void t1_font_shrink_glyph
+ __PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
+static void t1_free_data __PROTO((DviFont *));
+static void t1_reset_font __PROTO((DviFont *));
+static char *t1_lookup_font __PROTO((const char *, Ushort *, Ushort *));
+
+/* only symbol exported by this file */
+DviFontInfo t1_font_info = {
+ "Type1",
+ 1, /* scaling supported by format */
+ t1_load_font,
+ t1_font_get_glyph,
+ t1_font_shrink_glyph,
+ mdvi_shrink_glyph_grey,
+ t1_free_data,
+ t1_reset_font,
+ t1_lookup_font, /* lookup */
+ kpse_type1_format,
+ NULL
+};
+
+/* this seems good enough for most DVI files */
+#define T1_HASH_SIZE 31
+
+/* If these parameters change, we must delete all size information
+ * in all fonts, and reset the device resolutions in T1lib */
+static int t1lib_xdpi = -1;
+static int t1lib_ydpi = -1;
+
+static ListHead t1fonts = {NULL, NULL, 0};
+static DviHashTable t1hash;
+
+/* Type1 fonts need their own `lookup' function. Here is how it works:
+ * First we try to find the font by its given name. If that fails, we
+ * query the font maps. A typical font map entry may contain the line
+ *
+ * ptmr8rn Times-Roman ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <ptmr
+ *
+ * which means: If you're looking for the font `ptmr8rn' load `Times-Roman'
+ * which is in `ptmr' instead, and extend it by 0.82 points, then reencode
+ * it with the vector TeXBase1Encoding from the file `8r.enc'. This will
+ * fail if the entry looks like this:
+ *
+ * ptmr8rn Times-Roman ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc
+ *
+ * because to deal with this we would need to be able to locate the font file
+ * for the `Times-Roman' font ourselves, and that's beyond the scope of mdvi.
+ * But hey, we tried hard.
+ */
+char *t1_lookup_font(const char *name, Ushort *hdpi, Ushort *vdpi)
+{
+ char *filename;
+ char *newname;
+ const char *ext;
+ DviFontMapInfo info;
+
+ DEBUG((DBG_TYPE1, "(t1) looking for `%s'\n", name));
+
+ /* first let's try the font we were asked for */
+ filename = kpse_find_file(name, kpse_type1_format, 1);
+ if(filename != NULL) {
+ /* we got it */
+ return filename;
+ }
+
+ DEBUG((DBG_TYPE1, "(t1) %s: not found, querying font maps\n", name));
+ /* now query the fontmap */
+ if(mdvi_query_fontmap(&info, name) < 0) {
+ /* it's not there either */
+ return NULL;
+ }
+
+ /* check what we got */
+ if(info.fullfile) {
+ DEBUG((DBG_TYPE1, "(t1) %s: found `%s' (cached)\n",
+ name, info.fullfile));
+ /* this is a cached lookup */
+ return xstrdup(info.fullfile);
+ }
+
+ /* no file associated to this font? */
+ if(info.fontfile == NULL)
+ return info.psname ? mdvi_ps_find_font(info.psname) : NULL;
+
+ /* let's extract the extension */
+ ext = file_extension(info.fontfile);
+ if(ext && !STREQ(ext, "pfa") && !STREQ(ext, "pfb")) {
+ DEBUG((DBG_TYPE1,
+ "(t1) %s: associated name `%s' is not Type1\n",
+ name, info.fontfile));
+ /* it's not a Type1 font */
+ return NULL;
+ }
+
+ /* get the `base' name */
+ if(ext) {
+ newname = xstrdup(name);
+ newname[ext - info.fontfile - 1] = 0;
+ } else
+ newname = (char *)name; /* we don't modify this */
+
+ /* look it up */
+ DEBUG((DBG_TYPE1, "(t1) looking for `%s' on behalf of `%s'\n",
+ newname, name));
+ filename = kpse_find_file(newname, kpse_type1_format, 1);
+
+ /* we don't need this anymore */
+ if(newname != name)
+ xfree(newname);
+ if(filename == NULL) {
+ DEBUG((DBG_TYPE1, "(t1) %s: not found\n", name));
+ return NULL;
+ }
+
+ DEBUG((DBG_TYPE1, "(t1) %s: found as `%s'\n", name, filename));
+ /* got it! let's remember this */
+ mdvi_add_fontmap_file(name, filename);
+ return filename;
+}
+
+static void t1_reset_resolution(int xdpi, int ydpi)
+{
+ int i;
+ int nfonts;
+
+ DEBUG((DBG_TYPE1, "(t1) resetting device resolution (current: (%d,%d))\n",
+ t1lib_xdpi, t1lib_ydpi));
+
+ nfonts = T1_Get_no_fonts();
+ for(i = 0; i < nfonts; i++)
+ T1_DeleteAllSizes(i);
+ /* reset device resolutions */
+ if(T1_SetDeviceResolutions((float)xdpi, (float)ydpi) < 0)
+ warning(_("(t1) failed to reset device resolution\n"));
+ else
+ DEBUG((DBG_TYPE1,
+ "(t1) reset successful, new resolution is (%d, %d)\n",
+ xdpi, ydpi));
+ t1lib_xdpi = xdpi;
+ t1lib_ydpi = ydpi;
+}
+
+static void t1_reset_font(DviFont *font)
+{
+ T1Info *info = (T1Info *)font->private;
+
+ if(info == NULL)
+ return;
+ DEBUG((DBG_FONTS, "(t1) resetting font `%s'\n", font->fontname));
+ /* just mark the font as not having metric info. It will be reset
+ * automatically later */
+ info->hasmetrics = 0;
+}
+
+static void t1_transform_font(T1Info *info)
+{
+ if(!info->hasmetrics && info->encoding != NULL) {
+ DEBUG((DBG_TYPE1, "(t1) %s: encoding with vector `%s'\n",
+ info->fontname, info->encoding->name));
+ T1_DeleteAllSizes(info->t1id);
+ if(T1_ReencodeFont(info->t1id, info->encoding->vector) < 0)
+ warning(_("%s: could not encode font\n"), info->fontname);
+ }
+ if(info->mapinfo.slant) {
+ DEBUG((DBG_TYPE1, "(t1) %s: slanting by %.3f\n",
+ info->fontname,
+ MDVI_FMAP_SLANT(&info->mapinfo)));
+ T1_SlantFont(info->t1id,
+ MDVI_FMAP_SLANT(&info->mapinfo));
+ }
+ if(info->mapinfo.extend) {
+ DEBUG((DBG_TYPE1, "(t1) %s: extending by %.3f\n",
+ info->fontname,
+ MDVI_FMAP_EXTEND(&info->mapinfo)));
+ T1_ExtendFont(info->t1id,
+ MDVI_FMAP_EXTEND(&info->mapinfo));
+ }
+}
+
+/* if this function is called, we really need this font */
+static int t1_really_load_font(DviParams *params, DviFont *font, T1Info *info)
+{
+ int i;
+ T1Info *old;
+ int t1id;
+ int copied;
+ int status;
+
+ DEBUG((DBG_TYPE1, "(t1) really_load_font(%s)\n", info->fontname));
+
+ /* if the parameters changed, reset T1lib */
+ if(t1lib_xdpi != params->dpi || t1lib_ydpi != params->vdpi)
+ t1_reset_resolution(params->dpi, params->vdpi);
+
+ /* if we already have a T1lib id, do nothing */
+ if(info->t1id != -1) {
+ info->hasmetrics = 1;
+ /* apply slant and extend again */
+ t1_transform_font(info);
+ return 0;
+ }
+
+ /* before we even attempt to load the font, make sure we have metric
+ * data for it */
+ info->tfminfo = mdvi_ps_get_metrics(info->fontname);
+ if(info->tfminfo == NULL) {
+ DEBUG((DBG_FONTS,
+ "(t1) %s: no metric data, font ignored\n",
+ info->fontname));
+ goto t1_error;
+ }
+ /* fix this */
+ font->design = info->tfminfo->design;
+
+ /* check if we have a font with this name (maybe at a different size) */
+ old = (T1Info *)mdvi_hash_lookup(&t1hash, info->fontname);
+ if(old == info) {
+ /* let's avoid confusion */
+ old = NULL;
+ }
+ if(old && old->t1id != -1) {
+ /* let's take advantage of T1lib's font sharing */
+ t1id = T1_CopyFont(old->t1id);
+ DEBUG((DBG_TYPE1, "(t1) %s -> %d (CopyFont)\n",
+ info->fontname, t1id));
+ copied = 1;
+ } else {
+ t1id = T1_AddFont(font->filename);
+ DEBUG((DBG_TYPE1, "(t1) %s -> %d (AddFont)\n",
+ info->fontname, t1id));
+ copied = 0;
+ }
+ if(t1id < 0)
+ goto t1_error;
+ info->t1id = t1id;
+
+ /*
+ * a minor optimization: If the old font in the hash table has
+ * not been loaded yet, replace it by this one, so we can use
+ * CopyFont later.
+ */
+ if(old && old->t1id == -1) {
+ DEBUG((DBG_TYPE1, "(t1) font `%s' exchanged in hash table\n",
+ info->fontname));
+ mdvi_hash_remove(&t1hash, old->fontname);
+ mdvi_hash_add(&t1hash, info->fontname,
+ info, MDVI_HASH_UNCHECKED);
+ }
+
+ /* now let T1lib load it */
+ if(!copied && T1_LoadFont(info->t1id) < 0) {
+ DEBUG((DBG_TYPE1, "(t1) T1_LoadFont(%d) failed with error %d\n",
+ info->t1id, T1_errno));
+ goto t1_error;
+ }
+ DEBUG((DBG_TYPE1, "(t1) T1_LoadFont(%d) -> Ok\n", info->t1id));
+
+ /* get information from the fontmap */
+ status = mdvi_query_fontmap(&info->mapinfo, info->fontname);
+ if(!status && info->mapinfo.encoding)
+ info->encoding = mdvi_request_encoding(info->mapinfo.encoding);
+ t1_transform_font(info);
+
+ i = info->tfminfo->hic - info->tfminfo->loc + 1;
+ if(i != font->hic - font->loc + 1) {
+ /* reset to optimal size */
+ font->chars = xrealloc(font->chars, i * sizeof(DviFontChar));
+ }
+
+ /* get the scaled characters metrics */
+ get_tfm_chars(params, font, info->tfminfo, 0);
+ info->hasmetrics = 1;
+
+ DEBUG((DBG_TYPE1, "(t1) font `%s' really-loaded\n", info->fontname));
+ return 0;
+
+t1_error:
+ /* some error does not allows us to use this font. We need to reset
+ * the font structure, so the font system can try to read this
+ * font in a different class */
+
+ /* first destroy the private data */
+ t1_font_remove(info);
+ /* now reset all chars -- this is the important part */
+ xfree(font->chars);
+ font->chars = NULL;
+ font->loc = font->hic = 0;
+ return -1;
+}
+
+static int init_t1lib(DviParams *params)
+{
+ int t1flags;
+
+#ifdef WORD_LITTLE_ENDIAN
+ /* try making T1lib use bitmaps in our format, but if this
+ * fails we'll convert the bitmap ourselves */
+ T1_SetBitmapPad(BITMAP_BITS);
+#endif
+ T1_SetDeviceResolutions((float)params->dpi, (float)params->vdpi);
+ t1flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE|T1_NO_AFM;
+ if(DEBUGGING(TYPE1))
+ t1flags |= LOGFILE;
+ if(T1_InitLib(t1flags) == NULL)
+ return (t1lib_initialized = -1);
+ if(DEBUGGING(TYPE1)) {
+ DEBUG((DBG_TYPE1, "T1lib debugging output saved in t1lib.log\n"));
+ T1_SetLogLevel(T1LOG_DEBUG);
+ }
+ /* initialize our hash table, but don't allocate memory for it
+ * until we use it */
+ mdvi_hash_init(&t1hash);
+ DEBUG((DBG_TYPE1, "(t1) t1lib %s initialized -- resolution is (%d, %d), pad is %d bits\n",
+ T1_GetLibIdent(), params->dpi, params->vdpi, T1_GetBitmapPad()));
+ t1lib_initialized = 1;
+ t1lib_xdpi = params->dpi;
+ t1lib_ydpi = params->vdpi;
+ return 0;
+}
+
+static int t1_load_font(DviParams *params, DviFont *font)
+{
+ T1Info *info;
+ int i;
+
+ if(t1lib_initialized < 0)
+ return -1;
+ else if(t1lib_initialized == 0 && init_t1lib(params) < 0)
+ return -1;
+
+ if(font->in != NULL) {
+ /* we don't need this */
+ fclose(font->in);
+ font->in = NULL;
+ }
+
+ info = xalloc(T1Info);
+
+ /*
+ * mark the font as `unregistered' with T1lib. It will
+ * be added when we actually use it
+ */
+ info->t1id = -1;
+
+ /* add the font to our list */
+ info->fontname = font->fontname;
+ info->hasmetrics = 0;
+ info->encoding = NULL;
+ info->mapinfo.psname = NULL;
+ info->mapinfo.encoding = NULL;
+ info->mapinfo.fontfile = NULL;
+ info->mapinfo.extend = 0;
+ info->mapinfo.slant = 0;
+ info->encoding = NULL;
+
+ /* create the hash table if we have not done so yet */
+ if(t1hash.nbucks == 0)
+ mdvi_hash_create(&t1hash, T1_HASH_SIZE);
+ mdvi_hash_add(&t1hash, info->fontname, info, MDVI_HASH_UNIQUE);
+ listh_append(&t1fonts, LIST(info));
+
+ font->private = info;
+
+ /* reset everything */
+ font->chars = xnalloc(DviFontChar, 256);
+ font->loc = 0;
+ font->hic = 255;
+ for(i = 0; i < 256; i++) {
+ font->chars[i].code = i;
+ font->chars[i].offset = 1;
+ font->chars[i].loaded = 0;
+ font->chars[i].glyph.data = NULL;
+ font->chars[i].shrunk.data = NULL;
+ font->chars[i].grey.data = NULL;
+ }
+
+ return 0;
+}
+
+#define GLYPH_WIDTH(g) \
+ ((g)->metrics.rightSideBearing - (g)->metrics.leftSideBearing)
+#define GLYPH_HEIGHT(g) \
+ ((g)->metrics.ascent - (g)->metrics.descent)
+
+static inline BITMAP *t1_glyph_bitmap(GLYPH *glyph)
+{
+ BITMAP *bm;
+ int w, h;
+
+ w = GLYPH_WIDTH(glyph);
+ h = GLYPH_HEIGHT(glyph);
+
+ if(!w || !h)
+ return MDVI_GLYPH_EMPTY;
+ switch(glyph->bpp << 3) {
+ case 8:
+ bm = bitmap_convert_lsb8(glyph->bits, w, h);
+ break;
+ default:
+ warning(_("(t1) unsupported bitmap pad size %d\n"),
+ glyph->bpp);
+ bm = MDVI_GLYPH_EMPTY;
+ break;
+ }
+ return bm;
+}
+
+static void t1_font_shrink_glyph(DviContext *dvi, DviFont *font, DviFontChar *ch, DviGlyph *dest)
+{
+ double size;
+ GLYPH *glyph;
+ T1Info *info;
+ T1_TMATRIX matrix;
+
+ info = (T1Info *)font->private;
+ ASSERT(info != NULL);
+
+ DEBUG((DBG_TYPE1, "(t1) shrinking glyph for character %d in `%s' (%d,%d)\n",
+ ch->code, font->fontname, ch->width, ch->height));
+ size = (double)font->scale / (dvi->params.tfm_conv * 0x100000);
+ size = 72.0 * size / 72.27;
+ matrix.cxx = 1.0/(double)dvi->params.hshrink;
+ matrix.cyy = 1.0/(double)dvi->params.vshrink;
+ matrix.cxy = 0.0;
+ matrix.cyx = 0.0;
+ glyph = T1_SetChar(info->t1id, ch->code, (float)size, &matrix);
+
+ dest->data = t1_glyph_bitmap(glyph);
+ dest->x = -glyph->metrics.leftSideBearing;
+ dest->y = glyph->metrics.ascent;
+ dest->w = GLYPH_WIDTH(glyph);
+ dest->h = GLYPH_HEIGHT(glyph);
+
+#ifndef NODEBUG
+ if(DEBUGGING(BITMAP_DATA)) {
+ DEBUG((DBG_BITMAP_DATA,
+ "(t1) %s: t1_shrink_glyph(%d): (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
+ ch->glyph.w, ch->glyph.h, ch->glyph.x, ch->glyph.y,
+ dest->w, dest->h, dest->x, dest->y));
+ bitmap_print(stderr, (BITMAP *)dest->data);
+ }
+#endif
+ /* transform the glyph - we could do this with t1lib, but we do
+ * it ourselves for now */
+ font_transform_glyph(dvi->params.orientation, dest);
+}
+
+static int t1_font_get_glyph(DviParams *params, DviFont *font, int code)
+{
+ T1Info *info = (T1Info *)font->private;
+ GLYPH *glyph;
+ DviFontChar *ch;
+ double size;
+ T1_TMATRIX matrix;
+ int dpi;
+
+ ASSERT(info != NULL);
+ if(!info->hasmetrics && t1_really_load_font(params, font, info) < 0)
+ return -1;
+ ch = FONTCHAR(font, code);
+ if(!ch || !glyph_present(ch))
+ return -1;
+ ch->loaded = 1;
+ if(!ch->width || !ch->height) {
+ ch->glyph.x = ch->x;
+ ch->glyph.y = ch->y;
+ ch->glyph.w = ch->width;
+ ch->glyph.h = ch->height;
+ ch->glyph.data = NULL;
+ return 0;
+ }
+
+ /* load the glyph with T1lib (this is done only once for each glyph) */
+
+ /* get size in TeX points (tfm_conv includes dpi and magnification) */
+ size = (double)font->scale / (params->tfm_conv * 0x100000);
+ /* and transform into PostScript points */
+ size = 72.0 * size / 72.27;
+
+ dpi = Max(font->hdpi, font->vdpi);
+ /* we don't want the glyph to be cached twice (once by us, another by
+ * T1lib), so we use an identity matrix to tell T1lib not to keep the
+ * glyph around */
+ matrix.cxx = (double)font->hdpi / dpi;
+ matrix.cyy = (double)font->vdpi / dpi;
+ matrix.cxy = matrix.cyx = 0.0;
+ glyph = T1_SetChar(info->t1id, ch->code, (float)size, &matrix);
+ if(glyph == NULL) {
+ ch->glyph.x = ch->x;
+ ch->glyph.y = ch->y;
+ ch->glyph.w = ch->width;
+ ch->glyph.h = ch->height;
+ ch->glyph.data = NULL;
+ ch->missing = 1;
+ return 0;
+ }
+ /* and make it a bitmap */
+ ch->glyph.data = t1_glyph_bitmap(glyph);
+ ch->glyph.x = -glyph->metrics.leftSideBearing;
+ ch->glyph.y = glyph->metrics.ascent;
+ ch->glyph.w = GLYPH_WIDTH(glyph);
+ ch->glyph.h = GLYPH_HEIGHT(glyph);
+
+ /* let's also fix the glyph's origin
+ * (which is not contained in the TFM) */
+ ch->x = ch->glyph.x;
+ ch->y = ch->glyph.y;
+ /* let's fix these too */
+ ch->width = ch->glyph.w;
+ ch->height = ch->glyph.h;
+
+ return 0;
+}
+
+static void t1_font_remove(T1Info *info)
+{
+ T1Info *old;
+
+ /* first remove it from our list */
+ listh_remove(&t1fonts, LIST(info));
+
+ /* it it's in the hash table, we may need to replace this by another font */
+ old = (T1Info *)mdvi_hash_lookup(&t1hash, info->fontname);
+ if(old == info) {
+ mdvi_hash_remove(&t1hash, info->fontname);
+ /* go through the list and see if there is another
+ * font with this name */
+ for(old = (T1Info *)t1fonts.head; old; old = old->next)
+ if(STREQ(old->fontname, info->fontname))
+ break;
+ if(old != NULL)
+ mdvi_hash_add(&t1hash, old->fontname, old,
+ MDVI_HASH_UNCHECKED);
+ }
+ /* release our encoding vector */
+ if(info->encoding) {
+ DEBUG((DBG_TYPE1, "(t1) %s: releasing vector `%s'\n",
+ info->fontname, info->encoding->name));
+ mdvi_release_encoding(info->encoding, 1);
+ }
+
+ /* now get rid of it */
+ if(info->t1id != -1) {
+ DEBUG((DBG_TYPE1, "(t1) %s: T1_DeleteFont(%d)\n",
+ info->fontname, info->t1id));
+ T1_DeleteFont(info->t1id);
+ } else
+ DEBUG((DBG_TYPE1, "(t1) %s: not loaded yet, DeleteFont skipped\n",
+ info->fontname));
+
+ if(info->tfminfo)
+ free_font_metrics(info->tfminfo);
+ /*xfree(info->fontname);*/
+ xfree(info);
+}
+
+static void t1_free_data(DviFont *font)
+{
+ /* called after all the glyphs are destroyed */
+
+ if(font->private == NULL) {
+ /* this is perfectly normal, it just means the font has
+ * not been requested by MDVI yet */
+ return;
+ }
+
+ /* destroy this data */
+
+ t1_font_remove((T1Info *)font->private);
+ font->private = NULL;
+
+ /*
+ * if this is the last T1 font, reset the T1 library
+ * It is important that we do this, because this is will be called
+ * when the resolution or the magnification changes.
+ */
+ if(t1fonts.count == 0) {
+ DEBUG((DBG_TYPE1, "(t1) last font removed -- closing T1lib\n"));
+ T1_CloseLib();
+ t1lib_initialized = 0;
+ t1lib_xdpi = -1;
+ t1lib_ydpi = -1;
+ }
+}
+
+#endif /* WITH_TYPE1_FONTS */
diff --git a/dviware/mdvi/lib/tfm.c b/dviware/mdvi/lib/tfm.c
new file mode 100644
index 0000000000..6cc82abf1d
--- /dev/null
+++ b/dviware/mdvi/lib/tfm.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+static int tfm_load_font __PROTO((DviParams *, DviFont *));
+static int tfm_font_get_glyph __PROTO((DviParams *, DviFont *, int));
+
+DviFontInfo tfm_font_info = {
+ "TFM",
+ 0, /* scaling not supported by format */
+ tfm_load_font,
+ tfm_font_get_glyph,
+ mdvi_shrink_box,
+ mdvi_shrink_box,
+ NULL, /* free */
+ NULL, /* reset */
+ NULL, /* lookup */
+ kpse_tfm_format,
+ NULL
+};
+
+DviFontInfo ofm_font_info = {
+ "OFM",
+ 0, /* scaling not supported by format */
+ tfm_load_font,
+ tfm_font_get_glyph,
+ mdvi_shrink_box,
+ mdvi_shrink_box,
+ NULL, /* free */
+ NULL, /* reset */
+ NULL, /* lookup */
+ kpse_ofm_format,
+ NULL
+};
+
+DviFontInfo afm_font_info = {
+ "AFM",
+ 0, /* scaling not supported by format */
+ tfm_load_font,
+ tfm_font_get_glyph,
+ mdvi_shrink_box,
+ mdvi_shrink_box,
+ NULL, /* free */
+ NULL, /* reset */
+ NULL, /* lookup */
+ kpse_afm_format,
+ NULL
+};
+
+#define TYPENAME(font) \
+ ((font)->search.info ? (font)->search.info : "none")
+
+/*
+ * Although it does not seem that way, this conversion is independent of the
+ * shrinking factors, within roundoff (that's because `conv' and `vconv'
+ * have already been scaled by hshrink and vshrink, repsectively). We
+ * should really use `dviconv' and `dvivconv', but I'm not so sure those
+ * should be moved to the DviParams structure.
+ */
+#define XCONV(x) FROUND(params->conv * (x) * params->hshrink)
+#define YCONV(y) FROUND(params->vconv * (y) * params->vshrink)
+
+/* this is used quite often in several places, so I made it standalone */
+int get_tfm_chars(DviParams *params, DviFont *font, TFMInfo *info, int loaded)
+{
+ Int32 z, alpha, beta;
+ int n;
+ DviFontChar *ch;
+ TFMChar *ptr;
+
+ n = info->hic - info->loc + 1;
+ if(n != FONT_GLYPH_COUNT(font)) {
+ font->chars = xrealloc(font->chars,
+ n * sizeof(DviFontChar));
+ }
+ font->loc = info->loc;
+ font->hic = info->hic;
+ ch = font->chars;
+ ptr = info->chars;
+
+ /* Prepare z, alpha and beta for TFM width computation */
+ TFMPREPARE(font->scale, z, alpha, beta);
+
+ /* get the character metrics */
+ for(n = info->loc; n <= info->hic; ch++, ptr++, n++) {
+ int a, b, c, d;
+
+ ch->offset = ptr->present;
+ if(ch->offset == 0)
+ continue;
+ /* this is what we came here for */
+ ch->tfmwidth = TFMSCALE(z, ptr->advance, alpha, beta);
+ /* scale all other TFM units (so they are in DVI units) */
+ a = TFMSCALE(z, ptr->left, alpha, beta);
+ b = TFMSCALE(z, ptr->right, alpha, beta);
+ c = TFMSCALE(z, ptr->height, alpha, beta);
+ d = TFMSCALE(z, ptr->depth, alpha, beta);
+
+ /* now convert to unscaled pixels */
+ ch->width = XCONV(b - a);
+ ch->height = YCONV(c - d);
+ if(ch->height < 0) ch->height = -ch->height;
+ ch->x = XCONV(a);
+ ch->y = YCONV(c);
+ /*
+ * the offset is not used, but we might as well set it to
+ * something meaningful (and it MUST be non-zero)
+ */
+ ch->flags = 0;
+ ch->code = n;
+ ch->glyph.data = NULL;
+ ch->grey.data = NULL;
+ ch->shrunk.data = NULL;
+ ch->loaded = loaded;
+ }
+
+ return 0;
+}
+
+/*
+ * We use this function as a last resort to find the character widths in a
+ * font The DVI rendering code can correctly skip over a glyph if it knows
+ * its TFM width, which is what we try to find here.
+ */
+static int tfm_load_font(DviParams *params, DviFont *font)
+{
+ TFMInfo *tfm;
+ int type;
+
+ switch(font->search.info->kpse_type) {
+ case kpse_tfm_format:
+ type = DviFontTFM;
+ break;
+ case kpse_afm_format:
+ type = DviFontAFM;
+ break;
+ case kpse_ofm_format:
+ type = DviFontOFM;
+ break;
+ default:
+ return -1;
+ }
+
+ /* we don't need this */
+ if(font->in) {
+ fclose(font->in);
+ font->in = NULL;
+ }
+ tfm = get_font_metrics(font->fontname, type, font->filename);
+ if(tfm == NULL)
+ return -1;
+
+ if(tfm->checksum && font->checksum && tfm->checksum != font->checksum) {
+ warning(_("%s: Checksum mismatch (got %u, expected %u)\n"),
+ font->fontname, (unsigned)tfm->checksum,
+ (unsigned)font->checksum);
+ }
+ font->checksum = tfm->checksum;
+ font->design = tfm->design;
+ font->loc = 0;
+ font->hic = 0;
+ font->chars = NULL;
+ get_tfm_chars(params, font, tfm, 1);
+
+ /* free everything */
+ free_font_metrics(tfm);
+
+ return 0;
+}
+
+static int tfm_font_get_glyph(DviParams *params, DviFont *font, int code)
+{
+ DviFontChar *ch;
+
+ ch = FONTCHAR(font, code);
+ if(!glyph_present(ch))
+ return -1;
+ ch->glyph.x = ch->x;
+ ch->glyph.y = ch->y;
+ ch->glyph.w = ch->width;
+ ch->glyph.h = ch->height;
+ /*
+ * This has two purposes: (1) avoid unnecessary calls to this function,
+ * and (2) detect when the glyph data for a TFM font is actually used
+ * (we'll get a SEGV). Any occurrence of that is a bug.
+ */
+ ch->glyph.data = MDVI_GLYPH_EMPTY;
+
+ return 0;
+}
diff --git a/dviware/mdvi/lib/tfmfile.c b/dviware/mdvi/lib/tfmfile.c
new file mode 100644
index 0000000000..b91e931668
--- /dev/null
+++ b/dviware/mdvi/lib/tfmfile.c
@@ -0,0 +1,744 @@
+/* tfmfile.c -- readers for TFM, AFM, OTFM-0 and OTFM-1 files */
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h> /* tex-file.h needs this */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+#ifdef WITH_AFM_FILES
+#undef TRUE
+#undef FALSE
+#include "afmparse.h"
+#endif
+
+typedef struct tfmpool {
+ struct tfmpool *next;
+ struct tfmpool *prev;
+ char *short_name;
+ int links;
+ TFMInfo tfminfo;
+} TFMPool;
+
+static ListHead tfmpool = {NULL, NULL, 0};
+static DviHashTable tfmhash;
+
+#define TFM_HASH_SIZE 31
+
+#ifdef WORD_LITTLE_ENDIAN
+static inline void swap_array(Uint32 *ptr, int n)
+{
+ Uint32 i;
+
+ while(n-- > 0) {
+ i = *ptr;
+ *ptr++ = ((i & 0xff000000) >> 24)
+ | ((i & 0x00ff0000) >> 8)
+ | ((i & 0x0000ff00) << 8)
+ | ((i & 0x000000ff) << 24);
+ }
+}
+#endif
+
+#ifdef WITH_AFM_FILES
+
+/* reading of AFM files */
+/* macro to convert between AFM and TFM units */
+#define AFM2TFM(x) FROUND((double)(x) * 0x100000 / 1000)
+int afm_load_file(const char *filename, TFMInfo *info)
+{
+ /* the information we want is:
+ * - tfmwidth
+ * - width and heights
+ * - character origins
+ */
+ FontInfo *fi = NULL;
+ int status;
+ CharMetricInfo *cm;
+ FILE *in;
+
+ in = fopen(filename, "r");
+ if(in == NULL)
+ return -1;
+ status = afm_parse_file(in, &fi, P_GM);
+ fclose(in);
+
+ if(status != ok) {
+ error(_("%s: Error reading AFM data\n"), filename);
+ return -1;
+ }
+
+ /* aim high */
+ info->chars = xnalloc(TFMChar, 256);
+ info->loc = 256;
+ info->hic = 0;
+ info->design = 0xa00000; /* fake -- 10pt */
+ info->checksum = 0; /* no checksum */
+ info->type = DviFontAFM;
+ xstrncpy(info->coding, fi->gfi->encodingScheme, 63);
+ xstrncpy(info->family, fi->gfi->familyName, 63);
+
+ /* now get the data */
+ for(cm = fi->cmi; cm < fi->cmi + fi->numOfChars; cm++) {
+ int code;
+ TFMChar *ch;
+
+ code = cm->code;
+ if(code < 0 || code > 255)
+ continue; /* ignore it */
+ ch = &info->chars[code];
+ ch->present = 1;
+ if(code < info->loc)
+ info->loc = code;
+ if(code > info->hic)
+ info->hic = code;
+ ch->advance = AFM2TFM(cm->wx);
+ /* this is the `leftSideBearing' */
+ ch->left = AFM2TFM(cm->charBBox.llx);
+ /* this is the height (ascent - descent) -- the sign is to follow
+ * TeX conventions, as opposed to Adobe's ones */
+ ch->depth = -AFM2TFM(cm->charBBox.lly);
+ /* this is the width (rightSideBearing - leftSideBearing) */
+ ch->right = AFM2TFM(cm->charBBox.urx);
+ /* this is the `ascent' */
+ ch->height = AFM2TFM(cm->charBBox.ury);
+ }
+
+ /* we don't need this anymore */
+ afm_free_fontinfo(fi);
+
+ /* optimize storage */
+ if(info->loc > 0 || info->hic < 256) {
+ memmove(&info->chars[0],
+ &info->chars[info->loc],
+ (info->hic - info->loc + 1) * sizeof(TFMChar));
+ info->chars = xrealloc(info->chars,
+ (info->hic - info->loc + 1) * sizeof(TFMChar));
+ }
+
+ /* we're done */
+ return 0;
+}
+
+#endif /* WITH_AFM_FILES */
+
+int tfm_load_file(const char *filename, TFMInfo *info)
+{
+ int lf, lh, bc, ec, nw, nh, nd, ne;
+ int i, n;
+ Uchar *tfm;
+ Uchar *ptr;
+ struct stat st;
+ int size;
+ FILE *in;
+ Int32 *cb;
+ Int32 *charinfo;
+ Int32 *widths;
+ Int32 *heights;
+ Int32 *depths;
+ Uint32 checksum;
+
+ in = fopen(filename, "r");
+ if(in == NULL)
+ return -1;
+ tfm = NULL;
+
+ DEBUG((DBG_FONTS, "(mt) reading TFM file `%s'\n",
+ filename));
+ /* We read the entire TFM file into core */
+ if(fstat(fileno(in), &st) < 0)
+ return -1;
+ if(st.st_size == 0)
+ goto bad_tfm;
+
+ /* allocate a word-aligned buffer to hold the file */
+ size = 4 * ROUND(st.st_size, 4);
+ if(size != st.st_size)
+ warning(_("Warning: TFM file `%s' has suspicious size\n"),
+ filename);
+ tfm = (Uchar *)xmalloc(size);
+ if(fread(tfm, st.st_size, 1, in) != 1)
+ goto error;
+ /* we don't need this anymore */
+ fclose(in);
+ in = NULL;
+
+ /* not a checksum, but serves a similar purpose */
+ checksum = 0;
+
+ ptr = tfm;
+ /* get the counters */
+ lf = muget2(ptr);
+ lh = muget2(ptr); checksum += 6 + lh;
+ bc = muget2(ptr);
+ ec = muget2(ptr); checksum += ec - bc + 1;
+ nw = muget2(ptr); checksum += nw;
+ nh = muget2(ptr); checksum += nh;
+ nd = muget2(ptr); checksum += nd;
+ checksum += muget2(ptr); /* skip italics correction count */
+ checksum += muget2(ptr); /* skip lig/kern table size */
+ checksum += muget2(ptr); /* skip kern table size */
+ ne = muget2(ptr); checksum += ne;
+ checksum += muget2(ptr); /* skip # of font parameters */
+
+ size = ec - bc + 1;
+ cb = (Int32 *)tfm; cb += 6 + lh;
+ charinfo = cb; cb += size;
+ widths = cb; cb += nw;
+ heights = cb; cb += nh;
+ depths = cb;
+
+ if(widths[0] || heights[0] || depths[0] ||
+ checksum != lf || bc - 1 > ec || ec > 255 || ne > 256)
+ goto bad_tfm;
+
+ /* from this point on, no error checking is done */
+
+ /* now we're at the header */
+ /* get the checksum */
+ info->checksum = muget4(ptr);
+ /* get the design size */
+ info->design = muget4(ptr);
+ /* get the coding scheme */
+ if(lh > 2) {
+ /* get the coding scheme */
+ i = n = msget1(ptr);
+ if(n < 0 || n > 39) {
+ warning(_("%s: font coding scheme truncated to 40 bytes\n"),
+ filename);
+ n = 39;
+ }
+ memcpy(info->coding, ptr, n);
+ info->coding[n] = 0;
+ ptr += i;
+ } else
+ strcpy(info->coding, "FontSpecific");
+ /* get the font family */
+ if(lh > 12) {
+ n = msget1(ptr);
+ if(n > 0) {
+ i = Max(n, 63);
+ memcpy(info->family, ptr, i);
+ info->family[i] = 0;
+ } else
+ strcpy(info->family, "unspecified");
+ ptr += n;
+ }
+ /* now we don't read from `ptr' anymore */
+
+ info->loc = bc;
+ info->hic = ec;
+ info->type = DviFontTFM;
+
+ /* allocate characters */
+ info->chars = xnalloc(TFMChar, size);
+
+
+#ifdef WORD_LITTLE_ENDIAN
+ /* byte-swap the three arrays at once (they are consecutive in memory) */
+ swap_array((Uint32 *)widths, nw + nh + nd);
+#endif
+
+ /* get the relevant data */
+ ptr = (Uchar *)charinfo;
+ for(i = bc; i <= ec; ptr += 3, i++) {
+ int ndx;
+
+ ndx = (int)*ptr; ptr++;
+ info->chars[i-bc].advance = widths[ndx];
+ /* TFM files lack this information */
+ info->chars[i-bc].left = 0;
+ info->chars[i-bc].right = widths[ndx];
+ info->chars[i-bc].present = (ndx != 0);
+ if(ndx) {
+ ndx = ((*ptr >> 4) & 0xf);
+ info->chars[i-bc].height = heights[ndx];
+ ndx = (*ptr & 0xf);
+ info->chars[i-bc].depth = depths[ndx];
+ }
+ }
+
+ /* free everything */
+ xfree(tfm);
+
+ return 0;
+
+bad_tfm:
+ error(_("%s: File corrupted, or not a TFM file\n"), filename);
+error:
+ if(tfm) xfree(tfm);
+ if(in) fclose(in);
+ return -1;
+}
+
+static int ofm1_load_file(FILE *in, TFMInfo *info)
+{
+ int lf, lh, bc, ec, nw, nh, nd;
+ int nco, ncw, npc;
+ int i;
+ int n;
+ int size;
+ Int32 *tfm;
+ Int32 *widths;
+ Int32 *heights;
+ Int32 *depths;
+ TFMChar *tch;
+ TFMChar *end;
+
+ lf = fuget4(in);
+ lh = fuget4(in);
+ bc = fuget4(in);
+ ec = fuget4(in);
+ nw = fuget4(in);
+ nh = fuget4(in);
+ nd = fuget4(in);
+ fuget4(in); /* italics */
+ fuget4(in); /* lig-kern */
+ fuget4(in); /* kern */
+ fuget4(in); /* extensible recipe */
+ fuget4(in); /* parameters */
+ fuget4(in); /* direction */
+ nco = fuget4(in);
+ ncw = fuget4(in);
+ npc = fuget4(in);
+
+ /* get the checksum */
+ info->checksum = fuget4(in);
+ /* the design size */
+ info->design = fuget4(in);
+ /* get the coding scheme */
+ if(lh > 2) {
+ /* get the coding scheme */
+ i = n = fsget1(in);
+ if(n < 0 || n > 39)
+ n = 39;
+ fread(info->coding, 39, 1, in);
+ info->coding[n] = 0;
+ } else
+ strcpy(info->coding, "FontSpecific");
+ /* get the font family */
+ if(lh > 12) {
+ n = fsget1(in);
+ if(n > 0) {
+ i = Max(n, 63);
+ fread(info->family, i, 1, in);
+ info->family[i] = 0;
+ } else
+ strcpy(info->family, "unspecified");
+ }
+ tfm = NULL;
+
+ /* jump to the beginning of the char-info table */
+ fseek(in, 4L*nco, SEEK_SET);
+
+ size = ec - bc + 1;
+ info->loc = bc;
+ info->hic = ec;
+ info->chars = xnalloc(TFMChar, size);
+ end = info->chars + size;
+
+ for(tch = info->chars, i = 0; i < ncw; i++) {
+ TFMChar ch;
+ int nr;
+
+ /* in the characters we store the actual indices */
+ ch.advance = fuget2(in);
+ ch.height = fuget1(in);
+ ch.depth = fuget1(in);
+ /* skip 2nd word */
+ fuget4(in);
+ /* get # of repeats */
+ nr = fuget2(in);
+ /* skip parameters */
+ fseek(in, (long)npc * 2, SEEK_CUR);
+ /* if npc is odd, skip padding */
+ if(npc & 1) fuget2(in);
+
+ /* now repeat the character */
+ while(nr-- >= 0 && tch < end)
+ memcpy(tch++, &ch, sizeof(TFMChar));
+ if(tch == end)
+ goto bad_tfm;
+ }
+
+ /* I wish we were done, but we aren't */
+
+ /* get the widths, heights and depths */
+ size = nw + nh + nd;
+ tfm = xnalloc(Int32, size);
+ /* read them in one sweep */
+ if(fread(tfm, 4, size, in) != size) {
+ xfree(tfm);
+ goto bad_tfm;
+ }
+
+ /* byte-swap things if necessary */
+#ifdef WORD_LITTLE_ENDIAN
+ swap_array((Uint32 *)tfm, size);
+#endif
+ widths = tfm;
+ heights = widths + nw;
+ depths = heights + nh;
+
+ if(widths[0] || heights[0] || depths[0])
+ goto bad_tfm;
+
+ /* now fix the characters */
+ size = ec - bc + 1;
+ for(tch = info->chars; tch < end; tch++) {
+ tch->present = (tch->advance != 0);
+ tch->advance = widths[tch->advance];
+ tch->height = heights[tch->height];
+ tch->depth = depths[tch->depth];
+ tch->left = 0;
+ tch->right = tch->advance;
+ }
+
+ /* NOW we're done */
+ xfree(tfm);
+ return 0;
+
+bad_tfm:
+ if(tfm) xfree(tfm);
+ return -1;
+}
+
+/* we don't read OFM files into memory, because they can potentially be large */
+int ofm_load_file(const char *filename, TFMInfo *info)
+{
+ int lf, lh, bc, ec, nw, nh, nd;
+ int i, n;
+ Int32 *tfm;
+ Uchar *ptr;
+ int size;
+ FILE *in;
+ Int32 *cb;
+ Int32 *charinfo;
+ Int32 *widths;
+ Int32 *heights;
+ Int32 *depths;
+ Uint32 checksum;
+ int olevel;
+ int nwords;
+
+ in = fopen(filename, "r");
+ if(in == NULL)
+ return -1;
+
+ /* not a checksum, but serves a similar purpose */
+ checksum = 0;
+
+ /* get the counters */
+ /* get file level */
+ olevel = fsget2(in);
+ if(olevel != 0)
+ goto bad_tfm;
+ olevel = fsget2(in);
+ if(olevel != 0) {
+ DEBUG((DBG_FONTS, "(mt) reading Level-1 OFM file `%s'\n",
+ filename));
+ /* we handle level-1 files separately */
+ if(ofm1_load_file(in, info) < 0)
+ goto bad_tfm;
+ return 0;
+ }
+
+ DEBUG((DBG_FONTS, "(mt) reading Level-0 OFM file `%s'\n", filename));
+ nwords = 14;
+ lf = fuget4(in); checksum = nwords;
+ lh = fuget4(in); checksum += lh;
+ bc = fuget4(in);
+ ec = fuget4(in); checksum += 2 * (ec - bc + 1);
+ nw = fuget4(in); checksum += nw;
+ nh = fuget4(in); checksum += nh;
+ nd = fuget4(in); checksum += nd;
+ checksum += fuget4(in); /* skip italics correction count */
+ checksum += 2*fuget4(in); /* skip lig/kern table size */
+ checksum += fuget4(in); /* skip kern table size */
+ checksum += 2*fuget4(in); /* skip extensible recipe count */
+ checksum += fuget4(in); /* skip # of font parameters */
+
+ /* I have found several .ofm files that seem to have the
+ * font-direction word missing, so we try to detect that here */
+ if(checksum == lf + 1) {
+ DEBUG((DBG_FONTS, "(mt) font direction missing in `%s'\n",
+ filename));
+ checksum--;
+ nwords--;
+ } else {
+ /* skip font direction */
+ fuget4(in);
+ }
+
+ if(checksum != lf || bc > ec + 1 || ec > 65535)
+ goto bad_tfm;
+
+ /* now we're at the header */
+
+ /* get the checksum */
+ info->checksum = fuget4(in);
+ /* get the design size */
+ info->design = fuget4(in);
+
+ /* get the coding scheme */
+ if(lh > 2) {
+ /* get the coding scheme */
+ i = n = fsget1(in);
+ if(n < 0 || n > 39) {
+ warning(_("%s: font coding scheme truncated to 40 bytes\n"),
+ filename);
+ n = 39;
+ }
+ fread(info->coding, 39, 1, in);
+ info->coding[n] = 0;
+ ptr += i;
+ } else
+ strcpy(info->coding, "FontSpecific");
+ /* get the font family */
+ if(lh > 12) {
+ n = fsget1(in);
+ if(n > 0) {
+ i = Max(n, 63);
+ fread(info->family, i, 1, in);
+ info->family[i] = 0;
+ } else
+ strcpy(info->family, "unspecified");
+ }
+
+ /* now skip anything else in the header */
+ fseek(in, 4L*(nwords + lh), SEEK_SET);
+ /* and read everything at once */
+ size = 2*(ec - bc + 1) + nw + nh + nd;
+ tfm = xnalloc(Int32, size * sizeof(Int32));
+ if(fread(tfm, 4, size, in) != size) {
+ xfree(tfm);
+ goto bad_tfm;
+ }
+ /* byte-swap all the tables at once */
+#ifdef WORD_LITTLE_ENDIAN
+ swap_array((Uint32 *)tfm, size);
+#endif
+ cb = tfm;
+ charinfo = cb; cb += 2*(ec - bc + 1);
+ widths = cb; cb += nw;
+ heights = cb; cb += nh;
+ depths = cb;
+
+ if(widths[0] || heights[0] || depths[0]) {
+ xfree(tfm);
+ goto bad_tfm;
+ }
+
+ /* from this point on, no error checking is done */
+
+ /* we don't need this anymore */
+ fclose(in);
+
+ /* now we don't read from `ptr' anymore */
+
+ info->loc = bc;
+ info->hic = ec;
+ info->type = DviFontTFM;
+
+ /* allocate characters */
+ info->chars = xnalloc(TFMChar, size);
+
+ /* get the relevant data */
+ ptr = (Uchar *)charinfo;
+ for(i = bc; i <= ec; ptr += 4, i++) {
+ int ndx;
+
+ ndx = muget2(ptr);
+ info->chars[i-bc].advance = widths[ndx];
+ /* TFM files lack this information */
+ info->chars[i-bc].left = 0;
+ info->chars[i-bc].right = widths[ndx];
+ info->chars[i-bc].present = (ndx != 0);
+ ndx = muget1(ptr);
+ info->chars[i-bc].height = heights[ndx];
+ ndx = muget1(ptr);
+ info->chars[i-bc].depth = depths[ndx];
+ }
+
+ xfree(tfm);
+ return 0;
+
+bad_tfm:
+ error(_("%s: File corrupted, or not a TFM file\n"), filename);
+ fclose(in);
+ return -1;
+}
+
+char *lookup_font_metrics(const char *name, int *type)
+{
+ char *file;
+
+ switch(*type) {
+#ifndef WITH_AFM_FILES
+ case DviFontAny:
+#endif
+ case DviFontTFM:
+ file = kpse_find_tfm(name);
+ break;
+ case DviFontOFM: {
+ file = kpse_find_ofm(name);
+ /* we may have gotten a TFM back */
+ if(file != NULL) {
+ const char *ext = file_extension(file);
+ if(ext && STREQ(ext, "tfm"))
+ *type = DviFontTFM;
+ }
+ break;
+ }
+#ifdef WITH_AFM_FILES
+ case DviFontAFM:
+ file = kpse_find_file(name, kpse_afm_format, 0);
+ break;
+ case DviFontAny:
+ file = kpse_find_file(name, kpse_afm_format, 0);
+ *type = DviFontAFM;
+ if(file == NULL) {
+ file = kpse_find_tfm(name);
+ *type = DviFontTFM;
+ }
+ break;
+#endif
+ default:
+ return NULL;
+ }
+
+ return file;
+}
+
+/*
+ * The next two functions are just wrappers for the font metric loaders,
+ * and use the pool of TFM data
+ */
+
+/* this is how we interpret arguments:
+ * - if filename is NULL, we look for files of the given type,
+ * unless type is DviFontAny, in which case we try all the
+ * types we know of.
+ * - if filename is not NULL, we look at `type' to decide
+ * how to read the file. If type is DviFontAny, we just
+ * return an error.
+ */
+TFMInfo *get_font_metrics(const char *short_name, int type, const char *filename)
+{
+ TFMPool *tfm = NULL;
+ int status;
+ char *file;
+
+ if(tfmpool.count) {
+ tfm = (TFMPool *)mdvi_hash_lookup(&tfmhash,
+ MDVI_KEY(short_name));
+ if(tfm != NULL) {
+ DEBUG((DBG_FONTS, "(mt) reusing metric file `%s' (%d links)\n",
+ short_name, tfm->links));
+ tfm->links++;
+ return &tfm->tfminfo;
+ }
+ }
+
+ file = filename ? (char *)filename : lookup_font_metrics(short_name, &type);
+ if(file == NULL)
+ return NULL;
+
+ tfm = xalloc(TFMPool);
+ DEBUG((DBG_FONTS, "(mt) loading font metric data from `%s'\n", file, file));
+ switch(type) {
+ case DviFontTFM:
+ status = tfm_load_file(file, &tfm->tfminfo);
+ break;
+ case DviFontOFM:
+ status = ofm_load_file(file, &tfm->tfminfo);
+ break;
+#ifdef WITH_AFM_FILES
+ case DviFontAFM:
+ status = afm_load_file(file, &tfm->tfminfo);
+ break;
+#endif
+ default:
+ status = -1;
+ break;
+ }
+ if(file != filename)
+ xfree(file);
+ if(status < 0) {
+ xfree(tfm);
+ return NULL;
+ }
+ tfm->short_name = xstrdup(short_name);
+
+ /* add it to the pool */
+ if(tfmpool.count == 0)
+ mdvi_hash_create(&tfmhash, TFM_HASH_SIZE);
+ mdvi_hash_add(&tfmhash, MDVI_KEY(tfm->short_name),
+ tfm, MDVI_HASH_UNCHECKED);
+ listh_prepend(&tfmpool, LIST(tfm));
+ tfm->links = 1;
+
+ return &tfm->tfminfo;
+}
+
+void free_font_metrics(TFMInfo *info)
+{
+ TFMPool *tfm;
+
+ if(tfmpool.count == 0)
+ return;
+ /* get the entry -- can't use the hash table for this, because
+ * we don't have the short name */
+ for(tfm = (TFMPool *)tfmpool.head; tfm; tfm = tfm->next)
+ if(info == &tfm->tfminfo)
+ break;
+ if(tfm == NULL)
+ return;
+ if(--tfm->links > 0) {
+ DEBUG((DBG_FONTS, "(mt) %s not removed, still in use\n",
+ tfm->short_name));
+ return;
+ }
+ mdvi_hash_remove_ptr(&tfmhash, MDVI_KEY(tfm->short_name));
+
+ DEBUG((DBG_FONTS, "(mt) removing unused TFM data for `%s'\n", tfm->short_name));
+ listh_remove(&tfmpool, LIST(tfm));
+ xfree(tfm->short_name);
+ xfree(tfm->tfminfo.chars);
+ xfree(tfm);
+}
+
+void flush_font_metrics(void)
+{
+ TFMPool *ptr;
+
+ for(; (ptr = (TFMPool *)tfmpool.head); ) {
+ tfmpool.head = LIST(ptr->next);
+
+ xfree(ptr->short_name);
+ xfree(ptr->tfminfo.chars);
+ xfree(ptr);
+ }
+ mdvi_hash_reset(&tfmhash, 0);
+}
diff --git a/dviware/mdvi/lib/tt.c b/dviware/mdvi/lib/tt.c
new file mode 100644
index 0000000000..d04d33d7b3
--- /dev/null
+++ b/dviware/mdvi/lib/tt.c
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "mdvi.h"
+
+#ifdef WITH_TRUETYPE_FONTS
+
+#include <string.h>
+#include <freetype.h>
+#include <ftxpost.h>
+#include <ftxerr18.h>
+
+#include "private.h"
+
+static TT_Engine tt_handle;
+static int initialized = 0;
+
+typedef struct ftinfo {
+ struct ftinfo *next;
+ struct ftinfo *prev;
+ char *fontname;
+ char *fmfname;
+ TT_Face face;
+ TT_Instance instance;
+ TT_Glyph glyph;
+ int hasmetrics;
+ int loaded;
+ int fmftype;
+ TFMInfo *tfminfo;
+ DviFontMapInfo mapinfo;
+ DviEncoding *encoding;
+} FTInfo;
+
+static int tt_load_font __PROTO((DviParams *, DviFont *));
+static int tt_font_get_glyph __PROTO((DviParams *, DviFont *, int));
+static void tt_free_data __PROTO((DviFont *));
+static void tt_reset_font __PROTO((DviFont *));
+static void tt_shrink_glyph
+ __PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
+static void tt_font_remove __PROTO((FTInfo *));
+
+DviFontInfo tt_font_info = {
+ "TT",
+ 0,
+ tt_load_font,
+ tt_font_get_glyph,
+ tt_shrink_glyph,
+ mdvi_shrink_glyph_grey,
+ tt_free_data, /* free */
+ tt_reset_font, /* reset */
+ NULL, /* lookup */
+ kpse_truetype_format,
+ NULL
+};
+
+#define FT_HASH_SIZE 31
+
+static ListHead ttfonts = {NULL, NULL, 0};
+
+static int init_freetype(void)
+{
+ TT_Error code;
+
+ ASSERT(initialized == 0);
+ code = TT_Init_FreeType(&tt_handle);
+ if(code) {
+ DEBUG((DBG_TT, "(tt) Init_Freetype: error %d\n", code));
+ return -1;
+ }
+ code = TT_Init_Post_Extension(tt_handle);
+ if(code) {
+ TT_Done_FreeType(tt_handle);
+ return -1;
+ }
+ /* we're on */
+ initialized = 1;
+ return 0;
+}
+
+static void tt_encode_font(DviFont *font, FTInfo *info)
+{
+ TT_Face_Properties prop;
+ int i;
+
+ if(TT_Get_Face_Properties(info->face, &prop))
+ return;
+
+ for(i = 0; i < prop.num_Glyphs; i++) {
+ char *string;
+ int ndx;
+
+ if(TT_Get_PS_Name(info->face, i, &string))
+ continue;
+ ndx = mdvi_encode_glyph(info->encoding, string);
+ if(ndx < font->loc || ndx > font->hic)
+ continue;
+ font->chars[ndx - font->loc].code = i;
+ }
+}
+
+static int tt_really_load_font(DviParams *params, DviFont *font, FTInfo *info)
+{
+ DviFontChar *ch;
+ TFMChar *ptr;
+ Int32 z, alpha, beta;
+ int i;
+ FTInfo *old;
+ TT_Error status;
+ double point_size;
+ static int warned = 0;
+ TT_CharMap cmap;
+ TT_Face_Properties props;
+ int map_found;
+
+ DEBUG((DBG_TT, "(tt) really_load_font(%s)\n", info->fontname));
+
+ /* get the point size */
+ point_size = (double)font->scale / (params->tfm_conv * 0x100000);
+ point_size = 72.0 * point_size / 72.27;
+ if(info->loaded) {
+ /* just reset the size info */
+ TT_Set_Instance_Resolutions(info->instance,
+ params->dpi, params->vdpi);
+ TT_Set_Instance_CharSize(info->instance, FROUND(point_size * 64));
+ /* FIXME: should extend/slant again */
+ info->hasmetrics = 1;
+ return 0;
+ }
+
+ /* load the face */
+ DEBUG((DBG_TT, "(tt) loading new face `%s'\n",
+ info->fontname));
+ status = TT_Open_Face(tt_handle, font->filename, &info->face);
+ if(status) {
+ warning(_("(tt) %s: could not load face: %s\n"),
+ info->fontname, TT_ErrToString18(status));
+ return -1;
+ }
+
+ /* create a new instance of this face */
+ status = TT_New_Instance(info->face, &info->instance);
+ if(status) {
+ warning(_("(tt) %s: could not create face: %s\n"),
+ info->fontname, TT_ErrToString18(status));
+ TT_Close_Face(info->face);
+ return -1;
+ }
+
+ /* create a glyph */
+ status = TT_New_Glyph(info->face, &info->glyph);
+ if(status) {
+ warning(_("(tt) %s: could not create glyph: %s\n"),
+ info->fontname, TT_ErrToString18(status));
+ goto tt_error;
+ }
+
+ /*
+ * We'll try to find a Unicode charmap. It's not that important that we
+ * actually find one, especially if the fontmap files are installed
+ * properly, but it's good to have some predefined behaviour
+ */
+ TT_Get_Face_Properties(info->face, &props);
+
+ map_found = -1;
+ for(i = 0; map_found < 0 && i < props.num_CharMaps; i++) {
+ TT_UShort pid, eid;
+
+ TT_Get_CharMap_ID(info->face, i, &pid, &eid);
+ switch(pid) {
+ case TT_PLATFORM_APPLE_UNICODE:
+ map_found = i;
+ break;
+ case TT_PLATFORM_ISO:
+ if(eid == TT_ISO_ID_7BIT_ASCII ||
+ eid == TT_ISO_ID_8859_1)
+ map_found = 1;
+ break;
+ case TT_PLATFORM_MICROSOFT:
+ if(eid == TT_MS_ID_UNICODE_CS)
+ map_found = 1;
+ break;
+ }
+ }
+ if(map_found < 0) {
+ warning(_("(tt) %s: no acceptable map found, using #0\n"),
+ info->fontname);
+ map_found = 0;
+ }
+ DEBUG((DBG_TT, "(tt) %s: using charmap #%d\n",
+ info->fontname, map_found));
+ TT_Get_CharMap(info->face, map_found, &cmap);
+
+ DEBUG((DBG_TT, "(tt) %s: Set_Char_Size(%.2f, %d, %d)\n",
+ font->fontname, point_size, font->hdpi, font->vdpi));
+ status = TT_Set_Instance_Resolutions(info->instance,
+ params->dpi, params->vdpi);
+ if(status) {
+ error(_("(tt) %s: could not set resolution: %s\n"),
+ info->fontname, TT_ErrToString18(status));
+ goto tt_error;
+ }
+ status = TT_Set_Instance_CharSize(info->instance,
+ FROUND(point_size * 64));
+ if(status) {
+ error(_("(tt) %s: could not set point size: %s\n"),
+ info->fontname, TT_ErrToString18(status));
+ goto tt_error;
+ }
+
+ /* after this point we don't fail */
+
+ /* get information from the fontmap */
+ status = mdvi_query_fontmap(&info->mapinfo, info->fontname);
+ if(!status && info->mapinfo.encoding)
+ info->encoding = mdvi_request_encoding(info->mapinfo.encoding);
+ else
+ info->encoding = NULL;
+
+ if(info->encoding != NULL) {
+ TT_Post post;
+
+ status = TT_Load_PS_Names(info->face, &post);
+ if(status) {
+ warning(_("(tt) %s: could not load PS name table\n"),
+ info->fontname);
+ mdvi_release_encoding(info->encoding, 0);
+ info->encoding = NULL;
+ }
+ }
+
+ /* get the metrics. If this fails, it's not fatal, but certainly bad */
+ info->tfminfo = get_font_metrics(info->fontname,
+ info->fmftype, info->fmfname);
+
+ if(info->tfminfo == NULL) {
+ warning("(tt) %s: no metrics data, font ignored\n",
+ info->fontname);
+ goto tt_error;
+ }
+ /* fix this */
+ font->design = info->tfminfo->design;
+
+ /* get the scaled character metrics */
+ get_tfm_chars(params, font, info->tfminfo, 0);
+
+ if(info->encoding)
+ tt_encode_font(font, info);
+ else {
+ warning(_("%s: no encoding vector found, expect bad output\n"),
+ info->fontname);
+ /* this is better than nothing */
+ for(i = font->loc; i <= font->hic; i++)
+ font->chars[i - font->loc].code = TT_Char_Index(cmap, i);
+ }
+
+ info->loaded = 1;
+ info->hasmetrics = 1;
+ return 0;
+
+tt_error:
+ tt_font_remove(info);
+ xfree(font->chars);
+ font->chars = NULL;
+ font->loc = font->hic = 0;
+ return -1;
+}
+
+static int tt_load_font(DviParams *params, DviFont *font)
+{
+ int i;
+ FTInfo *info;
+
+ if(!initialized && init_freetype() < 0)
+ return -1;
+
+ if(font->in != NULL) {
+ fclose(font->in);
+ font->in = NULL;
+ }
+
+ info = xalloc(FTInfo);
+
+ memzero(info, sizeof(FTInfo));
+ info->fmftype = DviFontAny; /* any metrics type will do */
+ info->fmfname = lookup_font_metrics(font->fontname, &info->fmftype);
+ info->fontname = font->fontname;
+ info->hasmetrics = 0;
+ info->loaded = 0;
+
+ /* these will be obtained from the fontmaps */
+ info->mapinfo.psname = NULL;
+ info->mapinfo.encoding = NULL;
+ info->mapinfo.fontfile = NULL;
+ info->mapinfo.extend = 0;
+ info->mapinfo.slant = 0;
+
+ /* initialize these */
+ font->chars = xnalloc(DviFontChar, 256);
+ font->loc = 0;
+ font->hic = 255;
+ for(i = 0; i < 256; i++) {
+ font->chars[i].offset = 1;
+ font->chars[i].glyph.data = NULL;
+ font->chars[i].shrunk.data = NULL;
+ font->chars[i].grey.data = NULL;
+ }
+
+ if(info->fmfname == NULL)
+ warning(_("(tt) %s: no font metric data\n"), font->fontname);
+
+ listh_append(&ttfonts, LIST(info));
+ font->private = info;
+
+ return 0;
+}
+
+static int tt_get_bitmap(DviParams *params, DviFont *font,
+ int code, double xscale, double yscale, DviGlyph *glyph)
+{
+ TT_Outline outline;
+ TT_Raster_Map raster;
+ TT_BBox bbox;
+ TT_Glyph_Metrics metrics;
+ TT_Matrix mat;
+ FTInfo *info;
+ int error;
+ int have_outline = 0;
+ int w, h;
+
+ info = (FTInfo *)font->private;
+ if(info == NULL)
+ return -1;
+
+ error = TT_Load_Glyph(info->instance, info->glyph,
+ code, TTLOAD_DEFAULT);
+ if(error) goto tt_error;
+ error = TT_Get_Glyph_Outline(info->glyph, &outline);
+ if(error) goto tt_error;
+ have_outline = 1;
+ mat.xx = FROUND(xscale * 65536);
+ mat.yy = FROUND(yscale * 65536);
+ mat.yx = 0;
+ mat.xy = 0;
+ TT_Transform_Outline(&outline, &mat);
+ error = TT_Get_Outline_BBox(&outline, &bbox);
+ if(error) goto tt_error;
+ bbox.xMin &= -64;
+ bbox.yMin &= -64;
+ bbox.xMax = (bbox.xMax + 63) & -64;
+ bbox.yMax = (bbox.yMax + 63) & -64;
+ w = (bbox.xMax - bbox.xMin) / 64;
+ h = (bbox.yMax - bbox.yMin) / 64;
+
+ glyph->w = w;
+ glyph->h = h;
+ glyph->x = -bbox.xMin / 64;
+ glyph->y = bbox.yMax / 64;
+ if(!w || !h)
+ goto tt_error;
+ raster.rows = h;
+ raster.width = w;
+ raster.cols = ROUND(w, 8);
+ raster.size = h * raster.cols;
+ raster.flow = TT_Flow_Down;
+ raster.bitmap = xcalloc(h, raster.cols);
+
+ TT_Translate_Outline(&outline, -bbox.xMin, -bbox.yMin);
+ TT_Get_Outline_Bitmap(tt_handle, &outline, &raster);
+ glyph->data = bitmap_convert_msb8(raster.bitmap, w, h);
+ TT_Done_Outline(&outline);
+ xfree(raster.bitmap);
+
+ return 0;
+tt_error:
+ if(have_outline)
+ TT_Done_Outline(&outline);
+ return -1;
+}
+
+static int tt_font_get_glyph(DviParams *params, DviFont *font, int code)
+{
+ FTInfo *info = (FTInfo *)font->private;
+ DviFontChar *ch;
+ int error;
+ double xs, ys;
+ int dpi;
+
+ ASSERT(info != NULL);
+ if(!info->hasmetrics && tt_really_load_font(params, font, info) < 0)
+ return -1;
+ ch = FONTCHAR(font, code);
+ if(!ch || !glyph_present(ch))
+ return -1;
+ ch->loaded = 1;
+ if(!ch->width || !ch->height)
+ goto blank;
+ if(ch->code == 0) {
+ ch->glyph.data = NULL;
+ goto missing;
+ }
+ /* get the glyph */
+ dpi = Max(font->hdpi, font->vdpi);
+ error = tt_get_bitmap(params, font, ch->code,
+ (double)font->hdpi / dpi,
+ (double)font->vdpi / dpi,
+ &ch->glyph);
+ if(error)
+ goto missing;
+ ch->x = ch->glyph.x;
+ ch->y = ch->glyph.y;
+
+ return 0;
+
+missing:
+ ch->glyph.data = MDVI_GLYPH_EMPTY;
+ ch->missing = 1;
+blank:
+ ch->glyph.w = ch->width;
+ ch->glyph.h = ch->height;
+ ch->glyph.x = ch->x;
+ ch->glyph.y = ch->y;
+ return 0;
+}
+
+static void tt_shrink_glyph(DviContext *dvi, DviFont *font, DviFontChar *ch, DviGlyph *dest)
+{
+ tt_get_bitmap(&dvi->params, font,
+ ch->code,
+ (double)font->hdpi / (dvi->params.dpi * dvi->params.hshrink),
+ (double)font->vdpi / (dvi->params.vdpi * dvi->params.vshrink),
+ dest);
+ /* transform the glyph for the current orientation */
+ font_transform_glyph(dvi->params.orientation, dest);
+}
+
+static void tt_reset_font(DviFont *font)
+{
+ FTInfo *info = (FTInfo *)font->private;
+
+ if(info == NULL)
+ return;
+ info->hasmetrics = 0;
+}
+
+static void tt_font_remove(FTInfo *info)
+{
+ FTInfo *old;
+
+ if(info->loaded) {
+ /* all fonts in the hash table have called TT_Open_Face */
+ TT_Done_Instance(info->instance);
+ TT_Close_Face(info->face);
+ }
+ listh_remove(&ttfonts, LIST(info));
+ /* release our encodings */
+ if(info->encoding)
+ mdvi_release_encoding(info->encoding, 1);
+ /* and destroy the font */
+ if(info->tfminfo)
+ free_font_metrics(info->tfminfo);
+ if(info->fmfname)
+ xfree(info->fmfname);
+ xfree(info);
+}
+
+static void tt_free_data(DviFont *font)
+{
+ if(font->private == NULL)
+ return;
+
+ tt_font_remove((FTInfo *)font->private);
+ if(initialized && ttfonts.count == 0) {
+ DEBUG((DBG_TT, "(tt) last font removed -- closing FreeType\n"));
+ TT_Done_FreeType(tt_handle);
+ initialized = 0;
+ }
+}
+
+#endif /* WITH_TRUETYPE_FONTS */
diff --git a/dviware/mdvi/lib/util.c b/dviware/mdvi/lib/util.c
new file mode 100644
index 0000000000..34ba3fa1b9
--- /dev/null
+++ b/dviware/mdvi/lib/util.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "private.h"
+
+static char *const messages[] = {
+ _G("Ooops!"),
+ _G("Aieeeee!!"),
+ _G("Ouch!"),
+ _G("Houston, we have a problem"),
+ _G("3.. 2.. 1.. BOOM!"),
+ _G("I'm history"),
+ _G("I'm going down"),
+ _G("I smell a rat")
+};
+#define NMSGS (sizeof(messages) / sizeof(char *))
+
+static FILE *logfile = NULL;
+static int _mdvi_log_level;
+
+static void vputlog(int level, const char *head, const char *format, va_list ap)
+{
+ if(logfile != NULL && _mdvi_log_level >= level) {
+ if(head != NULL)
+ fprintf(logfile, "%s: ", head);
+ vfprintf(logfile, format, ap);
+ }
+}
+
+int mdvi_set_logfile(const char *filename)
+{
+ FILE *f = NULL;
+
+ if(filename && (f = fopen(filename, "w")) == NULL)
+ return -1;
+ if(logfile != NULL && !isatty(fileno(logfile))) {
+ fclose(logfile);
+ logfile = NULL;
+ }
+ if(filename)
+ logfile = f;
+ return 0;
+}
+
+int mdvi_set_logstream(FILE *file)
+{
+ if(logfile && !isatty(fileno(logfile))) {
+ fclose(logfile);
+ logfile = NULL;
+ }
+ logfile = file;
+ return 0;
+}
+
+int mdvi_set_loglevel(int level)
+{
+ int old = _mdvi_log_level;
+
+ _mdvi_log_level = level;
+ return old;
+}
+
+#ifndef NODEBUG
+Uint32 _mdvi_debug_mask = 0;
+
+void __debug(int mask, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ if(_mdvi_debug_mask & mask) {
+ if(!DEBUGGING(SILENT)) {
+ fprintf(stderr, "Debug: ");
+ vfprintf(stderr, format, ap);
+ fflush(stderr);
+ }
+#ifndef __GNUC__
+ /* let's be portable */
+ va_end(ap);
+ va_start(ap, format);
+#endif
+ vputlog(LOG_DEBUG, "Debug", format, ap);
+ }
+ va_end(ap);
+}
+#endif
+
+void message(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ if(_mdvi_log_level >= LOG_INFO) {
+ fprintf(stderr, "%s: ", program_name);
+ vfprintf(stderr, format, ap);
+#ifndef __GNUC__
+ va_end(ap);
+ va_start(ap, format);
+#endif
+ }
+ vputlog(LOG_INFO, NULL, format, ap);
+ va_end(ap);
+}
+
+void crash(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ fprintf(stderr, "%s: %s: ",
+ program_name,
+ gettext(messages[(int)time(NULL) % NMSGS]));
+ vfprintf(stderr, format, ap);
+#ifndef __GNUC__
+ /* let's be portable */
+ va_end(ap);
+ va_start(ap, format);
+#endif
+ vputlog(LOG_ERROR, _("Crashing"), format, ap);
+ va_end(ap);
+ abort();
+}
+
+void error(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ fprintf(stderr, _("%s: Error: "), program_name);
+ vfprintf(stderr, format, ap);
+#ifndef __GNUC__
+ /* let's be portable */
+ va_end(ap);
+ va_start(ap, format);
+#endif
+ vputlog(LOG_ERROR, _("Error"), format, ap);
+ va_end(ap);
+}
+
+void warning(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ fprintf(stderr, _("%s: Warning: "), program_name);
+ vfprintf(stderr, format, ap);
+#ifndef __GNUC__
+ /* let's be portable */
+ va_end(ap);
+ va_start(ap, format);
+#endif
+ vputlog(LOG_WARN, _("Warning"), format, ap);
+ va_end(ap);
+}
+
+void fatal(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ fprintf(stderr, _("%s: Fatal: "), program_name);
+ vfprintf(stderr, format, ap);
+#ifndef __GNUC__
+ /* let's be portable */
+ va_end(ap);
+ va_start(ap, format);
+#endif
+ vputlog(LOG_ERROR, _("Fatal"), format, ap);
+ va_end(ap);
+#ifndef NODEBUG
+ abort();
+#else
+ exit(EXIT_FAILURE);
+#endif
+}
+
+void *xmalloc(size_t nelems)
+{
+ void *ptr = malloc(nelems);
+
+ if(ptr == NULL)
+ fatal(_("out of memory allocating %u bytes\n"),
+ (unsigned)nelems);
+ return ptr;
+}
+
+void *xrealloc(void *data, size_t newsize)
+{
+ void *ptr;
+
+ if(newsize == 0)
+ crash(_("attempted to reallocate with zero size\n"));
+ ptr = realloc(data, newsize);
+ if(ptr == NULL)
+ fatal(_("failed to reallocate %u bytes\n"), (unsigned)newsize);
+ return ptr;
+}
+
+void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ if(nmemb == 0)
+ crash(_("attempted to callocate 0 members\n"));
+ if(size == 0)
+ crash(_("attempted to callocate %u members with size 0\n"),
+ (unsigned)nmemb);
+ ptr = calloc(nmemb, size);
+ if(ptr == 0)
+ fatal(_("failed to allocate %ux%u bytes\n"),
+ (unsigned)nmemb, (unsigned)size);
+ return ptr;
+}
+
+void xfree(void *ptr)
+{
+ if(ptr == NULL)
+ crash(_("attempted to free NULL pointer\n"));
+ free(ptr);
+}
+
+char *xstrdup(const char *string)
+{
+ int length;
+ char *ptr;
+
+ length = strlen(string) + 1;
+ ptr = (char *)xmalloc(length);
+ memcpy(ptr, string, length);
+ return ptr;
+}
+
+/* `to' should have room for length+1 bytes */
+char *xstrncpy(char *to, const char *from, size_t length)
+{
+ strncpy(to, from, length);
+ to[length] = '\0';
+ return to;
+}
+
+char *xstrndup(const char *string, size_t length)
+{
+ int n;
+ char *ptr;
+
+ n = strlen(string);
+ if(n > length)
+ n = length;
+ ptr = (char *)xmalloc(n + 1);
+ memcpy(ptr, string, n);
+ return ptr;
+}
+
+void *xmemdup(const void *data, size_t length)
+{
+ void *ptr = xmalloc(length);
+
+ memcpy(ptr, data, length);
+ return ptr;
+}
+
+double unit2pix_factor(const char *spec)
+{
+ double val;
+ double factor;
+ const char *p, *q;
+ static const char *units = "incmmmmtptpcddccspbpftydcs";
+
+ val = 0.0;
+
+ for(p = spec; *p >= '0' && *p <= '9'; p++)
+ val = 10.0 * val + (double)(*p - '0');
+ if(*p == '.') {
+ p++;
+ factor = 0.1;
+ while(*p && *p >= '0' && *p <= '9') {
+ val += (*p++ - '0') * factor;
+ factor = factor * 0.1;
+ }
+ }
+ factor = 1.0;
+ for(q = units; *q; q += 2) {
+ if(p[0] == q[0] && p[1] == q[1])
+ break;
+ }
+ switch((int)(q - units)) {
+ /*in*/ case 0: factor = 1.0; break;
+ /*cm*/ case 2: factor = 1.0 / 2.54; break;
+ /*mm*/ case 4: factor = 1.0 / 25.4; break;
+ /*mt*/ case 6: factor = 1.0 / 0.0254; break;
+ /*pt*/ case 8: factor = 1.0 / 72.27; break;
+ /*pc*/ case 10: factor = 12.0 / 72.27; break;
+ /*dd*/ case 12: factor = (1238.0 / 1157.0) / 72.27; break;
+ /*cc*/ case 14: factor = 12 * (1238.0 / 1157.0) / 72.27; break;
+ /*sp*/ case 16: factor = 1.0 / (72.27 * 65536); break;
+ /*bp*/ case 18: factor = 1.0 / 72.0; break;
+ /*ft*/ case 20: factor = 12.0; break;
+ /*yd*/ case 22: factor = 36.0; break;
+ /*cs*/ case 24: factor = 1.0 / 72000.0; break;
+ default: factor = 1.0;
+ }
+ return factor * val;
+}
+
+int unit2pix(int dpi, const char *spec)
+{
+ double factor = unit2pix_factor(spec);
+
+ return (int)(factor * dpi + 0.5);
+}
+
+Ulong get_mtime(int fd)
+{
+ struct stat st;
+
+ if(fstat(fd, &st) == 0)
+ return (Ulong)st.st_mtime;
+ return 0;
+}
+
+char *xstradd(char *dest, size_t *size, size_t n, const char *src, size_t m)
+{
+ if(m == 0)
+ m = strlen(src);
+ if(n + m >= *size) {
+ dest = xrealloc(dest, n + m + 1);
+ *size = n + m + 1;
+ }
+ memcpy(dest + n, src, m);
+ dest[n + m] = 0;
+ return dest;
+}
+
+int get_number(const char *string, long *val)
+{
+ long x;
+ char *end;
+
+ errno = 0;
+ x = strtol(string, &end, 10);
+ if(errno || *end)
+ return -1;
+ *val = x;
+ return 0;
+}
+
+char *getword(char *string, const char *delim, char **end)
+{
+ char *ptr;
+ char *word;
+
+ /* skip leading delimiters */
+ for(ptr = string; *ptr && strchr(delim, *ptr); ptr++);
+
+ if(*ptr == 0)
+ return NULL;
+ word = ptr++;
+ /* skip non-delimiters */
+ while(*ptr && !strchr(delim, *ptr))
+ ptr++;
+ *end = (char *)ptr;
+ return word;
+}
+
+char *getstring(char *string, const char *delim, char **end)
+{
+ char *ptr;
+ char *word;
+ int quoted = 0;
+
+ /* skip leading delimiters */
+ for(ptr = string; *ptr && strchr(delim, *ptr); ptr++);
+
+ if(ptr == NULL)
+ return NULL;
+ quoted = (*ptr == '"');
+ if(quoted)
+ for(word = ++ptr; *ptr && *ptr != '"'; ptr++);
+ else
+ for(word = ptr; *ptr && !strchr(delim, *ptr); ptr++);
+ *end = (char *)ptr;
+ return word;
+}
+
+static long pow2(size_t n)
+{
+ long x = 8; /* don't bother allocating less than this */
+
+ while(x < n)
+ x <<= 1L;
+ return x;
+}
+
+void dstring_init(Dstring *dstr)
+{
+ dstr->data = NULL;
+ dstr->size = 0;
+ dstr->length = 0;
+}
+
+int dstring_append(Dstring *dstr, const char *string, int len)
+{
+ if(len < 0)
+ len = strlen(string);
+ if(len) {
+ if(dstr->length + len >= dstr->size) {
+ dstr->size = pow2(dstr->length + len + 1);
+ dstr->data = xrealloc(dstr->data, dstr->size);
+ }
+ memcpy(dstr->data + dstr->length, string, len);
+ dstr->length += len;
+ dstr->data[dstr->length] = 0;
+ } else if(dstr->size == 0) {
+ ASSERT(dstr->data == NULL);
+ dstr->size = 8;
+ dstr->data = xmalloc(8);
+ dstr->data[0] = 0;
+ }
+
+ return dstr->length;
+}
+
+int dstring_copy(Dstring *dstr, int pos, const char *string, int len)
+{
+ ASSERT(pos >= 0);
+ if(len < 0)
+ len = strlen(string);
+ if(len) {
+ if(pos + len >= dstr->length) {
+ dstr->length = pos;
+ return dstring_append(dstr, string, len);
+ }
+ memcpy(dstr->data + pos, string, len);
+ }
+ return dstr->length;
+}
+
+int dstring_insert(Dstring *dstr, int pos, const char *string, int len)
+{
+ ASSERT(pos >= 0);
+ if(pos == dstr->length)
+ return dstring_append(dstr, string, len);
+ if(len < 0)
+ len = strlen(string);
+ if(len) {
+ if(dstr->length + len >= dstr->size) {
+ dstr->size = pow2(dstr->length + len + 1);
+ dstr->data = xrealloc(dstr->data, dstr->size);
+ }
+ /* make room */
+ memmove(dstr->data + pos, dstr->data + pos + len, len);
+ /* now copy */
+ memcpy(dstr->data + pos, string, len);
+ dstr->length += len;
+ dstr->data[dstr->length] = 0;
+ }
+ return dstr->length;
+}
+
+int dstring_new(Dstring *dstr, const char *string, int len)
+{
+ if(len < 0)
+ len = strlen(string);
+ if(len) {
+ dstr->size = pow2(len + 1);
+ dstr->data = xmalloc(dstr->size * len);
+ memcpy(dstr->data, string, len);
+ } else
+ dstring_init(dstr);
+ return dstr->length;
+}
+
+void dstring_reset(Dstring *dstr)
+{
+ if(dstr->data)
+ xfree(dstr->data);
+ dstring_init(dstr);
+}
+
diff --git a/dviware/mdvi/lib/vf.c b/dviware/mdvi/lib/vf.c
new file mode 100644
index 0000000000..86185f3662
--- /dev/null
+++ b/dviware/mdvi/lib/vf.c
@@ -0,0 +1,240 @@
+/* vf.c -- VF font support */
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "mdvi.h"
+#include "private.h"
+
+static int vf_load_font __PROTO((DviParams *, DviFont *));
+static void vf_free_macros __PROTO((DviFont *));
+
+/* only symbol exported by this file */
+DviFontInfo vf_font_info = {
+ "VF",
+ 1, /* virtual fonts scale just fine */
+ vf_load_font,
+ NULL, /* get_glyph */
+ NULL, /* shrink0 */
+ NULL, /* shrink1 */
+ vf_free_macros,
+ NULL, /* reset */
+ NULL, /* lookup */
+ kpse_vf_format,
+ NULL
+};
+
+DviFontInfo ovf_font_info = {
+ "OVF",
+ 1, /* virtual fonts scale just fine */
+ vf_load_font,
+ NULL, /* get_glyph */
+ NULL, /* shrink0 */
+ NULL, /* shrink1 */
+ vf_free_macros,
+ NULL, /* reset */
+ NULL, /* lookup */
+ kpse_ovf_format,
+ NULL
+};
+
+static int vf_load_font(DviParams *params, DviFont *font)
+{
+ FILE *p;
+ Uchar *macros;
+ int msize;
+ int mlen;
+ Int32 checksum;
+ long alpha, beta, z;
+ int op;
+ int i;
+ int nchars;
+ int loc, hic;
+ DviFontRef *last;
+
+ macros = NULL;
+ msize = mlen = 0;
+ p = font->in;
+
+ if(fuget1(p) != 247 || fuget1(p) != 202)
+ goto badvf;
+ mlen = fuget1(p);
+ fseek(p, (long)mlen, SEEK_CUR);
+ checksum = fuget4(p);
+ if(checksum && font->checksum && checksum != font->checksum) {
+ warning(_("%s: Checksum mismatch (expected %u, got %u)\n"),
+ font->fontname, font->checksum, checksum);
+ } else if(!font->checksum)
+ font->checksum = checksum;
+ font->design = fuget4(p);
+
+ /* read all the fonts in the preamble */
+ last = NULL;
+
+ /* initialize alpha, beta and z for TFM width computation */
+ TFMPREPARE(font->scale, z, alpha, beta);
+
+ op = fuget1(p);
+ while(op >= DVI_FNT_DEF1 && op <= DVI_FNT_DEF4) {
+ DviFontRef *ref;
+ Int32 scale, design;
+ Uint32 checksum;
+ int id;
+ int n;
+ int hdpi;
+ int vdpi;
+ char *name;
+
+ /* process fnt_def commands */
+
+ id = fugetn(p, op - DVI_FNT_DEF1 + 1);
+ checksum = fuget4(p);
+ scale = fuget4(p);
+ design = fuget4(p);
+
+ /* scale this font according to our parent's scale */
+ scale = TFMSCALE(scale, z, alpha, beta);
+ design = FROUND(params->tfm_conv * design);
+
+ /* compute the resolution */
+ hdpi = FROUND(params->mag * params->dpi * scale / design);
+ vdpi = FROUND(params->mag * params->vdpi * scale / design);
+ n = fuget1(p) + fuget1(p);
+ name = xmalloc(n + 1);
+ fread(name, 1, n, p);
+ name[n] = 0;
+ DEBUG((DBG_FONTS, "(vf) %s: defined font `%s' at %.1fpt (%dx%d dpi)\n",
+ font->fontname, name,
+ (double)scale / (params->tfm_conv * 0x100000), hdpi, vdpi));
+
+ /* get the font */
+ ref = font_reference(params, id, name, checksum, hdpi, vdpi, scale);
+ if(ref == NULL) {
+ error(_("(vf) %s: could not load font `%s'\n"),
+ font->fontname, name);
+ goto error;
+ }
+ xfree(name);
+ if(last == NULL)
+ font->subfonts = last = ref;
+ else
+ last->next = ref;
+ ref->next = NULL;
+ op = fuget1(p);
+ }
+
+ if(op >= DVI_FNT_DEF1 && op <= DVI_FNT_DEF4)
+ goto error;
+
+ /* This function correctly reads both .vf and .ovf files */
+
+ font->chars = xnalloc(DviFontChar, 256);
+ for(i = 0; i < 256; i++)
+ font->chars[i].offset = 0;
+ nchars = 256;
+ loc = -1; hic = -1;
+ /* now read the characters themselves */
+ while(op <= 242) {
+ int pl;
+ Int32 cc;
+ Int32 tfm;
+
+ if(op == 242) {
+ pl = fuget4(p);
+ cc = fuget4(p);
+ tfm = fuget4(p);
+ } else {
+ pl = op;
+ cc = fuget1(p);
+ tfm = fuget3(p);
+ }
+ if(loc < 0 || cc < loc)
+ loc = cc;
+ if(hic < 0 || cc > hic)
+ hic = cc;
+ if(cc >= nchars) {
+ font->chars = xresize(font->chars,
+ DviFontChar, cc + 16);
+ for(i = nchars; i < cc + 16; i++)
+ font->chars[i].offset = 0;
+ nchars = cc + 16;
+ }
+ if(font->chars[cc].offset) {
+ error(_("(vf) %s: character %d redefined\n"),
+ font->fontname, cc);
+ goto error;
+ }
+
+ DEBUG((DBG_GLYPHS, "(vf) %s: defined character %d (macro length %d)\n",
+ font->fontname, cc, pl));
+ font->chars[cc].width = pl + 1;
+ font->chars[cc].code = cc;
+ font->chars[cc].tfmwidth = TFMSCALE(tfm, z, alpha, beta);
+ font->chars[cc].offset = mlen;
+ font->chars[cc].loaded = 1;
+ if(mlen + pl + 1 > msize) {
+ msize = mlen + pl + 256;
+ macros = xresize(macros, Uchar, msize);
+ }
+ if(pl && fread(macros + mlen, 1, pl, p) != pl)
+ break;
+ macros[mlen+pl] = DVI_EOP;
+ mlen += pl + 1;
+ op = fuget1(p);
+ }
+ if(op != 248) {
+ error(_("(vf) %s: no postamble\n"), font->fontname);
+ goto error;
+ }
+
+ /* make macro memory just big enough */
+ if(msize > mlen) {
+ macros = xresize(macros, Uchar, mlen);
+ msize = mlen;
+ }
+
+ DEBUG((DBG_FONTS|DBG_GLYPHS,
+ "(vf) %s: macros use %d bytes\n", font->fontname, msize));
+
+ if(loc > 0 || hic < nchars-1) {
+ memmove(font->chars, font->chars + loc,
+ (hic - loc + 1) * sizeof(DviFontChar));
+ font->chars = xresize(font->chars,
+ DviFontChar, hic - loc + 1);
+ }
+ font->loc = loc;
+ font->hic = hic;
+ font->private = macros;
+
+ return 0;
+
+badvf:
+ error(_("%s: File corrupted, or not a VF file.\n"), font->fontname);
+error:
+ if(font->chars)
+ xfree(font->chars);
+ if(macros)
+ xfree(macros);
+ return -1;
+}
+
+static void vf_free_macros(DviFont *font)
+{
+ xfree(font->private);
+}