/*
 * dvi.h --
 *
 *      This header file describes the internal data structures of the
 *      DVI widget.
 *
 * Copyright © 1999 Anselm Lingnau <lingnau@tm.informatik.uni-frankfurt.de>
 * See file COPYING for conditions on use and distribution.
 *
 * $Id: dvi.h,v 1.7 2000/06/29 10:54:42 lingnau Exp $
 */

#ifndef DVI_H
#define DVI_H

#define DVI_NAME "dvi"
#define DVI_VERSION "0.2"
#define DVI_MAJOR_VERSION 0
#define DVI_MINOR_VERSION 2

#include <stdlib.h>
#include <time.h>		/* for time_t */
#include <sys/stat.h>
#include "tcl.h"

#ifndef DVI_DEBUG
#define DVI_DEBUG 1
#endif

/*
 * Here are typedefs that we use for the various quantities that occur
 * in DVI files.
 */
/*#include "typedefs.h"*/

typedef signed char S8;
typedef unsigned char U8;
typedef signed short S16;
typedef unsigned short U16;

#if SIZEOF_INT == 4
typedef signed int S32;
typedef unsigned int U32;
#define MAX_S32 2147483647
#define MIN_S32 (-2147483647 - 1)
#define MAX_U32 4294967295
#define S32FMT "%d"

#elif SIZEOF_LONG == 4
typedef signed long S32;
typedef unsigned long U32;
#define MAX_S32 2147483647L
#define MIN_S32 (-2147483647L - 1)
#define MAX_U32 4294967295UL
#define S32FMT "%ld"

#else
#error "We don\'t seem to have a 4-byte data type."
#endif /* SIZEOF...*/

/*
 * This structure describes a page in terms of its page numbers. A DVI
 * page is identified either by its `absolute' number in the file
 * (counting from 1 to dviFile->pageCount) or by a page specification
 * made up of the ten counters within the D_BOP DVI command.
 */

typedef struct Dvi_PageSpec {
        int countersUsed;	/* number of counters used in specification */
        unsigned int careVector; /* bits: do we care about this number? */
        unsigned int occurrences; /* search for k-th occurrence of spec */
        S32 number[10];         /* desired page numbers (may be negative) */
} Dvi_PageSpec;

#define DVI_PS_ABSOLUTE (-1)	/* countersUsed = ... indicates absolute pn */
#define DVI_PS_IGNORE(p, i)     (((p)->careVector & (1 << (i))) == 0)

#define DVI_PS_NOCURRPAGE       (30000)
#define DVI_PS_NOSUCHPAGE       (30001)
#define DVI_PS_NOMATCH          (30002)

struct Dvi_Code;

EXTERN int Dvi_CodeGetPageNumbers _ANSI_ARGS_((struct Dvi_Code *codePtr,
					       unsigned int absPageNo,
					       long *pageNoPtr));
EXTERN int Dvi_CodeFindTeXPage _ANSI_ARGS_((struct Dvi_Code *codePtr,
					    Dvi_PageSpec *pageSpecPtr));
EXTERN U8 *Dvi_CodeFindCodeForPage _ANSI_ARGS_((struct Dvi_Code *codePtr,
						unsigned int absPageNo));
EXTERN int Dvi_CodeGetPageSpec _ANSI_ARGS_((char *string,
					    Dvi_PageSpec *pageSpecPtr));

typedef struct Dvi_PageInfo {
    U8 *code;			/* Start of DVI code for page */
} Dvi_PageInfo;

struct Dvi_File;
struct Dvi_FileInfo;

/*
 * This data structure describes the structure of a bunch of DVI pages.
 * This can refer to the contents of a DVI file, but doesn't have to.
 */

typedef struct Dvi_Code {
    U32 num;			/* Numerator for DVI metrics (cf DVI format) */
    U32 den;			/* Denominator for DVI metrics */
    U32 mag;			/* Magnification value for document */
    
    unsigned int stackSize;	/* Maximum size of DVI stack necessary */
    unsigned int pageCount;	/* Number of DVI pages */
    
    unsigned int pageTableSize;	/* Current max size of page table */
    Dvi_PageInfo *pageTable;

    /* struct Dvi_File *dviFile; */
} Dvi_Code;

typedef int (Dvi_CodeAnchorRegisterProc) _ANSI_ARGS_((ClientData clientData,
						      char *anchor,
						      unsigned int pageNum));

EXTERN Dvi_Code *Dvi_CodeCreate _ANSI_ARGS_((long num, long den, long mag,
					     unsigned int stackSize,
					     unsigned int pageCount));
EXTERN Dvi_Code *Dvi_CodeCreateFromFileInfo
    _ANSI_ARGS_((struct Dvi_FileInfo*,
		 Dvi_CodeAnchorRegisterProc *anchorRegisterProc,
		 ClientData anchorRegisterClientData));

