]> www.fi.muni.cz Git - evince.git/commitdiff
New directory with the beginning of a .dvi backend.
authorSøren Sandmann <sandmann@redhat.com>
Tue, 21 Dec 2004 23:57:26 +0000 (23:57 +0000)
committerSøren Sandmann Pedersen <ssp@src.gnome.org>
Tue, 21 Dec 2004 23:57:26 +0000 (23:57 +0000)
Tue Dec 21 18:55:06 2004  Søren Sandmann  <sandmann@redhat.com>

* dvi/*: New directory with the beginning of a .dvi backend.

32 files changed:
ChangeLog
dvi/Makefile [new file with mode: 0644]
dvi/dvilib/TODO [new file with mode: 0644]
dvi/dvilib/dl-dvi-file.cc [new file with mode: 0755]
dvi/dvilib/dl-dvi-file.hh [new file with mode: 0755]
dvi/dvilib/dl-dvi-fontdefinition.cc [new file with mode: 0755]
dvi/dvilib/dl-dvi-fontdefinition.hh [new file with mode: 0755]
dvi/dvilib/dl-dvi-parser.cc [new file with mode: 0755]
dvi/dvilib/dl-dvi-parser.hh [new file with mode: 0755]
dvi/dvilib/dl-dvi-program.cc [new file with mode: 0755]
dvi/dvilib/dl-dvi-program.hh [new file with mode: 0755]
dvi/dvilib/dl-dvi-runtime.cc [new file with mode: 0755]
dvi/dvilib/dl-dvi-runtime.hh [new file with mode: 0755]
dvi/dvilib/dl-font.hh [new file with mode: 0755]
dvi/dvilib/dl-loader.cc [new file with mode: 0755]
dvi/dvilib/dl-loader.hh [new file with mode: 0755]
dvi/dvilib/dl-pkfont.cc [new file with mode: 0755]
dvi/dvilib/dl-pkfont.hh [new file with mode: 0755]
dvi/dvilib/dl-refcounted.hh [new file with mode: 0755]
dvi/dvilib/dl-vffont.cc [new file with mode: 0755]
dvi/dvilib/dl-vffont.hh [new file with mode: 0755]
dvi/fest.tex [new file with mode: 0644]
dvi/font.cc [new file with mode: 0755]
dvi/font.hh [new file with mode: 0755]
dvi/main.cc [new file with mode: 0755]
dvi/model.cc [new file with mode: 0755]
dvi/model.hh [new file with mode: 0755]
dvi/observer.hh [new file with mode: 0755]
dvi/painter.cc [new file with mode: 0755]
dvi/painter.hh [new file with mode: 0755]
dvi/view.cc [new file with mode: 0755]
dvi/view.hh [new file with mode: 0755]

index d82900e881e8fa78de126de75130ee68d1b248d5..fbeec1a2ebb4a35f44f5fa8d0abc0f048131fe62 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Tue Dec 21 18:55:06 2004  Søren Sandmann  <sandmann@redhat.com>
+
+       * dvi/*: New directory with the beginning of a .dvi backend.
+
 2004-12-21  Havoc Pennington  <hp@redhat.com>
 
        * shell/eggfindbar.c (egg_find_bar_init): change buttons to
diff --git a/dvi/Makefile b/dvi/Makefile
new file mode 100644 (file)
index 0000000..3ba3611
--- /dev/null
@@ -0,0 +1,38 @@
+binary = dviviewer
+
+sources =                                      \
+       main.cc                                 \
+                                               \
+       painter.cc                              \
+       font.cc                                 \
+       view.cc                                 \
+       model.cc                                \
+                                               \
+       dvilib/dl-dvi-file.cc                   \
+       dvilib/dl-dvi-fontdefinition.cc         \
+       dvilib/dl-dvi-parser.cc                 \
+       dvilib/dl-dvi-program.cc                \
+       dvilib/dl-dvi-runtime.cc                \
+       dvilib/dl-loader.cc                     \
+       dvilib/dl-pkfont.cc                     \
+       dvilib/dl-vffont.cc
+
+headers =                                      \
+       painter.hh                              \
+       font.hh                                 \
+       view.hh                                 \
+       model.hh                                \
+                                               \
+       dvilib/dl-dvi-file.hh                   \
+       dvilib/dl-dvi-fontdefinition.hh         \
+       dvilib/dl-dvi-parser.hh                 \
+       dvilib/dl-dvi-runtime.hh                \
+       dvilib/dl-font.hh                       \
+       dvilib/dl-loader.hh                     \
+       dvilib/dl-pkfont.hh                     \
+       dvilib/dl-vffont.hh
+
+CFLAGS = -Idvilib -Wall -W -ansi -pedantic -g -O0 `pkg-config --cflags gtk+-2.0`
+
+$(binary): $(sources) $(headers)
+       c++ $(CFLAGS) $(sources) -o$(binary) -lfl `pkg-config --libs gtk+-2.0`
diff --git a/dvi/dvilib/TODO b/dvi/dvilib/TODO
new file mode 100644 (file)
index 0000000..fb58cb3
--- /dev/null
@@ -0,0 +1,2 @@
+- Add a cache so we don't call kpsewhich for each font
+- possibly make cache persistent so we don't have to call kpsewhich on startup
diff --git a/dvi/dvilib/dl-dvi-file.cc b/dvi/dvilib/dl-dvi-file.cc
new file mode 100755 (executable)
index 0000000..1739be9
--- /dev/null
@@ -0,0 +1,50 @@
+#include "dl-dvi-file.hh"
+#include "dl-dvi-parser.hh"
+
+using namespace DviLib;
+
+DviFile::DviFile (AbstractLoader& l) :
+    loader (l)
+{
+    DviParser parser (loader);
+    
+    preamble = parser.parse_preamble ();
+    postamble = parser.parse_postamble ();
+    
+    n_pages = 0;
+    uint page_pointer = postamble->last_page_address;
+
+    cout << page_pointer << endl;
+
+    while (page_pointer != (uint)-1)
+    {
+       loader.goto_from_start (page_pointer);
+       
+       page_headers[n_pages++] = 
+           parser.parse_page_header (&page_pointer);
+    }
+}
+
+DviPage *
+DviFile::get_page (uint n)
+{
+    DviPage *page = pages[n];
+    
+    if (n > get_n_pages())
+       return 0;
+    
+    if (page == 0)
+    {
+       DviParser parser (loader);
+       DviPageHeader *header;
+       DviProgram *program;
+       
+       header = page_headers[n];
+       loader.goto_from_start (header->address + 45);
+       program = parser.parse_program ();
+       
+       page = new DviPage (*header, *program);
+    }
+    
+    return page;
+}
diff --git a/dvi/dvilib/dl-dvi-file.hh b/dvi/dvilib/dl-dvi-file.hh
new file mode 100755 (executable)
index 0000000..d6c0201
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef DL_DVI_FILE_HH
+#define DL_DVI_FILE_HH
+
+#include "dl-dvi-program.hh"
+#include <map>
+#include <list>
+#include <algorithm>
+#include "dl-dvi-fontdefinition.hh"
+#include "dl-loader.hh"
+
+namespace DviLib {
+    const uint N_PAGE_COUNTERS = 10;          // \count0 ... \count9
+    
+    class DviPageHeader : public RefCounted {
+    public:
+       int count[N_PAGE_COUNTERS];
+       uint address;          // address of this page, not the preceding
+    };
+    
+    class DviPage : public AbstractDviProgram { 
+       DviProgram& program;
+       int count[N_PAGE_COUNTERS];        // \count0 ... \count9
+    public:
+       DviPage (DviProgram& p, int c[N_PAGE_COUNTERS]) :
+           program (p)
+       {
+           for (uint i=0; i<N_PAGE_COUNTERS; ++i)
+               count[i] = c[i];
+       }
+       DviPage (DviPageHeader& h, DviProgram& p) :
+           program (p)
+       {
+           for (uint i=0; i<N_PAGE_COUNTERS; ++i)
+               count[i] = h.count[i];
+       }
+       virtual void execute (DviRuntime& runtime)
+       {
+           program.execute (runtime);
+       }
+       int get_page_count (int i) { return count[i]; }
+    };
+    
+    enum DviType {
+       NORMAL_DVI  = 2, // FIXME: this should be 2
+       TEX_XET_DVI = 2  // FIXME: is this correct?
+    };
+    
+    class DviFilePreamble : public RefCounted {
+    public:
+       // preamble
+       DviType type;
+       uint magnification;
+       uint numerator;
+       uint denominator;
+       string comment;
+    };
+    
+    class DviFilePostamble : public RefCounted {
+    public:
+       // postamble
+       DviType type;
+       uint magnification;
+       uint numerator;
+       uint denominator;
+       
+       uint last_page_address;
+       uint max_height;
+       uint max_width;
+       uint stack_height;
+       map <uint, DviFontdefinition *> fontdefinitions;
+    };
+    
+    class DviFile : public RefCounted {
+       AbstractLoader &loader;
+       
+       DviFilePreamble *preamble;
+       DviFilePostamble *postamble;
+       
+       uint n_pages;
+       map <uint, DviPageHeader *> page_headers;
+       map <uint, DviPage *> pages;
+       
+    public:
+       DviFile (AbstractLoader& l);
+       DviPage *get_page (uint n);     /* unref it when done */
+       ~DviFile (void) {}
+       uint get_n_pages () { return n_pages; }
+       DviFontdefinition *get_fontdefinition (uint n) 
+       {
+           return postamble->fontdefinitions[n];
+       }
+       uint get_numerator () { return postamble->numerator; }
+       uint get_denominator () { return postamble->denominator; }
+       uint get_magnification () { return postamble->magnification; }
+    };
+    
+}    
+#endif // DL_DVI_FILE_HH
+
diff --git a/dvi/dvilib/dl-dvi-fontdefinition.cc b/dvi/dvilib/dl-dvi-fontdefinition.cc
new file mode 100755 (executable)
index 0000000..553ea28
--- /dev/null
@@ -0,0 +1,3 @@
+#include "dl-dvi-fontdefinition.hh"
+
+using namespace DviLib;
diff --git a/dvi/dvilib/dl-dvi-fontdefinition.hh b/dvi/dvilib/dl-dvi-fontdefinition.hh
new file mode 100755 (executable)
index 0000000..e6bb0d6
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef DL_FONT_DEFINITION_HH__
+#define DL_FONT_DEFINITION_HH__
+
+#include <string>
+
+#include "dl-refcounted.hh"
+
+namespace DviLib {
+    
+    class DviFontdefinition : public RefCounted {
+    public:
+       uint fontnum;
+       uint checksum;
+       uint at_size;           /* if 300 dpi base, 
+                                * load at at_size * 300 / 1000 */
+       uint design_size;
+       string directory;
+       string name;
+    };
+
+}    
+#endif // DL_FONT_DEFINITION_HH__
diff --git a/dvi/dvilib/dl-dvi-parser.cc b/dvi/dvilib/dl-dvi-parser.cc
new file mode 100755 (executable)
index 0000000..7caac02
--- /dev/null
@@ -0,0 +1,581 @@
+#include "dl-dvi-parser.hh"
+
+using namespace DviLib;
+
+enum DviOpcode {
+    DVI_SETCHAR0 = 0, /* 128 of these */
+    DVI_SETCHAR127 = 127,
+    DVI_SET1,
+    DVI_SET2, 
+    DVI_SET3, 
+    DVI_SET4,
+    DVI_SETRULE,
+    DVI_PUT1,
+    DVI_PUT2,
+    DVI_PUT3,
+    DVI_PUT4,
+    DVI_PUTRULE,
+    DVI_NOP,
+    DVI_BOP,
+    DVI_EOP,
+    DVI_PUSH,
+    DVI_POP,
+    DVI_RIGHT1,
+    DVI_RIGHT2,
+    DVI_RIGHT3,
+    DVI_RIGHT4,
+    DVI_W0,
+    DVI_W1,
+    DVI_W2,
+    DVI_W3,
+    DVI_W4,
+    DVI_X0,
+    DVI_X1,
+    DVI_X2,
+    DVI_X3,
+    DVI_X4,
+    DVI_DOWN1,
+    DVI_DOWN2,
+    DVI_DOWN3,
+    DVI_DOWN4,
+    DVI_Y0,
+    DVI_Y1,
+    DVI_Y2,
+    DVI_Y3,
+    DVI_Y4,
+    DVI_Z0,
+    DVI_Z1,
+    DVI_Z2,
+    DVI_Z3,
+    DVI_Z4, 
+    DVI_FONTNUM0 = 171, /* 64 of these */
+    DVI_FONTNUM63 = 234,
+    DVI_FNT1,
+    DVI_FNT2,
+    DVI_FNT3,
+    DVI_FNT4,
+    DVI_XXX1,
+    DVI_XXX2,
+    DVI_XXX3,
+    DVI_XXX4,
+    DVI_FNTDEF1,
+    DVI_FNTDEF2,
+    DVI_FNTDEF3,
+    DVI_FNTDEF4,
+    DVI_PRE,
+    DVI_POST,
+    DVI_POSTPOST = 249
+};
+
+static void 
+skip_font_definition (AbstractLoader& l, uint *count)
+{ 
+    *count += 12;
+    l.skip_n (12);
+    
+    *count += 2;
+    uint dl = l.get_uint8();
+    uint nl = l.get_uint8();
+    
+    *count += dl+nl;
+    l.skip_n (dl+nl);
+}
+
+static DviCommand *
+parse_command (AbstractLoader &l, uint *count, DviOpcode *opcode)
+{
+    int h, w;
+    string error;
+    string s;
+    
+    *opcode = (DviOpcode)l.get_uint8 ();
+    *count += 1;
+    
+    if (DVI_SETCHAR0 <= *opcode && *opcode <= DVI_SETCHAR127)
+       return new DviSetCharCommand (*opcode);
+    else if (DVI_FONTNUM0 <= *opcode && *opcode <= DVI_FONTNUM63)
+       return new DviFontNumCommand (*opcode - DVI_FONTNUM0);
+    else switch (*opcode) {
+    case DVI_SET1:
+       *count += 1;
+       return new DviSetCharCommand (l.get_uint8());
+       break;
+    case DVI_SET2:
+       *count += 2;
+       return new DviSetCharCommand (l.get_uint16());
+       break;
+    case DVI_SET3:
+       *count += 3;
+       return new DviSetCharCommand (l.get_uint24());
+       break;
+    case DVI_SET4:
+       *count += 4;
+       return new DviSetCharCommand (l.get_uint32());
+       break;
+    case DVI_SETRULE:
+       *count += 8;
+       h = l.get_int32 ();
+       w = l.get_int32 ();
+       return new DviSetRuleCommand (h, w);
+       break;
+    case DVI_PUT1:
+       *count += 1;
+       return new DviPutCharCommand (l.get_uint8());
+       break;
+    case DVI_PUT2:
+       *count += 2;
+       return new DviPutCharCommand (l.get_uint16());
+       break;
+    case DVI_PUT3:
+       *count += 3;
+       return new DviPutCharCommand (l.get_uint24());
+       break;
+    case DVI_PUT4:
+       *count += 4;
+       return new DviPutCharCommand (l.get_uint32());
+       break;
+    case DVI_PUTRULE:
+       *count += 8;
+       h = l.get_int32();
+       w = l.get_int32();
+       return new DviPutRuleCommand (h, w);
+       break;
+    case DVI_PUSH:
+       return new DviPushCommand();
+       break;
+    case DVI_POP:
+       return new DviPopCommand();
+       break;
+    case DVI_RIGHT1:
+       *count += 1;
+       return new DviRightCommand (l.get_int8());
+       break;
+    case DVI_RIGHT2:
+       *count += 2;
+       return new DviRightCommand (l.get_int16());
+       break;
+    case DVI_RIGHT3:
+       *count += 3;
+       return new DviRightCommand (l.get_int24());
+       break;
+    case DVI_RIGHT4:
+       *count += 4;
+       return new DviRightCommand (l.get_int32());
+       break;
+    case DVI_W0:
+       return new DviWRepCommand ();
+       break;
+    case DVI_W1:
+       *count += 1;
+       return new DviWCommand (l.get_int8());
+       break;
+    case DVI_W2:
+       *count += 2;
+       return new DviWCommand (l.get_int16());
+       break;
+    case DVI_W3:
+       *count += 3;
+       return new DviWCommand (l.get_int24());
+       break;
+    case DVI_W4:
+       *count += 4;
+       return new DviWCommand (l.get_int32());
+       break;
+    case DVI_X0:
+       return new DviXRepCommand ();
+       break;
+    case DVI_X1:
+       *count += 1;
+       return new DviXCommand (l.get_int8());
+       break;
+    case DVI_X2:
+       *count += 2;
+       return new DviXCommand (l.get_int16());
+       break;
+    case DVI_X3:
+       *count += 3;
+       return new DviXCommand (l.get_int24());
+       break;
+    case DVI_X4:
+       *count += 4;
+       return new DviXCommand (l.get_int32());
+       break;
+    case DVI_DOWN1:
+       *count += 1;
+       return new DviDownCommand (l.get_int8());
+       break;
+    case DVI_DOWN2:
+       *count += 2;
+       return new DviDownCommand (l.get_int16());
+       break;
+    case DVI_DOWN3:
+       *count += 3;
+       return new DviDownCommand (l.get_int24());
+       break;
+    case DVI_DOWN4:
+       *count += 4;
+       return new DviDownCommand (l.get_int32());
+       break;
+    case DVI_Y0:
+       return new DviYRepCommand ();
+       break;
+    case DVI_Y1:
+       *count += 1;
+       return new DviYCommand (l.get_int8());
+       break;
+    case DVI_Y2:
+       *count += 2;
+       return new DviYCommand (l.get_int16());
+       break;
+    case DVI_Y3:
+       *count += 3;
+       return new DviYCommand (l.get_int24());
+       break;
+    case DVI_Y4:
+       *count += 4;
+       return new DviYCommand (l.get_int32());
+       break;
+    case DVI_Z0:
+       return new DviZRepCommand ();
+       break;
+    case DVI_Z1:
+       *count += 1;
+       return new DviZCommand (l.get_int8());
+       break;
+    case DVI_Z2:
+       *count += 2;
+       return new DviZCommand (l.get_int16());
+       break;
+    case DVI_Z3:
+       *count += 3;
+       return new DviZCommand (l.get_int24());
+       break;
+    case DVI_Z4:
+       *count += 4;
+       return new DviZCommand (l.get_int32());
+       break;
+    case DVI_FNT1:
+       *count += 1;
+       return new DviFontNumCommand (l.get_uint8());
+       break;
+    case DVI_FNT2:
+       *count += 2;
+       return new DviFontNumCommand (l.get_uint16());
+       break;
+    case DVI_FNT3:
+       *count += 3;
+       return new DviFontNumCommand (l.get_uint24());
+       break;
+    case DVI_FNT4:
+       *count += 4;
+       return new DviFontNumCommand (l.get_uint32());
+       break;
+    case DVI_XXX1:
+       s = l.get_string8();
+       *count += s.length() + 1;
+       return new DviSpecialCommand (s);
+       break;
+    case DVI_XXX2:
+       s = l.get_string16();
+       *count += s.length() + 2;
+       return new DviSpecialCommand (s);
+       break;
+    case DVI_XXX3:
+       s = l.get_string24();
+       *count += s.length() + 3;
+       return new DviSpecialCommand (s);
+       break;
+    case DVI_XXX4:
+       s = l.get_string32();
+       *count += s.length() + 4;
+       return new DviSpecialCommand (s);
+       break;
+    case DVI_FNTDEF1:
+       l.get_uint8 ();
+       skip_font_definition (l, count);
+       break;
+    case DVI_FNTDEF2:
+       l.get_uint16 ();
+       skip_font_definition (l, count);
+       break;
+    case DVI_FNTDEF3: 
+       l.get_uint24 ();
+       skip_font_definition (l, count);
+       break;
+    case DVI_FNTDEF4:
+       l.get_uint32 ();
+       skip_font_definition (l, count);
+       break;
+    case DVI_BOP:      // BOP and EOP are not considered commands
+    case DVI_EOP:
+    case DVI_NOP:       // NOP is ignored
+    case DVI_PRE:       // PRE, POST and POSTPOST are not supposed to happen
+    case DVI_POST:
+    case DVI_POSTPOST:
+       break;
+    default:
+       printf ("%u\n", *opcode);
+       throw string ("Unknown command");
+       break;
+    }
+    return 0;
+}
+
+DviProgram *
+DviParser::parse_program (void)
+{
+    DviProgram *program = new DviProgram ();
+    DviOpcode opcode;
+    
+    do
+    { 
+       DviCommand *cmd;
+       uint dummy;
+       
+       cmd = parse_command (loader, &dummy, &opcode);
+       if (cmd)
+       {
+           program->add_command (cmd);
+           cmd->unref();
+       }
+       
+    } while (opcode != DVI_EOP);
+    
+    return program;
+}
+
+DviProgram *
+DviParser::parse_program (uint n_bytes)
+{
+    DviProgram *program = new DviProgram ();
+    uint count = 0;
+    
+    while (count < n_bytes)
+    {
+       DviOpcode opcode;
+       DviCommand *cmd;
+       
+       cmd = parse_command (loader, &count, &opcode);
+       if (cmd)
+       {
+           cout << opcode << endl;
+           program->add_command (cmd);
+           cmd->unref();
+       }
+    }
+    
+    return program;
+}
+
+DviPageHeader *
+DviParser::parse_page_header (uint *page_pointer)
+{
+    DviOpcode c;
+    
+    DviPageHeader *header = new DviPageHeader();
+    
+    header->address = *page_pointer;
+    
+    c = (DviOpcode)loader.get_uint8();
+    if (c != DVI_BOP)
+       throw string ("Expected BOP not found");
+    for (uint i=0; i<N_PAGE_COUNTERS; ++i)
+       header->count[i] = loader.get_uint32 ();
+    
+    *page_pointer = loader.get_uint32 ();
+    
+    return header;
+}
+
+DviFontdefinition *
+DviParser::parse_fontdefinition (void)
+{
+    DviFontdefinition *fontdef = new DviFontdefinition;
+    DviOpcode c = (DviOpcode)loader.get_uint8 ();
+    
+    switch (c) {
+    case DVI_FNTDEF1:
+       fontdef->fontnum = loader.get_uint8 ();
+       break;
+    case DVI_FNTDEF2:
+       fontdef->fontnum = loader.get_uint16 ();
+       break;
+    case DVI_FNTDEF3:
+       fontdef->fontnum = loader.get_uint24 ();
+       break;
+    case DVI_FNTDEF4:
+       fontdef->fontnum = loader.get_uint32 ();
+       break;
+    default:
+       throw string ("DVI_FNTDEF? expected");
+       break;
+    }
+    fontdef->checksum = loader.get_uint32 ();
+    fontdef->at_size = loader.get_uint32 ();
+    fontdef->design_size = loader.get_uint32 ();
+    
+    uint dirlength = loader.get_uint8 ();
+    uint namelength = loader.get_uint8 ();
+    
+    fontdef->directory = "";
+    fontdef->name = "";
+    
+    for (uint i=0; i<dirlength; ++i)
+       fontdef->directory += loader.get_uint8();
+    for (uint i=0; i<namelength; ++i)
+       fontdef->name += loader.get_uint8();
+    
+    cout << "parsed fd: " << fontdef->name << " " << fontdef->fontnum << endl;
+    
+    return fontdef;
+}
+
+DviFilePreamble *
+DviParser::parse_preamble (void)
+{
+    DviFilePreamble *preamble = new DviFilePreamble;
+    
+    DviOpcode c = (DviOpcode)loader.get_uint8 ();
+    if (c != DVI_PRE)
+    {
+       string asdf ("asdf");
+       throw string ("Corrupt .dvi file - first byte is not DVI_PRE" + asdf);
+    }
+    
+    preamble->type = (DviType)loader.get_uint8 ();
+    if (preamble->type != NORMAL_DVI)
+    {
+       string asdf ("asdf");
+       cout << asdf;
+       throw string ("Unknown .dvi format" + asdf);
+    }
+    
+    preamble->numerator = loader.get_uint32 ();
+    preamble->denominator = loader.get_uint32 ();
+    preamble->magnification = loader.get_uint32 ();
+    preamble->comment = loader.get_string8 ();
+    
+    return preamble;
+}
+
+DviFilePostamble *
+DviParser::parse_postamble (void)
+{
+    DviFilePostamble *postamble = new DviFilePostamble;
+    
+    loader.goto_from_end (-5);
+    
+    int i;
+    do {
+       i = loader.get_uint8 ();
+       loader.goto_from_current (-2);
+    } while (i == 223);
+    
+    postamble->type = (DviType)i;
+    
+    loader.goto_from_current (-3);
+    loader.goto_from_start (loader.get_uint32() + 1);
+    
+    postamble->last_page_address = loader.get_uint32();
+    postamble->numerator = loader.get_uint32();
+    postamble->denominator = loader.get_uint32();
+    postamble->magnification = loader.get_uint32();
+    postamble->max_height = loader.get_uint32();
+    postamble->max_width = loader.get_uint32();
+    postamble->stack_height = loader.get_uint16();
+    
+    loader.get_uint16 (); // skip number of pages (we count them instead)
+    
+    while (true)
+    {
+       DviOpcode c = (DviOpcode)loader.get_uint8 ();
+       
+       if (c == DVI_NOP)
+           continue;
+       else if (DVI_FNTDEF1 <= c  &&  c <= DVI_FNTDEF4)
+       {
+           loader.goto_from_current (-1);
+           DviFontdefinition *fd = parse_fontdefinition ();
+           
+           postamble->fontdefinitions[fd->fontnum] = fd;
+           cout << fd->name << endl;
+           cout << postamble->fontdefinitions[fd->fontnum]->name;
+       }
+       else
+       {
+           loader.goto_from_current (-1);
+           break;
+       }
+    }
+    return postamble;
+}
+
+VfFontPreamble *
+DviParser::parse_vf_font_preamble (void)
+{
+    DviOpcode c;
+    VfFontPreamble *preamble = new VfFontPreamble;
+    
+    c = (DviOpcode)loader.get_uint8 ();
+    if (c != DVI_PRE)
+       throw string ("Not a .vf file");
+    c = (DviOpcode)loader.get_uint8 ();
+    if (c != 202)
+       throw string ("Not a .vf file");
+    
+    preamble->comment = loader.get_string8 ();
+    preamble->checksum = loader.get_uint32 ();
+    preamble->design_size = loader.get_uint32 ();
+    
+    while (true)
+    {
+       DviOpcode c = (DviOpcode)loader.get_uint8 ();
+       
+       if (DVI_FNTDEF1 <= c  &&  c <= DVI_FNTDEF4)
+       {
+           loader.goto_from_current (-1);
+           DviFontdefinition *fd = parse_fontdefinition ();
+           
+           preamble->fontdefinitions.push_back (fd);
+       }
+       else
+       {
+           loader.goto_from_current (-1);
+           break;
+       }
+    }
+    return preamble;
+}
+
+VfChar *
+DviParser::parse_vf_char (void)
+{
+    DviOpcode c;
+    
+    c = (DviOpcode)loader.get_uint8 ();
+    
+    VfChar *ch = new VfChar;
+    
+    if (c == DVI_POST)
+       return 0;
+    else if (c > 242)
+       throw string ("Corrupt .vf file");
+    else 
+    {
+       uint packet_length;
+       if (c == 242)
+       {
+           packet_length = loader.get_uint32 ();
+           ch->character_code = loader.get_uint32 ();
+           ch->tfm_width = loader.get_uint32 ();
+       }
+       else
+       {
+           packet_length = c;
+           ch->character_code = loader.get_uint8 ();
+           ch->tfm_width = loader.get_uint24 ();
+       }
+       ch->program = parse_program (packet_length);
+    }
+    return ch;
+}
diff --git a/dvi/dvilib/dl-dvi-parser.hh b/dvi/dvilib/dl-dvi-parser.hh
new file mode 100755 (executable)
index 0000000..32e065f
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef DL_DVI_PARSER_HH
+#define DL_DVI_PARSER_HH
+
+#include "dl-loader.hh"
+#include "dl-refcounted.hh"
+#include "dl-dvi-program.hh"
+#include "dl-dvi-fontdefinition.hh"
+#include "dl-dvi-file.hh"
+#include "dl-vffont.hh"
+
+namespace DviLib {
+    
+    class DviParser : public RefCounted {
+       AbstractLoader& loader;
+    public:
+       DviParser (AbstractLoader& l) : loader (l)
+       {
+       };
+       
+       DviFontdefinition *     parse_fontdefinition    (void);
+       DviProgram *            parse_program           (void);
+       DviProgram *            parse_program           (uint max);
+       DviPageHeader *         parse_page_header       (uint *prev_page);
+       DviFilePreamble *       parse_preamble          (void);
+       DviFilePostamble *      parse_postamble         (void);
+       VfFontPreamble *        parse_vf_font_preamble  (void);
+       VfChar *                parse_vf_char           (void);
+       
+       ~DviParser (void) 
+       {
+       };
+    };
+}
+
+#endif
diff --git a/dvi/dvilib/dl-dvi-program.cc b/dvi/dvilib/dl-dvi-program.cc
new file mode 100755 (executable)
index 0000000..cb1f07f
--- /dev/null
@@ -0,0 +1,30 @@
+#include "dl-dvi-program.hh"
+#include <algorithm>
+
+using namespace DviLib;
+
+typedef vector<DviCommand *>::iterator It;
+
+void
+DviProgram::execute (DviRuntime& runtime)
+{
+    for (It i = commands.begin(); i != commands.end(); ++i)    
+    {
+       (*i)->execute (runtime);
+    }
+}
+
+void 
+DviProgram::add_command (DviCommand *cmd)
+{
+    cmd->ref();
+    commands.push_back (cmd);
+}
+
+DviProgram::~DviProgram (void)
+{
+    for (It i = commands.begin(); i != commands.end(); ++i)
+    {
+       (*i)->unref ();
+    }
+}
diff --git a/dvi/dvilib/dl-dvi-program.hh b/dvi/dvilib/dl-dvi-program.hh
new file mode 100755 (executable)
index 0000000..afe5fdb
--- /dev/null
@@ -0,0 +1,272 @@
+#ifndef DL_DVI_PROGRAM_HH__
+#define DL_DVI_PROGRAM_HH__
+
+using namespace std;
+
+#include <string>
+#include <vector>
+
+#include <iostream>
+
+#include "dl-refcounted.hh"
+#include "dl-dvi-runtime.hh"
+
+namespace DviLib
+{
+    class DviCommand : public RefCounted
+    {
+    public:
+       virtual void execute (DviRuntime& runtime) = 0;
+       virtual ~DviCommand() {};
+    };
+    
+    class AbstractDviProgram : public RefCounted
+    {
+    public:
+       virtual void execute (DviRuntime &runtime) = 0;
+       virtual ~AbstractDviProgram (void) {};
+    };
+    
+    class DviProgram : public AbstractDviProgram
+    {
+    public:
+       vector <DviCommand *> commands;
+       void add_command (DviCommand *cmd);
+       virtual void execute (DviRuntime& runtime);
+       virtual ~DviProgram (void);
+    };
+    
+    class DviCharCommand : public DviCommand
+    {
+    private:
+       uint c;
+       
+    public:
+       DviCharCommand (uint c_arg)
+       {
+           c = c_arg;
+       }
+       uint get_c (void) const { return c; }
+    };
+    
+    class DviPutCharCommand : public DviCharCommand
+    {
+    public:
+       DviPutCharCommand (uint ch) : DviCharCommand (ch) {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.put_char (get_c());
+       }
+    };
+    
+    class DviSetCharCommand : public DviCharCommand
+    {
+    public:
+       DviSetCharCommand (uint ch) : DviCharCommand (ch) {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.set_char (get_c());
+       }
+    };
+    
+    class DviRuleCommand : public DviCommand
+    {
+    private:
+       int h, w;
+       
+    public:
+       DviRuleCommand (int h_arg, int w_arg) : h(h_arg), w(w_arg) 
+       {
+           std::cout << "rule cmd " << h << " " << w << std::endl;
+       }
+       int get_h (void) const { return h; }
+       int get_w (void) const { return w; }
+    };
+    
+    class DviPutRuleCommand : public DviRuleCommand
+    {
+    public:
+       DviPutRuleCommand (int h, int w) : DviRuleCommand (h, w) {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.put_rule (get_h(), get_w());
+       }
+    };
+    
+    class DviSetRuleCommand : public DviRuleCommand
+    {
+    public:
+       DviSetRuleCommand (int h, int w) : DviRuleCommand (h, w) {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.set_rule (get_h(), get_w());
+       }
+    };
+    
+    class DviPushCommand : public DviCommand
+    {
+    public:
+       DviPushCommand () {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.push ();
+       }
+    };
+    
+    class DviPopCommand : public DviCommand
+    {
+    public:
+       DviPopCommand () {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.pop ();
+       }
+    };
+    
+    class DviMoveCommand : public DviCommand
+    {
+    private:
+       int len;
+       
+    public:
+       DviMoveCommand (int len_arg) : len (len_arg) {};
+       int get_len (void) { return len; }
+    };
+    
+    class DviRightCommand : public DviMoveCommand
+    {
+    public:
+       DviRightCommand (int len) : DviMoveCommand (len) 
+       {
+#if 0
+           cout << "right command " << get_len() << endl;
+#endif
+       };
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.right (get_len());
+       }
+    };
+    
+    class DviWCommand : public DviMoveCommand
+    {
+    public:
+       DviWCommand (int len) : DviMoveCommand (len) {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.w (get_len());
+       }
+    };
+    
+    class DviXCommand : public DviMoveCommand
+    {
+    public:
+       DviXCommand (int len) : DviMoveCommand (len) {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.x (get_len());
+       }
+    };
+    
+    class DviDownCommand : public DviMoveCommand
+    {
+    public:
+       DviDownCommand (int len) : DviMoveCommand (len) 
+       {
+#if 0
+           cout << "down command " << get_len() << endl;
+#endif
+       };
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.down (get_len());
+       }
+    };
+    
+    class DviYCommand : public DviMoveCommand
+    {
+    public:
+       DviYCommand (int len) : DviMoveCommand (len) {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.y (get_len());
+       }
+    };
+    
+    class DviZCommand : public DviMoveCommand
+    {
+    public:
+       DviZCommand (int len) : DviMoveCommand (len) {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.z (get_len());
+       }
+    };
+    
+    class DviFontNumCommand : public DviCommand
+    {
+    private:
+       int num;
+       
+    public:
+       DviFontNumCommand (int num_arg) : num (num_arg) {}
+       virtual void execute (DviRuntime& runtime)
+       {
+           runtime.font_num (num);
+       }
+    };
+    
+    class DviSpecialCommand : public DviCommand
+    {
+       string spc;
+    public:
+       DviSpecialCommand (string s) : spc (s) {};
+       virtual ~DviSpecialCommand () {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.special (spc);
+       }
+    };
+    
+    class DviWRepCommand : public DviCommand
+    {
+    public:
+       DviWRepCommand () {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.w_rep ();
+       }
+    };
+    
+    class DviXRepCommand : public DviCommand
+    {
+    public:
+       DviXRepCommand () {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.x_rep ();
+       }
+    };
+    
+    class DviYRepCommand : public DviCommand
+    {
+    public:
+       DviYRepCommand () {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.y_rep ();
+       }
+    };
+    
+    class DviZRepCommand : public DviCommand
+    {
+    public:
+       DviZRepCommand () {};
+       virtual void execute (DviRuntime& runtime) 
+       {
+           runtime.z_rep ();
+       }
+    };
+    
+}
+#endif // DL_DVI_PROGRAM_HH__
diff --git a/dvi/dvilib/dl-dvi-runtime.cc b/dvi/dvilib/dl-dvi-runtime.cc
new file mode 100755 (executable)
index 0000000..52b2620
--- /dev/null
@@ -0,0 +1,2 @@
+#include "dl-dvi-runtime.hh"
+
diff --git a/dvi/dvilib/dl-dvi-runtime.hh b/dvi/dvilib/dl-dvi-runtime.hh
new file mode 100755 (executable)
index 0000000..abb8c71
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef DL_DVI_STACK_HH
+#define DL_DVI_STACK_HH
+
+#include "dl-refcounted.hh"
+#include "dl-dvi-fontdefinition.hh"
+#include <string>
+#include <map>
+
+namespace DviLib {
+    class DviRuntime : public RefCounted
+    {
+    public:
+       virtual void set_char (int ch) = 0;             // typeset ch, move w
+       virtual void put_char (int ch) = 0;             // typeset ch, don't move
+       virtual void set_rule (int height, 
+                              int width) = 0;          // rule, move (height, width)
+       virtual void put_rule (int height, 
+                              int width) = 0;          // rule, don't move
+       virtual void push (void) = 0;                   // push current context
+       virtual void pop (void) = 0;                    // pop ccontext
+       virtual void right (int len) = 0;               // move right len
+       virtual void w (int len) = 0;                   // move right len, set w = len
+       virtual void w_rep () = 0;                      // move right w
+       virtual void x (int len) = 0;                   // move right len, set x = len
+       virtual void x_rep () = 0;                      // move right x
+       virtual void down (int len) = 0;                // move down len
+       virtual void y (int len) = 0;                   // move down len, set y = len
+       virtual void y_rep () = 0;                      // move down y
+       virtual void z (int len) = 0;                   // move down len, set z = len
+       virtual void z_rep () = 0;                      // move down z  
+       virtual void push_fontmap (std::map<int, DviFontdefinition *> fontmap) = 0;
+       virtual void font_num (int num) = 0;            // f = num
+       virtual void special (std::string spc) = 0;     // do something special
+       
+       virtual void paint_bitmap (const unsigned char *data, 
+                                  uint width, 
+                                  uint height,
+                                  int hoffset,
+                                  int voffseth) = 0;
+       
+       virtual ~DviRuntime () {};
+    };
+}
+
+#endif
diff --git a/dvi/dvilib/dl-font.hh b/dvi/dvilib/dl-font.hh
new file mode 100755 (executable)
index 0000000..855ab73
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef DL_FONT_HH__
+#define DL_FONT_HH__
+
+#include "dl-loader.hh"
+#include "dl-refcounted.hh"
+#include "dl-dvi-runtime.hh"
+
+#include <vector>
+#include <map>
+
+namespace DviLib {
+
+    class AbstractCharacter : public RefCounted {
+    public:
+       virtual void paint (DviRuntime &runtime) = 0;
+       virtual int get_tfm_width () = 0;
+    };
+
+    class AbstractFont : public RefCounted {
+    public:
+       virtual int get_at_size () = 0;
+       virtual int get_design_size () = 0;
+       virtual AbstractCharacter *get_char (int ccode) = 0;
+    };
+}
+
+#endif /* DL_PKFONT_HH__ */
diff --git a/dvi/dvilib/dl-loader.cc b/dvi/dvilib/dl-loader.cc
new file mode 100755 (executable)
index 0000000..ce29a43
--- /dev/null
@@ -0,0 +1,196 @@
+#include "dl-loader.hh"
+#include <errno.h>
+#include <iostream>
+
+using namespace DviLib;
+
+/* Abstract loader */
+/* =============== */
+
+/* unsigned integers */
+int 
+AbstractLoader::get_uint16 ()
+{
+    return (get_uint8() << 8) | get_uint8();
+}
+
+int 
+AbstractLoader::get_uint24 ()
+{
+    return (get_uint16() << 8) | get_uint8();
+}
+int 
+AbstractLoader::get_uint32 ()
+{
+    return (get_uint16() << 16) | get_uint16();
+}
+
+/* signed integers */
+int 
+AbstractLoader::get_int16 ()
+{
+    return (get_int8() << 8) | get_uint8();
+}
+
+int 
+AbstractLoader::get_int24 ()
+{
+    return (get_int16() << 8) | get_uint8();
+}
+
+int 
+AbstractLoader::get_int32 ()
+{
+    return (get_int16() << 16) | get_uint16();
+}
+
+/* (Pascal) strings */
+string 
+AbstractLoader::get_string8 ()
+{
+    return get_n (get_uint8());
+}
+
+string 
+AbstractLoader::get_string16 ()
+{
+    return get_n (get_uint16());
+}
+
+string
+AbstractLoader::get_string24 ()
+{
+    return get_n (get_uint24());
+}
+
+string 
+AbstractLoader::get_string32 ()
+{
+    return get_n (get_uint32());
+}
+
+void 
+AbstractLoader::skip_string8 ()
+{
+    get_string8();
+}
+
+void 
+AbstractLoader::skip_string16 ()
+{
+    get_string16();
+}
+
+void 
+AbstractLoader::skip_string24 ()
+{
+    get_string24();
+}
+
+void 
+AbstractLoader::skip_string32 ()
+{
+    get_string32();
+}
+
+
+/* "n" */
+void 
+AbstractLoader::skip_n (int n)
+{
+    get_n(n);
+}
+
+string 
+AbstractLoader::get_n (int n)
+{
+    string r;
+    
+    while (n--)
+       r += get_uint8 ();
+    
+    return r;
+}
+
+void
+AbstractLoader::get_n (int n, unsigned char *v)
+{
+    while (n--)
+       *v++ = (unsigned char)get_uint8 ();
+}
+
+/* File loader */
+
+/* FIXME
+ * 
+ * do not use C style files (?)
+ * what exceptions should we throw?
+ */
+
+FileLoader::FileLoader (const string &name)
+{
+    filename = name;
+    f = fopen (filename.c_str(), "r");
+    if (!f)
+    {
+       string s (strerror (errno));
+       throw string ("Could not open " + filename + ": " + s);
+    }
+}
+
+FileLoader::~FileLoader ()
+{
+    std::cout << "hej" << std::endl;
+    if (fclose (f) == EOF)
+       throw string ("Error closing " + filename);
+}
+
+int
+FileLoader::get_int8 ()
+{
+    int c; 
+    
+    if ((c = fgetc (f)) == EOF)
+       throw string ("Unexpected end of file");
+    else
+       return (signed char)c;
+}
+
+int
+FileLoader::get_uint8 ()
+{
+    return (unsigned char)get_int8();
+}
+
+void
+FileLoader::goto_from_start (int n)
+{
+    if (fseek (f, n, SEEK_SET) < 0)
+    {
+       string error = "fseek failed: ";
+       error += strerror (errno);
+       throw error;
+    }
+}
+
+void
+FileLoader::goto_from_current (int n)
+{
+    if (fseek (f, n, SEEK_CUR) < 0)
+    {
+       string error = "fseek failed: ";
+       error += strerror (errno);
+       throw error;
+    }
+}
+
+void
+FileLoader::goto_from_end (int n)
+{
+    if (fseek (f, n, SEEK_END) < 0)
+    {
+       string error = "fseek failed: ";
+       error += strerror (errno);
+       throw error;
+    }    
+}
diff --git a/dvi/dvilib/dl-loader.hh b/dvi/dvilib/dl-loader.hh
new file mode 100755 (executable)
index 0000000..f0ac956
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DL_LOADER_HH
+#define DL_LOADER_HH
+
+#include <string>
+#include <cstdio>
+#include <vector>
+
+#include "dl-refcounted.hh"
+
+namespace DviLib {
+    
+    class AbstractLoader : public RefCounted {
+    public:
+       virtual int get_uint8 ()                = 0;
+       virtual int get_uint16 ();
+       virtual int get_uint24 ();
+       virtual int get_uint32 ();
+       
+       virtual int get_int8 ()                 = 0;
+       virtual int get_int16 ();
+       virtual int get_int24 ();
+       virtual int get_int32 ();
+       
+       virtual string get_string8 ();
+       virtual string get_string16 ();
+       virtual string get_string24 ();
+       virtual string get_string32 ();
+       
+       virtual void skip_string8 ();
+       virtual void skip_string16 ();
+       virtual void skip_string24 ();
+       virtual void skip_string32 ();
+       
+       virtual void goto_from_start (int i)    = 0;
+       virtual void goto_from_end (int i)      = 0;
+       virtual void goto_from_current (int i)  = 0;
+       
+       virtual void skip_n (int n);
+       virtual string get_n (int n);
+       virtual void get_n (int n, unsigned char *v);
+       
+       virtual ~AbstractLoader() {};
+    };
+    
+    class FileLoader : public AbstractLoader {
+       FILE *f;
+       string filename;
+    public:
+       FileLoader (const string &name);
+       virtual int get_int8 ();
+       virtual int get_uint8 ();
+       virtual void goto_from_start (int i);
+       virtual void goto_from_end (int i);
+       virtual void goto_from_current (int i);
+       
+       virtual ~FileLoader ();
+    };
+}
+#endif // DL_LOADER_HH
diff --git a/dvi/dvilib/dl-pkfont.cc b/dvi/dvilib/dl-pkfont.cc
new file mode 100755 (executable)
index 0000000..2544e35
--- /dev/null
@@ -0,0 +1,379 @@
+#include "dl-pkfont.hh"
+#include <algorithm>
+#include <iostream>
+
+using namespace DviLib;
+
+enum PkOpcode {
+    DL_PK_FIRST_COMMAND = 240,
+    DL_PK_XXX1 = 240,
+    DL_PK_XXX2,
+    DL_PK_XXX3,
+    DL_PK_XXX4,
+    DL_PK_YYY,
+    DL_PK_POST,
+    DL_PK_NOP,
+    DL_PK_PRE
+};
+
+enum Color {
+    BLACK,
+    WHITE
+};
+
+class Bitmap {
+    uint *data;
+    uint width;
+public:
+    Bitmap (uint width_arg, uint height)
+    {
+       width = width_arg;
+       data = new uint [width * height];
+       std::fill (data, data + width * height, 0x00000000);
+    }
+    uchar *steal_pixels (void)
+    {
+       uchar *r = (uchar *)data;
+       data = 0;
+       return r;
+    }
+    ~Bitmap () 
+    { 
+    }
+    void fill_black (uint index, uint len)
+    {
+#if 0
+       cout << "filling: " << len << endl;
+#endif
+       std::fill (data + index,
+                  data + index + len,
+                  0xff000000);
+    }
+    void copy (uint src_index, uint len, uint dest_index)
+    {
+       std::copy (data + src_index, 
+                  data + (src_index + len),
+                  data + dest_index);
+    }
+    uint x (uint index)
+    {
+       return index % width;
+    }
+#if 0
+    uint y (uint index)
+    {
+       return (index * 4) / (width * 4);
+    }
+#endif
+    bool pixel (uint index) { 
+       return *(data + index) == 0xff000000;
+    }
+};
+
+class DviLib::RleContext {
+    uchar *data;
+    bool first;
+    uchar nyb0 (uchar x) { return x >> 4; };
+    uchar nyb1 (uchar x) { return x & 15; };
+    Bitmap& bitmap;
+public:
+    uint index;
+    Color color;
+    RleContext (uchar *data_arg,
+               Color color_arg,
+               Bitmap &bitmap_arg) :
+       data (data_arg),
+       first (true),
+       bitmap (bitmap_arg),
+       
+       index (0),
+       color (color_arg)
+    { }
+    uchar get_nybble (void)
+    {
+       if (first)
+       {
+           first = false;
+           return nyb0 (*data);
+       }
+       else
+       {
+           first = true;
+           return nyb1 (*data++);
+       }
+    }
+    Bitmap& get_bitmap () { return bitmap; }
+};
+
+inline CountType
+PkChar::get_count (RleContext& nr, uint *count)
+{
+    CountType result = RUN_COUNT;
+    uint i;
+    
+    i = nr.get_nybble();
+    if (i == 15)
+    {
+       *count = 1;
+       return REPEAT_COUNT;
+    }
+    else if (i == 14)
+    {
+       result = REPEAT_COUNT;
+       i = nr.get_nybble();
+    }
+    switch (i) {
+    case 15: case 14:
+       throw string ("Duplicated repeat count");
+       break;
+    case 0:
+       for (i = 1; (*count = nr.get_nybble()) == 0; ++i)
+           ;
+       while (i-- > 0)
+           *count = (*count << 4) + nr.get_nybble();
+       *count = *count - 15 + (13 - dyn_f)*16 + dyn_f;
+       break;
+    default:
+       if (i <= dyn_f)
+           *count = i;
+       else
+           *count = (i - dyn_f - 1)*16 + nr.get_nybble() + dyn_f + 1;
+       break;
+    }
+    return result;
+}
+
+void
+PkChar::unpack_rle (RleContext& nr)
+{
+    uint count;
+    
+    while (nr.index < height * width)
+    {
+       CountType count_type = get_count (nr, &count);
+       Bitmap& bm = nr.get_bitmap ();
+       
+       switch (count_type) {
+       case RUN_COUNT:
+           if (nr.color == BLACK)                  
+           {
+               bm.fill_black (nr.index, count);
+               nr.color = WHITE;
+           }
+           else
+               nr.color = BLACK;
+           nr.index += count;
+           break;
+       case REPEAT_COUNT:
+           uint temp = nr.index;
+           
+           nr.index += count * width;
+           unpack_rle (nr);
+           
+           uint x = bm.x(temp);
+           
+           if (bm.pixel (temp - x))
+               bm.fill_black (temp + count * width - x, x);
+           
+           for (uint i = 0; i < count; ++i)
+               bm.copy (temp + count * width - x, width, 
+                        temp - x + i * width);
+           return;
+           break;
+       }
+    }
+}
+
+void
+PkChar::unpack_bitmap (void)
+{
+    uint i, weight;
+    
+    uchar *bitmap 
+       = new uchar [4 * width * height];
+    fill (bitmap, bitmap + 4 * width * height, 0xFF);
+    
+    weight = 128;
+    
+    for (i=0; i < height * width; i+=4)
+    {
+       if ((*data.packed & weight) != 0)
+           bitmap[i] = bitmap[i+1] = 
+               bitmap[i+2] = bitmap[i+3] = 0x00;
+       weight = (weight == 1)?
+           (data.packed++, 128) : weight >> 1;
+    }
+    data.bitmap = bitmap;
+}
+
+void
+PkChar::unpack (void)
+{
+    if (unpacked)
+       return;
+    
+    if (dyn_f == 14)
+       unpack_bitmap();
+    else
+    {
+       Bitmap bitmap (width, height);
+       
+       RleContext nr (data.packed, 
+                      first_is_black? BLACK : WHITE,
+                      bitmap);
+       unpack_rle (nr);
+       unpacked = true;
+       data.bitmap = bitmap.steal_pixels ();
+    }
+}
+
+PkChar::PkChar (AbstractLoader &loader)
+{
+    uint flag_byte = loader.get_uint8 ();
+    
+    dyn_f = flag_byte >> 4;
+    if (dyn_f == 15)
+       throw string ("Corrupt .pk file");
+    
+    first_is_black = (flag_byte & 8)? true : false;
+    
+    uint length = 0; // to quiet gcc
+
+    switch (flag_byte & 7)
+    {
+    case 0: case 1: case 2: case 3:
+       /* short preamble */
+       length = loader.get_uint8 () + ((flag_byte & 3) << 8) - 8;
+       character_code = loader.get_uint8 ();
+       tfm_width = loader.get_uint24 ();
+       dx = loader.get_uint8 () << 16;
+       dy = 0;
+       width = loader.get_uint8 ();
+       height = loader.get_uint8 ();
+       hoffset = loader.get_int8 ();
+       voffset = loader.get_int8 ();
+       break;
+
+    case 4: case 5: case 6:
+       /* extended short preamble */
+       length = loader.get_uint16 () + ((flag_byte & 3) << 16) - 13;
+       cout << length;
+       character_code = loader.get_uint8 ();
+       cout << ',' << character_code;
+       tfm_width = loader.get_uint24 ();
+       dx = loader.get_uint16 () << 16;
+       dy = 0;
+       width = loader.get_uint16 ();
+       height = loader.get_uint16 ();
+       hoffset = loader.get_int16 ();
+       voffset = loader.get_int16 ();
+       break;
+
+    case 7:
+       /* long preamble */
+       length = loader.get_int32 () - 28;
+       character_code = loader.get_int32 ();
+       tfm_width = loader.get_int32 ();
+       dx = loader.get_int32 ();
+       dy = loader.get_int32 ();
+       width = loader.get_int32 ();
+       height = loader.get_int32 ();
+       hoffset = loader.get_int32 ();
+       voffset = loader.get_int32 ();
+       break;
+
+    default:
+       /* should not be reached */
+       break;
+    }
+    unpacked = false;
+    data.packed = new uchar[length];
+    loader.get_n (length, data.packed);
+}
+
+void
+PkChar::paint (DviRuntime &runtime) 
+{
+    const unsigned char *bitmap;
+    bitmap = get_bitmap ();
+    runtime.paint_bitmap (bitmap, 
+                         get_width(), get_height(),
+                         get_hoffset(), get_voffset());
+    
+}
+void
+PkFont::load (void)
+{
+    PkOpcode c;
+    
+    c = (PkOpcode) loader.get_uint8 ();
+    if (c != DL_PK_PRE)
+       throw string ("Not a .pk file (no pre)");
+    
+    id = loader.get_uint8 ();
+    if (id != 89)
+       throw string ("Not a .pk file (incorrect id)");
+    
+    comment = loader.get_string8 ();
+    design_size = loader.get_uint32 (); 
+    checksum = loader.get_uint32 ();
+    hppp = loader.get_uint32 ();
+    vppp = loader.get_uint32 ();
+    
+    do
+    {
+       c = (PkOpcode)loader.get_uint8 ();
+       switch (c)
+       {
+       case DL_PK_XXX1:
+           loader.skip_string8 ();
+           break;
+       case DL_PK_XXX2:
+           loader.skip_string16 ();
+           break;
+       case DL_PK_XXX3:
+           loader.skip_string24 ();
+           break;
+       case DL_PK_XXX4:
+           loader.skip_string32 ();
+           break;
+       case DL_PK_YYY:
+           loader.get_uint32 ();
+           break;
+       case DL_PK_POST:
+           break;
+       case DL_PK_NOP:
+           break;
+       case DL_PK_PRE:
+           throw string ("Unexpected PRE");
+           break;
+       default:
+           loader.goto_from_current (-1);
+           if (c <= DL_PK_FIRST_COMMAND)
+           {
+               PkChar *pkc = new PkChar (loader);
+               chars[pkc->get_character_code()] = pkc;
+#if 0
+               cout << '[' << pkc->get_character_code() << ']';
+#endif
+           }
+           else
+               throw string ("Undefined PK command");
+           break;
+       }
+    } while (c != DL_PK_POST);
+}
+
+PkFont::PkFont (AbstractLoader& l, int at_size_arg) :
+    loader (l),
+    at_size (at_size_arg)
+{
+    load ();
+}
+
+PkFont::PkFont (AbstractLoader& l) :
+    loader (l)
+{
+    load ();
+    at_size = design_size;
+}
diff --git a/dvi/dvilib/dl-pkfont.hh b/dvi/dvilib/dl-pkfont.hh
new file mode 100755 (executable)
index 0000000..66cd69b
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef DL_PKFONT_HH__
+#define DL_PKFONT_HH__
+
+#include "dl-loader.hh"
+#include "dl-refcounted.hh"
+#include "dl-font.hh"
+
+#include <vector>
+#include <map>
+
+namespace DviLib {
+    
+    class RleContext;
+    
+    enum CountType {
+       RUN_COUNT,
+       REPEAT_COUNT
+    };
+    
+    class PkChar : public AbstractCharacter {
+       uint dyn_f;
+       bool first_is_black;    // if first run count is black or white
+       int character_code;
+       int tfm_width;          // in what units? FIXME
+       uint dx;                // escapement - what is this? FIXME
+       uint dy;
+       uint width;             // in pixels
+       uint height;            // in pixels
+       int hoffset;
+       int voffset;
+       
+       bool unpacked;
+       union {
+           unsigned char *bitmap;  // 32 bit/pixel ARGB format
+           unsigned char *packed;
+       } data;
+       
+       CountType get_count (RleContext& nr, uint *count);
+       void unpack_rle (RleContext& nr);
+       void unpack_bitmap (void);
+       void unpack (void);
+    public:
+       PkChar (AbstractLoader &l);
+       virtual void paint (DviRuntime &runtime);
+       const unsigned char *get_bitmap (void) 
+       { 
+           if (!unpacked)
+               unpack ();
+           return data.bitmap;
+       }
+       uint get_width (void)
+       {
+           return width;
+       }
+       uint get_height (void)
+       {
+           return height;
+       }
+       virtual int get_tfm_width (void)
+       {
+           return tfm_width;
+       }
+       int get_hoffset (void) 
+       {
+           return hoffset;
+       }
+       int get_voffset (void)
+       {
+           return voffset;
+       }
+       int get_character_code (void) { return character_code; }
+    };
+    
+    class PkFont : public AbstractFont {
+       AbstractLoader& loader;
+       uint id;
+       string comment;
+       uint design_size;
+       uint checksum;
+       uint hppp;              /* horizontal pixels per point */
+       uint vppp;              /* vertical  pixels per point */
+       map <uint, PkChar *> chars;
+       int at_size;
+       void load (void);
+    public:
+       PkFont (AbstractLoader& l);
+       PkFont (AbstractLoader& l, int at_size);
+       virtual PkChar *get_char (int ccode)
+       {
+           return chars[ccode]; 
+       }
+       virtual int get_design_size (void)
+       {
+           return design_size; 
+       }
+       virtual int get_at_size (void)
+       {
+           return at_size;
+       }
+       virtual ~PkFont () {}
+    };
+}
+
+#endif /* DL_PKFONT_HH__ */
diff --git a/dvi/dvilib/dl-refcounted.hh b/dvi/dvilib/dl-refcounted.hh
new file mode 100755 (executable)
index 0000000..068ac2e
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef DL_REFCOUNTED_HH
+#define DL_REFCOUNTED_HH
+
+using namespace std;
+
+typedef unsigned int uint;
+typedef unsigned char uchar;
+
+namespace DviLib {
+    
+    class RefCounted
+    {
+       int refcount;
+
+    public:
+
+       RefCounted (void)
+       {
+           refcount = 1;
+       }
+
+       RefCounted *ref (void)
+       {
+           refcount++;
+           return this;
+       }
+
+       void unref (void)
+       {
+           refcount--;
+           if (!refcount)
+               delete this;
+       }
+    };
+}
+
+#endif // DL_REFCOUNTED_HH
diff --git a/dvi/dvilib/dl-vffont.cc b/dvi/dvilib/dl-vffont.cc
new file mode 100755 (executable)
index 0000000..91109d8
--- /dev/null
@@ -0,0 +1,16 @@
+#include "dl-vffont.hh"
+#include "dl-dvi-parser.hh"
+
+using namespace DviLib;
+
+VfFont::VfFont (AbstractLoader &l, int at_size_arg) :
+    at_size (at_size_arg)
+{
+    DviParser parser (l);
+    preamble = parser.parse_vf_font_preamble ();
+
+    VfChar *ch;
+    while ((ch = parser.parse_vf_char ()) != NULL)
+       chars[ch->character_code] = ch;
+}
+
diff --git a/dvi/dvilib/dl-vffont.hh b/dvi/dvilib/dl-vffont.hh
new file mode 100755 (executable)
index 0000000..185e4a9
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DL_VFFONT_HH__
+#define DL_VFFONT_HH__
+
+#include "dl-dvi-file.hh"
+#include "dl-dvi-fontdefinition.hh"
+#include "dl-font.hh"
+
+namespace DviLib {
+    
+    class VfChar : public AbstractCharacter {
+    public:
+       int tfm_width;
+       DviProgram *program;
+       int character_code;
+
+       virtual void paint (DviRuntime& runtime)
+       {
+           runtime.push();
+           program->execute (runtime); // FIXME push, pop, etc.
+           runtime.pop();
+       }
+       virtual int get_tfm_width () { return tfm_width; }
+    };
+    
+    class VfFontPreamble : public RefCounted {
+    public:
+       string comment;
+       uint checksum;
+       uint design_size;
+       vector <DviFontdefinition *> fontdefinitions;
+    };
+    
+    class VfFont : public AbstractFont {
+       VfFontPreamble *preamble;
+       map <int, VfChar *> chars;
+       int at_size;
+    public:
+       VfFont (AbstractLoader& l, int at_size);
+       virtual VfChar *get_char (int ccode) 
+       { 
+           return chars[ccode]; 
+       };
+       int get_design_size () 
+       { 
+           return preamble->design_size; 
+       }
+       virtual int get_at_size ()
+       {
+           /* FIXME (what is the correct thing to do here?) */
+           return at_size;
+       }
+       virtual ~VfFont () {}
+    };
+}
+#endif /* DL_VFFONT_HH__ */
diff --git a/dvi/fest.tex b/dvi/fest.tex
new file mode 100644 (file)
index 0000000..1ae5083
--- /dev/null
@@ -0,0 +1,23 @@
+\documentclass[a4paper, danish]{article}
+
+\usepackage{times}
+\usepackage[T1]{fontenc}
+\usepackage{babel}
+
+\begin{document}
+
+\section{Title}
+
+{\large Hej verden\par}
+
+{\large Bl\aa b\ae rgr\o d\par}
+
+\subsection {Subtitle}
+
+Math: $\sum_{i=0}^\infty \frac{1}{i^2} = \frac{\pi^2}{6}$
+
+{\large\bf Big, bold\par}
+
+{\Huge\bf Huge, bold\par}
+
+\end{document}
diff --git a/dvi/font.cc b/dvi/font.cc
new file mode 100755 (executable)
index 0000000..512370e
--- /dev/null
@@ -0,0 +1,169 @@
+#include "font.hh"
+
+#include "painter.hh"
+#include "dl-pkfont.hh"
+#include "dl-vffont.hh"
+
+using DviLib::FileLoader;
+using DviLib::AbstractFont;
+using DviLib::VfChar;
+using DviLib::PkChar;
+using DviLib::PkFont;
+using DviLib::VfFont;
+
+static char *
+do_run_program (const char *program,
+               GList *args,
+               GError **err)
+{
+    char **argv = g_new (char *, g_list_length (args) + 2);
+    GList *l;
+    int i;
+    char *result;
+
+    i = 0;
+    argv[i++] = g_strdup (program);
+    for (l = args; l; l = l->next)
+       argv[i++] = g_strdup ((char *)l->data);
+    argv[i++] = NULL;
+    
+    g_list_free (args);
+
+
+    /* run it */
+    g_spawn_sync         (NULL, /* working directory */
+                         argv, /* arguments */
+                         NULL, /* environment */
+                         G_SPAWN_SEARCH_PATH, /* flags */
+                         NULL, /* child setup */
+                         NULL, /* user data for child setup */
+                         &result, /* stdout */
+                         NULL, /* stderr */
+                         NULL, /* exit status */
+                         err /* GError */);
+
+    g_strfreev (argv);
+    
+    return result;
+}
+
+
+static char *
+run_program (const char *program,
+            GError **err,
+            const char *arg1,
+            ...)
+{
+    va_list arg_list;
+    GList *arguments = NULL;
+    char *s;
+
+    va_start (arg_list, arg1);
+
+    arguments = g_list_append (arguments, (gpointer)arg1);
+    
+    s = va_arg (arg_list, gchar*);
+    while (s)
+    {
+       arguments = g_list_append (arguments, s);
+       s = va_arg (arg_list, gchar*);
+    }
+
+    va_end (arg_list);
+
+    return do_run_program (program, arguments, err);
+}
+
+static char *
+run_kpsewhich (int dpi,
+              string format,
+              string name)
+{
+    char *dpistr = g_strdup_printf ("--dpi=%d", dpi);
+    char *formatstr = g_strdup_printf ("--format=%s", format.c_str());
+    char *namestr = g_strdup (name.c_str());
+    GError *err = NULL;
+    char *result;
+
+    result = run_program ("kpsewhich", &err, dpistr, formatstr, namestr, NULL);
+
+    if (!result)
+    {
+       cout << err->message << endl;
+    }
+    else
+    {
+       g_strstrip (result);
+
+       if (*result == '\0')
+       {
+           /* Nothing useful returned */
+           g_free (result);
+           result = NULL;
+       }
+    }
+
+    cout << "kpsewhich " << dpistr << " " << formatstr << " " << namestr << " " << endl;
+    
+    g_free (dpistr);
+    g_free (formatstr);
+    g_free (namestr);
+
+    return result;
+}
+
+static void
+run_mktexpk (int dpi, string name)
+{
+    char *dpistr = g_strdup_printf ("--bdpi=%d", dpi);
+    char *bdpistr = g_strdup_printf ("--dpi=%d", dpi);
+    char *namestr = g_strdup (name.c_str());
+    char *result;
+
+    result = run_program ("mktexpk", NULL, bdpistr, dpistr, namestr, NULL);
+    if (result)
+       g_free (result);
+
+    g_free (dpistr);
+    g_free (bdpistr);
+    g_free (namestr);
+}
+
+AbstractFont *
+FontFactory::create_font (std::string name, 
+                         int dpi,
+                         int at_size)
+{
+    char *filename;
+
+    /* Find VF */
+    filename = run_kpsewhich (dpi, "vf", name);
+
+    if (filename)
+       return new VfFont (*new FileLoader (filename), at_size);
+
+    /* Try PK */
+    
+    filename = run_kpsewhich (dpi, "pk", name);
+
+    if (filename)
+       return new PkFont (*new FileLoader (filename), at_size);
+
+    /* Generate PK */
+    
+    run_mktexpk (dpi, name);
+
+    cout << "birnan" << endl;
+    
+    /* Try PK again */
+    filename = run_kpsewhich (dpi, "pk", name);
+
+    if (filename)
+       return new PkFont (*new FileLoader (filename), at_size);
+
+    cout << "no luck" << endl;
+    
+    throw (string ("bad font"));
+    
+    return NULL;
+}
diff --git a/dvi/font.hh b/dvi/font.hh
new file mode 100755 (executable)
index 0000000..5f34c07
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef FONT_HH
+#define FONT_HH
+
+#include "dl-dvi-program.hh"
+#include "dl-font.hh"
+
+// Font factories
+
+class AbstractFontFactory : public DviLib::RefCounted {
+public:
+    virtual DviLib::AbstractFont *create_font (std::string name, 
+                                              int dpi, 
+                                              int at_size) = 0;
+};
+
+class FontFactory : public AbstractFontFactory {
+public:
+    virtual DviLib::AbstractFont *create_font (std::string name, 
+                                              int dpi,
+                                              int at_size);
+};
+
+#endif
diff --git a/dvi/main.cc b/dvi/main.cc
new file mode 100755 (executable)
index 0000000..1037256
--- /dev/null
@@ -0,0 +1,31 @@
+#include <gtk/gtk.h>
+
+#include "model.hh"
+#include "view.hh"
+#include "painter.hh"
+
+int
+main (int argc, char *argv[])
+{
+    GtkWidget *window, *scrwin;
+
+    gtk_init (&argc, &argv);
+
+    Model *model = new Model ("fest.dvi");
+    View *view = new View (model);
+    
+    
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+    scrwin = gtk_scrolled_window_new (NULL, NULL);
+
+    gtk_container_add (GTK_CONTAINER (window), scrwin);
+
+    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrwin), view->get_widget());
+    
+    gtk_widget_show_all (GTK_WIDGET (window));
+    
+    gtk_main ();
+    
+    return 0;
+}
diff --git a/dvi/model.cc b/dvi/model.cc
new file mode 100755 (executable)
index 0000000..154352e
--- /dev/null
@@ -0,0 +1,23 @@
+#include "model.hh"
+
+Model::Model (string file_name) 
+{
+    try {
+       FileLoader *fl = new FileLoader (file_name);
+       dvi_file = new DviFile (*fl);
+       state = HAS_FILE;
+    }
+    catch (string e) {
+       dvi_file = 0;
+       state = ERROR;
+       err_msg = e;
+       cout << "error" << endl;
+    }
+}
+
+Model::Model (void) 
+{
+    state = NO_FILE;
+    dvi_file = 0;
+}
+    
diff --git a/dvi/model.hh b/dvi/model.hh
new file mode 100755 (executable)
index 0000000..749c640
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef MODEL_HH
+#define MODEL_HH
+
+#include "dl-refcounted.hh"
+#include "dl-dvi-file.hh"
+#include "observer.hh"
+#include <list>
+
+enum ModelState {
+    HAS_FILE,
+    NO_FILE,
+    ERROR
+};
+
+using DviLib::FileLoader;
+using DviLib::DviFile;
+using DviLib::RefCounted;
+using std::string;
+
+class Model : public RefCounted {
+    ModelState state;
+    DviFile *dvi_file;
+    string file_name;
+    string err_msg;
+    vector <Observer *> observers;
+    
+public:
+    Model (string file_name);
+    Model (void);
+    void add_observer (Observer& o)
+    {
+       observers.push_back (&o);
+    }
+    void notify (void)
+    {
+       typedef vector <Observer *>::const_iterator It;
+       for (It i = observers.begin(); i != observers.end(); ++i)
+           (*i)->notify ();
+    }
+    ModelState get_state (void) { return state; }
+    string get_error (void) {
+       if (state == ERROR)
+           return err_msg;
+       else
+           return "";
+    };
+    DviFile *get_dvi_file (void) {
+       if (state == HAS_FILE)
+           return dvi_file;
+       else
+           return 0;
+    };
+    string get_file_name (void) {
+       if (state == HAS_FILE)
+           return file_name;
+       else
+           return "";
+    };
+};
+
+#endif
diff --git a/dvi/observer.hh b/dvi/observer.hh
new file mode 100755 (executable)
index 0000000..488fc52
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef OBSERVER_HH
+#define OBSERVER_HH
+
+#include <dl-refcounted.hh>
+
+using DviLib::RefCounted;
+
+class Observer : public RefCounted {
+public:
+    virtual void notify (void) const = 0;
+    virtual ~Observer() {}
+};
+
+
+#endif /* OBSERVER_HH */
diff --git a/dvi/painter.cc b/dvi/painter.cc
new file mode 100755 (executable)
index 0000000..a1bb758
--- /dev/null
@@ -0,0 +1,334 @@
+#include "painter.hh"
+#include "dl-dvi-fontdefinition.hh"
+
+using DviLib::DviFontdefinition;
+using DviLib::AbstractCharacter;
+
+// paint a bitmap
+void
+DviPainter::paint_bitmap (const unsigned char *data,
+                         uint width, uint height, 
+                         int hoffset, int voffset)
+{
+    GdkPixbuf *pixbuf = 
+       gdk_pixbuf_new_from_data (data,
+                                 GDK_COLORSPACE_RGB, 
+                                 TRUE,        // has_alpha,
+                                 8,
+                                 width,
+                                 height,
+                                 width * 4,  // rowstride
+                                 NULL,     // destroy_fn
+                                 NULL);    // destroy_fn_data
+    
+    uint x = dvi_to_pixels (current_frame->h);
+    uint y = dvi_to_pixels (current_frame->v);
+    
+    gdk_pixbuf_render_to_drawable (pixbuf,
+                                  pixmap,
+                                  gc,
+                                  0, 0,
+                                  x-hoffset,
+                                  y-voffset,
+                                  //y+(height - voffset),
+                                  width,
+                                  height,
+                                  GDK_RGB_DITHER_NONE,
+                                  0, 0);
+}
+
+// typeset ch, move w
+void 
+DviPainter::set_char (int ch)
+{
+    g_assert (current_font);
+    
+    AbstractCharacter *character = current_font->get_char (ch);
+    character->paint (* this);
+    
+    int tfm_width = character->get_tfm_width ();
+    int at_size = current_font->get_at_size ();
+    int dvi_width = tfm_to_dvi (tfm_width, at_size);
+    
+    current_frame->h += dvi_width;
+}
+
+// typeset ch, don't move
+void 
+DviPainter::put_char (int ch)
+{
+    AbstractCharacter *character = current_font->get_char (ch);
+    character->paint (* this);
+}
+
+void 
+// rule, move (height, width)
+DviPainter::set_rule (int height, 
+                     int width)
+{
+    int width_p = dvi_to_pixels_no_offset (width);
+    int height_p = dvi_to_pixels_no_offset (height);
+    int x = dvi_to_pixels (current_frame->h);
+    int y = dvi_to_pixels (current_frame->v);
+    
+    cout << "BIRNAN\n" << endl;
+    
+    gdk_draw_rectangle (pixmap,        gc, TRUE, 
+                       x, y, 
+                       width_p + 1, height_p + 1);
+    
+    current_frame->h += width;
+}
+
+// rule, don't move
+void 
+DviPainter::put_rule (int height, 
+                     int width)
+{
+    cout << "w h " << width << " " << height << " " << endl;
+    
+    int width_p = dvi_to_pixels_no_offset (width);
+    int height_p = dvi_to_pixels_no_offset (height);
+    int x = dvi_to_pixels (current_frame->h);
+    int y = dvi_to_pixels (current_frame->v);
+    
+    cout << "EMFLE\n" << endl;
+    
+    cout << "x y h w " << x << " " << y << " " << height_p << " " 
+        << width_p << endl;
+    
+    gdk_draw_rectangle (pixmap,        gc, TRUE, 
+                       x, y, 
+                       width_p + 1, height_p + 1);
+}
+
+// push current context
+DviFrame *
+DviFrame::copy (void)
+{
+    DviFrame *frame = new DviFrame ();
+
+    frame->h = this->h;
+    frame->v = this->v;
+    frame->w = this->w;
+    frame->x = this->x;
+    frame->y = this->y;
+    frame->z = this->z;
+
+    return frame;
+}
+
+void 
+DviPainter::push (void)
+{
+    DviFrame *new_frame = current_frame->copy();
+    new_frame->next = current_frame;
+    current_frame = new_frame;
+}
+
+// pop ccontext
+void 
+DviPainter::pop (void)
+{
+    DviFrame *old_frame = current_frame;
+
+    current_frame = current_frame->next;
+
+    old_frame->unref();
+}
+
+// move right len
+void 
+DviPainter::right (int len)
+{
+    current_frame->h += len;
+}
+
+// move right len, set w = len
+void 
+DviPainter::w (int len)
+{
+    right (len);
+    current_frame->w = len;
+}
+
+// move right w
+void 
+DviPainter::w_rep ()
+{
+    right (current_frame->w);
+}
+
+// move right len, set x = len
+void 
+DviPainter::x (int len)
+{
+    right (len);
+    current_frame->x = len;
+}
+
+// move right x
+void 
+DviPainter::x_rep ()
+{
+    right (current_frame->x);
+}
+
+// move down len
+void 
+DviPainter::down (int len)
+{
+    current_frame->v += len;
+}
+
+// move down len, set y = len
+void 
+DviPainter::y (int len)
+{
+    down (len);
+    current_frame->y = len;
+}
+
+// move down y
+void 
+DviPainter::y_rep ()
+{
+    down (current_frame->y);
+}
+
+// move down len, set z = len
+void 
+DviPainter::z (int len)
+{
+    down (len);
+    current_frame->z = len;
+}
+
+// move down z
+void 
+DviPainter::z_rep ()
+{
+    down (current_frame->z);
+}
+
+// f = font_num 
+void 
+DviPainter::font_num (int font_num)
+{
+    cout << "get fno " << font_num << endl;
+    DviFontdefinition *fd = dvi_file->get_fontdefinition (font_num);
+    
+    g_assert (fd);
+    if (fd)
+    {
+       // gtkdvi:
+       int dpi = (int)floor( 0.5 + 1.0 * base_dpi * 
+                             dvi_file->get_magnification() * fd->at_size /
+                             ( 1000.0 * fd->design_size));
+       cout << "fno: " << fd->fontnum << endl;
+       cout << fd->name << endl;
+       current_font = 
+           font_factory->create_font (fd->name, dpi, fd->at_size);
+    }
+}
+
+// do something special
+void 
+DviPainter::special (string spc)
+{
+    cout << "warning: special " << spc << " " << "not handled" << endl;
+}
+
+int 
+DviPainter::tfm_to_dvi (uint tfm, int at_size)
+{
+    // this is from gtkdvi:
+    int alpha, z, beta, b0, b1, b2, b3, r;
+    
+    alpha = 16;
+    z = at_size;
+    while (z >= (1<<23))
+    {
+       z >>= 1;
+       alpha <<= 1;
+    }
+    beta = 256/alpha;
+    alpha *= z;
+    
+#if 0
+    b0 = tfm & (0xFF << 24);
+    b1 = tfm & (0xFF << 16);
+    b2 = tfm & (0xFF << 8);
+    b3 = tfm & (0xFF << 0);
+#endif
+    
+    b0 = tfm >> 24;  
+    b1 = (tfm >> 16) & 255;
+    b2 = (tfm >> 8) & 255;
+    b3 = tfm & 255;
+    
+#if 0
+    r = (((((b3 * z) / 256) + (b2 * z)) / 256) + (b1 * z))/beta;
+#endif
+    
+    b1 *= z;
+    b2 *= z;
+    b3 *= z;
+    
+    r = (((b3 / 256 + b2) / 256) + b1) / beta;
+    
+    if (b0 > 0)
+    {
+       if ((b0 > 0) != (tfm > 0))
+           cout << "b0: " << b0 << "tfm: " << tfm << endl;
+       r -= alpha;
+    }
+    
+    return r;
+}
+
+DviPainter::DviPainter (GdkPixmap              *pixmap_arg,
+                        GdkGC                 *gc_arg,
+                        DviLib::DviFile       *dvi_file_arg,
+                        uint                   base_dpi_arg,
+                        AbstractFontFactory   *font_factory_arg)
+{
+    pixmap             = (GdkPixmap *)g_object_ref (pixmap_arg);
+    gc                 = (GdkGC *)g_object_ref (gc_arg);
+    dvi_file           = dvi_file_arg;
+    base_dpi           = base_dpi_arg;
+    font_factory       = font_factory_arg;
+
+    dvi_file->ref();
+    font_factory->ref();
+    
+    current_font = 0;
+    
+    current_frame = new DviFrame;
+    current_frame->h = 0;
+    current_frame->v = 0;
+    current_frame->w = 0;
+    current_frame->x = 0;
+    current_frame->y = 0;
+    current_frame->z = 0;
+    
+    // from gtkdvi:
+    scale =  dvi_file->get_numerator() / 254000.0;
+    scale *= 1.0 * base_dpi / dvi_file->get_denominator ();
+    scale *= dvi_file->get_magnification () / 1000.0;
+}
+
+DviPainter::~DviPainter ()
+{
+    g_object_unref (pixmap);
+    g_object_unref (gc);
+    dvi_file->unref();
+    font_factory->unref();
+    while (current_frame)
+       pop();
+}
+
+void
+DviPainter::push_fontmap (std::map<int, DviFontdefinition *> fontmap)
+{
+}
diff --git a/dvi/painter.hh b/dvi/painter.hh
new file mode 100755 (executable)
index 0000000..cbb968b
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef PAINTER_HH
+#define PAINTER_HH
+
+#include "dl-dvi-program.hh"
+#include "dl-dvi-file.hh"
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "font.hh"
+#include <gdk/gdk.h>
+#include <cmath>
+#include <list>
+
+class AbstractDviPainter : public DviLib::DviRuntime
+{
+public:
+    virtual void paint_bitmap (const unsigned char *data, 
+                              uint width, 
+                              uint height,
+                              int hoffset,
+                              int voffseth) = 0;
+    virtual ~AbstractDviPainter () {}
+};
+
+class DviFrame : public DviLib::RefCounted
+{
+public:
+    int h, v, w, x, y, z;              // in dvi units
+    DviFrame *next;
+    DviFrame *copy ();
+};
+
+class DviPainter : public AbstractDviPainter
+{
+public:
+    virtual void set_char (int ch);            // typeset ch, move w
+    virtual void put_char (int ch);            // typeset ch, don't move
+    virtual void set_rule (int height, 
+                          int width);          // rule, move (height, width)
+    virtual void put_rule (int height, 
+                          int width);          // rule, don't move
+    virtual void push (void);                  // push current context
+    virtual void pop (void);                   // pop ccontext
+    virtual void right (int len);              // move right len
+    virtual void w (int len);                  // move right len, set w = len
+    virtual void w_rep ();                     // move right w
+    virtual void x (int len);                  // move right len, set x = len
+    virtual void x_rep ();                     // move right x
+    virtual void down (int len);               // move down len
+    virtual void y (int len);                  // move down len, set y = len
+    virtual void y_rep ();                     // move down y
+    virtual void z (int len);                  // move down len, set z = len
+    virtual void z_rep ();                     // move down z
+    virtual void push_fontmap (std::map<int, DviLib::DviFontdefinition *> fontmap);
+    virtual void font_num (int font_num);      // current_font = fd
+    virtual void special (string spc);         // do something special
+    virtual void paint_bitmap (const unsigned char *data, 
+                              uint width, 
+                              uint height,
+                              int voffset,
+                              int hoffset);
+private:
+    GdkPixmap          *pixmap;
+    GdkGC               *gc;
+    DviLib::DviFile     *dvi_file;
+    uint                base_dpi;
+    AbstractFontFactory *font_factory;
+
+    // runtime
+    DviLib::AbstractFont *current_font;
+    DviFrame *current_frame;           // stack of DVI frames
+
+    double scale;              // convert dvi units to pixels
+    int dvi_to_pixels (int du) 
+    { 
+       // We add base_dpi horizontally and vertically. This
+       // has the effect of adding an inch horizontally and
+       // vertically. This is just how .dvi files work ...
+       return (int)floor (0.5 + scale * du) + base_dpi; 
+    }
+    int dvi_to_pixels_no_offset (int du) 
+    { 
+       return (int)floor (0.5 + scale * du); 
+    }
+    int tfm_to_dvi (uint tfm, int at_size);
+    
+public:
+    DviPainter (GdkPixmap              *pixmap_arg,
+               GdkGC                   *gc_arg,
+               DviLib::DviFile         *dvi_file_arg,
+               uint                     base_dpi_arg,
+               AbstractFontFactory     *font_factory_arg);
+    virtual ~DviPainter ();
+};
+
+#endif
diff --git a/dvi/view.cc b/dvi/view.cc
new file mode 100755 (executable)
index 0000000..0f2f4b5
--- /dev/null
@@ -0,0 +1,113 @@
+#include "view.hh"
+#include "dl-dvi-fontdefinition.hh"
+
+using DviLib::DviPage;
+using DviLib::DviFontdefinition;
+
+View::View (Model *model_arg)
+{
+    model = model_arg;
+    
+    model->add_observer (*this);
+    
+    drawing_area = gtk_drawing_area_new ();
+    gtk_widget_show (drawing_area);
+    gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 
+                          BASE_DPI * PAPER_WIDTH,
+                          BASE_DPI * PAPER_HEIGHT);
+    gtk_signal_connect (GTK_OBJECT (drawing_area), "realize",
+                       (GtkSignalFunc) on_da_realize, this);
+    gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+                       (GtkSignalFunc) on_da_expose, this);
+}
+
+void
+View::create_pixmap (void)
+{
+    pixmap = gdk_pixmap_new(drawing_area->window,
+                           BASE_DPI * PAPER_WIDTH,
+                           BASE_DPI * PAPER_HEIGHT,
+                           -1);
+}
+
+void
+View::expose (GdkEventExpose *event)
+{
+    gdk_draw_pixmap (
+       drawing_area->window,
+       drawing_area->style->fg_gc[GTK_WIDGET_STATE (drawing_area)],
+       pixmap,
+       event->area.x,     event->area.y,
+       event->area.x,     event->area.y,
+       event->area.width, event->area.height);
+}
+
+void
+View::redraw (void) const
+{
+    // clear page
+    gdk_draw_rectangle (pixmap, 
+                       drawing_area->style->white_gc,
+                       TRUE, 0, 0,
+                       BASE_DPI * PAPER_WIDTH,
+                       BASE_DPI * PAPER_HEIGHT);
+    
+    cout << "width " << BASE_DPI * PAPER_WIDTH << endl;
+    cout << "height " << BASE_DPI * PAPER_HEIGHT << endl;
+    
+    // create a painter
+    DviPainter *painter =                              
+       new DviPainter (pixmap,
+                       drawing_area->style->fg_gc[GTK_WIDGET_STATE 
+                                                  (drawing_area)],
+                       model->get_dvi_file (),
+                       BASE_DPI,
+                       new FontFactory());
+    // get page
+    DviPage *page;
+    try 
+    {
+       page = model->get_dvi_file ()->get_page (0);
+    }
+    catch (string s)
+    {
+       cout << s;
+       abort ();
+    }
+    
+    // draw it with the painter
+    page->execute (* painter);
+    
+}
+
+void
+View::notify (void) const
+{
+    ModelState state = model->get_state ();
+    
+    switch (state) {
+    case HAS_FILE: 
+       redraw ();
+       break;
+       
+    case NO_FILE:
+       break;
+       
+    case ERROR:
+       break;
+    }
+}
+
+void
+on_da_realize (GtkDrawingArea *da, View *v)
+{
+    v->create_pixmap ();
+    v->notify ();
+}
+
+gint
+on_da_expose (GtkWidget *widget, GdkEventExpose *event, View *v)
+{
+    v->expose (event);
+    return FALSE;
+}
diff --git a/dvi/view.hh b/dvi/view.hh
new file mode 100755 (executable)
index 0000000..bdab6df
--- /dev/null
@@ -0,0 +1,37 @@
+// notes:
+/*
+ * hold en gdkpixbuf ved lige, og tegn den på en gtkdrawingarea 
+ * ved passende lejligheder
+ */
+
+#include "model.hh"
+#include <gtk/gtk.h>
+#include "painter.hh"
+
+enum {
+    BASE_DPI = 300,
+    PAPER_WIDTH = 7,           // inches
+    PAPER_HEIGHT = 17          // inches
+};
+
+class View : public Observer {
+private:
+    Model *model;
+    GtkWidget *drawing_area;
+    GdkPixmap *pixmap;
+public:
+    View (Model *model_arg);
+    
+    GtkWidget *get_widget (void) { return drawing_area; }
+    
+    void create_pixmap (void);
+    void expose (GdkEventExpose *event);
+    void notify (void) const;
+    void redraw (void) const;
+};
+
+void on_da_realize (GtkDrawingArea *da,
+                   View           *v);
+int  on_da_expose  (GtkWidget      *widget,
+                   GdkEventExpose *event,
+                   View           *v);