/*
 * This structure describes a loaded DVI file. It contains various items
 * of information about the file on disk and in memory.
 */

typedef struct Dvi_FileInfo {
    struct Dvi_FileInfo *nextPtr;
    char *name;			/* Name of the file */
    dev_t devNo;		/* Device number of the file */
    ino_t inodeNo;		/* Inode number of the file */
    int refCount;		/* Reference count for file */
    int fileDesc;		/* O/S file descriptor */
    off_t fileSize;		/* Size of file in bytes */
    time_t lastModTime;		/* Time of last modification of file */
    U8 *contents;		/* Byte contents of the file */
    U8 *postamble;		/* Pointer to postamble (if available) */
    unsigned long generation;	/* Times this file has been reloaded */
    struct Dvi_Code *codePtr;	/* DVI file structure */
} Dvi_FileInfo;

typedef void (Dvi_ReloadProc) _ANSI_ARGS_((ClientData clientData,
					   struct Dvi_File *dviFile));
typedef int (Dvi_ErrorProc) _ANSI_ARGS_((ClientData clientData,
					 const char *errMsg));
typedef struct Dvi_File {
    struct Dvi_File *nextPtr;	/* Next entry in chain */
    Dvi_FileInfo *infoPtr;	/* Actual DVI file information */
    Dvi_ReloadProc *reloadProc; /* Invoked if underlying file was reloaded */
    ClientData reloadClientData; /* for reloadProc */
} Dvi_File;

#define DVI_FILEINFO(d) ((d)->infoPtr)

#define DVI_MIN_STACK 100	/* Minimum DVI stack size (cf. DVI driver */
				/* standard) (Hallo Joachim!) */

EXTERN Dvi_File *Dvi_FileOpen _ANSI_ARGS_((const char *name,
					   Dvi_ReloadProc *reloadProc,
					   ClientData reloadClientData,
					   Dvi_ErrorProc *errorProc,
					   ClientData errorClientData));
EXTERN int Dvi_FileChanged _ANSI_ARGS_((Dvi_File *dviFile));
EXTERN int Dvi_FileClose _ANSI_ARGS_((Dvi_File *dviFile));
EXTERN int Dvi_FileReload _ANSI_ARGS_((Dvi_File *dviFile,
				       Dvi_ErrorProc *errorProc,
				       ClientData errorClientData));
EXTERN int Dvi_FileParameters _ANSI_ARGS_((Dvi_FileInfo *dviFileInfoPtr,
					   unsigned char **postPtr,
					   long *numPtr,
					   long *denPtr,
					   long *magPtr,
					   unsigned int *stackSizePtr,
					   unsigned int *pageCountPtr));
EXTERN void Dvi_FileComment _ANSI_ARGS_((Dvi_File *dviFile, char **commentPtr,
					 unsigned int *lengthPtr));

EXTERN U8 *Dvi_LoadFileBinary _ANSI_ARGS_((const char *name));
EXTERN Tcl_Obj *Dvi_ListPageNumbers _ANSI_ARGS_((Dvi_File *dviFile));

#ifdef DVI_DEBUG
EXTERN int Dvi_PurgeFiles _ANSI_ARGS_((void));
EXTERN int Dvi_FileDump _ANSI_ARGS_((Tcl_DString *string, Dvi_File *filePtr));
EXTERN int Dvi_FileDumpAll _ANSI_ARGS_((Tcl_DString *string));
#endif /* DVI_DEBUG */

typedef enum Dvi_FontType {
    dvi_font_pk = 0,
    dvi_font_vf = 1,
    dvi_font_tfm = 2,
    dvi_font_invalid
} Dvi_FontType;

struct Dvi_Interp;
struct Dvi_Font;
struct Dvi_FontList;

/*
 * The following data structure represents an unpacked glyph. The glyph
 * bitmap is stuffed right after this header into a big allocation.
 */

typedef struct Dvi_Glyph {
    unsigned int width, height; /* Width and height of unpacked glyph */
    unsigned int bytesWidth;	/* Width in bytes */
    int horizOffset, vertOffset; /* Reference point offset */
    U8 *renderData;		/* For speed on X11 */
    ClientData fgUid;		/* For colour support. */
    int shrink;			/* Shrink factor for shrinkGlyphPtr */
    int hShrinkOffset, vShrinkOffset;
    void *shrinkGlyphPtr;	/* Cache for shrunken bitmap */
} Dvi_Glyph;

typedef int (Dvi_FontLoadProc) _ANSI_ARGS_((struct Dvi_Interp *dviInterp,
                                            struct Dvi_Font *dviFont));
typedef Dvi_Glyph * (Dvi_FontGlyphProc) _ANSI_ARGS_((struct Dvi_Font *dviFont,
                                                     S32 character,
                                                     S32 *tfmWidthPtr,
                                                     S32 *pixelWidthPtr));
typedef int (Dvi_FontCloseProc) _ANSI_ARGS_((struct Dvi_Font *dviFont));

typedef struct Dvi_FontTypeDesc {
    char *name;
    Dvi_FontLoadProc *loadProc;
    Dvi_FontGlyphProc *glyphProc;
    Dvi_FontCloseProc *closeProc;
} Dvi_FontTypeDesc;

EXTERN int Dvi_CreateFontType _ANSI_ARGS_((Dvi_FontType type, char *name,
                                           Dvi_FontLoadProc *loadProc,
                                           Dvi_FontGlyphProc *glyphProc,
                                           Dvi_FontCloseProc *closeProc));
EXTERN int Dvi_CreateFontType_PK _ANSI_ARGS_((void));
EXTERN int Dvi_CreateFontType_VF _ANSI_ARGS_((void));
EXTERN int Dvi_CreateFontType_TFM _ANSI_ARGS_((void));

/*
 * This structure describes a DVI font.
 */

typedef struct Dvi_Font {
    struct Dvi_Font *nextPtr;	/* next font in table */
    int refCount;		/* number of interpreters using this font */
    char *fontName;		/* DVI internal name */
    char *fileName;		/* External file name */
    Dvi_FontType type;		/* PK, Virtual, TFM, ... */
    unsigned int resolution;	/* Font resolution (dots per inch) */
    U32 designSize;		/* Font design size */
    U32 fontScale;		/* Scaling factor */
    U32 check;			/* Font checksum */
    U8 *bytes;			/* Pointer to font file if loaded */
    ClientData fontData;	/* Type-specific per-font data */
} Dvi_Font;

EXTERN int Dvi_FontAdd _ANSI_ARGS_((struct Dvi_Interp *dviInterp,
				    struct Dvi_FontList **fontListPtr,
				    S32 fontNum,
                                    U32 check, U32 fontScale, U32 designSize,
                                    size_t nameLen, char *name));
EXTERN Dvi_Font * Dvi_FontFind _ANSI_ARGS_((struct Dvi_Interp *dviInterp,
                                            U32 check, U32 fontScale,
                                            U32 designSize,
                                            size_t nameLen, char *name));
EXTERN Dvi_Font * Dvi_FontNew _ANSI_ARGS_((struct Dvi_Interp *dviInterp,
                                           U32 check, U32 fontScale,
                                           U32 designSize,
                                           size_t nameLen, char *name));
EXTERN void Dvi_FontFree _ANSI_ARGS_((Dvi_Font *fontPtr));
EXTERN void Dvi_FontPurge _ANSI_ARGS_((void));

EXTERN Dvi_Glyph * Dvi_FontGetGlyph _ANSI_ARGS_((Dvi_Font *dviFont,
                                                 S32 character,
                                                 S32 *tfmWidthPtr,
                                                 S32 *pixelWidthPtr));
#ifdef DVI_DEBUG
EXTERN Tcl_Obj * Dvi_FontDump _ANSI_ARGS_((Tcl_Interp *interp,
					   Dvi_Font *dviFont));
EXTERN Tcl_Obj * Dvi_FontDumpAll _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Dvi_FontDumpGlyph _ANSI_ARGS_((struct Dvi_Interp *dviInterp,
                                          U32 fontSize, char *name,
                                          S32 character, Tcl_DString *string));
#endif

EXTERN char *Dvi_FindFontFile _ANSI_ARGS_((unsigned int nameLen, char *name,
                                           unsigned int *resPtr,
                                           Dvi_FontType *typePtr));

EXTERN int Dvi_GetVFInfo _ANSI_ARGS_((Dvi_Font *dviFont, S32 character,
				      S32 *tfmWidthPtr, S32 *pixelWidthPtr,
				      Dvi_Font **firstFontPtr, U8 **codePtrPtr,
				      struct Dvi_FontList **fontListPtrPtr));

/*
 * This structure represents a frame on the DVI evaluation stack.
 */

typedef struct Dvi_StackFrame {
    S32 h, v, w, x, y, z, hh, vv; /* DVI virtual machine registers */
} Dvi_StackFrame;

/*
 * This structure is used to translate from DVI font numbers to the
 * corresponding fonts. There is a list of these for every DVI interpreter.
 */

typedef struct Dvi_FontList {
    struct Dvi_FontList *nextPtr; /* next font in list */
    S32 fontNum;		/* number of font in this DVI interpreter */
    Dvi_Font *fontPtr;		/* pointer to font in repository */
} Dvi_FontList;

typedef enum {
    DVI_FMODE_DVI,
    DVI_FMODE_POST,
    DVI_FMODE_VF
} Dvi_FontDefMode;

/*
 * Types for various kinds of procedures used in DVI rendering.
 */

typedef void (Dvi_GlyphProc) _ANSI_ARGS_((ClientData clientData,
                                          struct Dvi_Interp *dviInterp,
                                          S32 x, S32 y,
                                          Dvi_Font *fontPtr, S32 character,
                                          S32 *tfmWidthPtr, S32 *pixWidthPtr));
typedef void (Dvi_RuleProc) _ANSI_ARGS_((ClientData clientData,
                                         struct Dvi_Interp *dviInterp,
                                         S32 x, S32 y, S32 height, S32 width));
typedef int (Dvi_FontDefProc) _ANSI_ARGS_((ClientData clientData,
                                           struct Dvi_Interp *dviInterp,
                                           Dvi_FontList **fontListPtr,
					   S32 fontNum, U32 check,
					   U32 fontScale, U32 designSize,
                                           size_t nameLen, char *name,
                                           Dvi_FontDefMode mode));
typedef int (Dvi_SpecialProc) _ANSI_ARGS_((ClientData clientData,
                                           struct Dvi_Interp *dviInterp,
                                           U8 *code, S32 x, S32 y,
                                           U32 length, const char *string));

/*
 * This structure describes a DVI interpreter.
 */

typedef struct Dvi_Interp {
    Tcl_Interp *interp;		/* Tcl interpreter for error reporting etc. */
    Dvi_Code *dviCode;		/* Code that this interpreter works on */

    unsigned int xResolution;	/* Horizontal resol. of rendering device */
    unsigned int yResolution;	/* Vertical resolution of rendering device */
    double tfmConv;		/* Conversion factor for TFM units (sp) */
    double xConv, yConv;	/* Conversion factors from sp to resolution */
    double trueXConv, trueYConv;
    unsigned int maxDrift;	/* maximum fuzz factor for DVI rendering */
    unsigned int stackSize;	/* DVI evaluation stack size */
    unsigned int stackPtr;	/* DVI evaluation stack pointer */
    Dvi_StackFrame *stack;	/* DVI evaluation stack */
    Dvi_FontList *fonts;	/* Main font translation table */
    ClientData procData;
    Dvi_GlyphProc *glyphProc;	/* Procedures used in rendering */
    Dvi_RuleProc *ruleProc;
    Dvi_FontDefProc *fontDefProc;
    Dvi_SpecialProc *specialProc;
} Dvi_Interp;

EXTERN Dvi_Interp *Dvi_CreateInterp _ANSI_ARGS_((Tcl_Interp *interp,
                                                 unsigned int xRes,
                                                 unsigned int yRes,
                                                 unsigned int stackSize,
                                                 U32 num, U32 den, U32 mag));
EXTERN Dvi_Interp *Dvi_CreateInterpForCode _ANSI_ARGS_((Tcl_Interp *interp,
							unsigned int xRes,
							unsigned int yRes,
							Dvi_Code *dviCode));
EXTERN int Dvi_SetResolution _ANSI_ARGS_((Dvi_Interp *dviInterp,
                                          unsigned int xRes, unsigned int yRes,
                                          U32 num, U32 den, U32 mag));
EXTERN void Dvi_DeleteInterp _ANSI_ARGS_((Dvi_Interp *dviInterp));
EXTERN void Dvi_ResetInterp _ANSI_ARGS_((Dvi_Interp *dviInterp,
                                         int clearFonts));

EXTERN int Dvi_FontsFromPostamble _ANSI_ARGS_((Dvi_Interp *dviInterp,
                                               Dvi_File *dviFile));

EXTERN U8 *Dvi_ProcessFontDef _ANSI_ARGS_((Dvi_Interp *dviInterp,
					   Dvi_FontList **fontListPtr,
					   S32 fontNum, U8 *fontDefPtr,
					   Dvi_FontDefMode mode));
EXTERN int Dvi_Interpret _ANSI_ARGS_((Dvi_Interp *dviInterp, U8 *code));
EXTERN int Dvi_DoInterpret _ANSI_ARGS_((Dvi_Interp *dviInterp, U8 *code,
					Dvi_Font *f,
					Dvi_FontList *fontListPtr));

EXTERN Dvi_File *Dvi_GetFileByCookie _ANSI_ARGS_((Tcl_Interp *interp,
						  const char *cookie,
						  const int flags));

/*
 * Procedures from dviTcl.c:
 */

EXTERN int Dvi_GetPixels _ANSI_ARGS_((Tcl_Interp *interp,
				      const int resolution, const char *string,
				      int *result, int flags));

EXTERN int Dvi_TclGetPageNumbers _ANSI_ARGS_((Tcl_Interp *interp,
					      Dvi_Code *codePtr,
					      Tcl_Obj *pageNoObj));

EXTERN int Dvi_Init _ANSI_ARGS_((Tcl_Interp *interp));

#endif /* DVI_H */
