added type3 char handling
authorkramm <kramm>
Sun, 21 Oct 2007 19:55:44 +0000 (19:55 +0000)
committerkramm <kramm>
Sun, 21 Oct 2007 19:55:44 +0000 (19:55 +0000)
lib/pdf/GFXOutputDev.cc
lib/pdf/GFXOutputDev.h
lib/pdf/InfoOutputDev.cc
lib/pdf/InfoOutputDev.h

index 0eb7c04..0a7e4bd 100644 (file)
@@ -1,4 +1,4 @@
-/* pdfswf.cc
+/* GFXOutputDev.cc
    implements a pdf output device (OutputDev).
 
    This file is part of swftools.
@@ -194,7 +194,7 @@ GFXOutputState::GFXOutputState() {
 
 GBool GFXOutputDev::interpretType3Chars() 
 {
-    return this->do_interpretType3Chars;
+    return gTrue;
 }
 
 typedef struct _drawnchar
@@ -360,7 +360,7 @@ GFXOutputDev::GFXOutputDev(parameter_t*p)
     this->config_break_on_warning=0;
     this->config_remapunicode=0;
     this->config_transparent=0;
-    this->do_interpretType3Chars = gTrue;
+    this->config_extrafontdata = 0;
 
     this->parameters = p;
     
@@ -377,9 +377,7 @@ GFXOutputDev::GFXOutputDev(parameter_t*p)
 
 void GFXOutputDev::setParameter(const char*key, const char*value)
 {
-    if(!strcmp(key,"rawtext")) {
-        this->do_interpretType3Chars = atoi(value)^1;
-    } else if(!strcmp(key,"breakonwarning")) {
+    if(!strcmp(key,"breakonwarning")) {
        this->config_break_on_warning = atoi(value);
     } else if(!strcmp(key,"fontconfig")) {
         this->config_use_fontconfig = atoi(value);
@@ -387,6 +385,8 @@ void GFXOutputDev::setParameter(const char*key, const char*value)
         this->config_remapunicode = atoi(value);
     } else if(!strcmp(key,"transparent")) {
         this->config_transparent = atoi(value);
+    } else if(!strcmp(key,"extrafontdata")) {
+        this->config_extrafontdata = atoi(value);
     }
 }
   
@@ -890,6 +890,21 @@ char* makeStringPrintable(char*str)
     tmp_printstr[len] = 0;
     return tmp_printstr;
 }
+#define INTERNAL_FONT_SIZE 1024.0
+void GFXOutputDev::updateFontMatrix(GfxState*state)
+{
+    double m11,m21,m12,m22;
+    state->getFontTransMat(&m11, &m12, &m21, &m22);
+    m11 *= state->getHorizScaling();
+    m21 *= state->getHorizScaling();
+
+    this->current_font_matrix.m00 = m11 / INTERNAL_FONT_SIZE;
+    this->current_font_matrix.m01 = m12 / INTERNAL_FONT_SIZE;
+    this->current_font_matrix.m10 = -m21 / INTERNAL_FONT_SIZE;
+    this->current_font_matrix.m11 = -m22 / INTERNAL_FONT_SIZE;
+    this->current_font_matrix.tx = 0;
+    this->current_font_matrix.ty = 0;
+}
 
 void GFXOutputDev::beginString(GfxState *state, GString *s) 
 { 
@@ -899,17 +914,7 @@ void GFXOutputDev::beginString(GfxState *state, GString *s)
     }
 
     msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
-    double m11,m21,m12,m22;
-    state->getFontTransMat(&m11, &m12, &m21, &m22);
-    m11 *= state->getHorizScaling();
-    m21 *= state->getHorizScaling();
-
-    this->current_font_matrix.m00 = m11 / 1024.0;
-    this->current_font_matrix.m01 = m12 / 1024.0;
-    this->current_font_matrix.m10 = -m21 / 1024.0;
-    this->current_font_matrix.m11 = -m22 / 1024.0;
-    this->current_font_matrix.tx = 0;
-    this->current_font_matrix.ty = 0;
+    updateFontMatrix(state);
 }
 
 static gfxline_t* mkEmptyGfxShape(double x, double y)
@@ -948,7 +953,7 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y,
 
     GfxFont*font = state->getFont();
 
-    if(font->getType() == fontType3 && do_interpretType3Chars) {
+    if(font->getType() == fontType3) {
        /* type 3 chars are passed as graphics */
        msg("<debug> type3 char at %f/%f", x, y);
        return;
@@ -1034,38 +1039,49 @@ void GFXOutputDev::endTextObject(GfxState *state)
 /* the logic seems to be as following:
    first, beginType3Char is called, with the charcode and the coordinates.
    if this function returns true, it already knew about the char and has now drawn it.
-   if the function returns false, it's a new char, and type3D1 is called with some parameters-
-   the all draw operations until endType3Char are part of the char (which in this moment is
+   if the function returns false, it's a new char, and type3D0 and/or type3D1 might be 
+   called with some parameters.
+   Afterwards, all draw operations until endType3Char are part of the char (which in this moment is
    at the position first passed to beginType3Char). the char ends with endType3Char.
 
    The drawing operations between beginType3Char and endType3Char are somewhat different to
-   the normal ones. For example, the fillcolor equals the stroke color.
+   the normal ones. For example, the fillcolor equals the stroke color. (Because the stroke
+   color determines the color of a font)
 */
 
-GBool GFXOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
+GBool GFXOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode charid, Unicode *u, int uLen)
 {
-    msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
+    msg("<debug> beginType3Char %d u=%d", charid, uLen?u[0]:0);
     type3active = 1;
+    
+    if(config_extrafontdata && current_fontinfo) {
+
+       gfxmatrix_t m = this->current_font_matrix;
+       state->transform(0, 0, &m.tx, &m.ty);
+       m.m00*=INTERNAL_FONT_SIZE;
+       m.m01*=INTERNAL_FONT_SIZE;
+       m.m10*=INTERNAL_FONT_SIZE;
+       m.m11*=INTERNAL_FONT_SIZE;
+       m.tx += user_movex + clipmovex;
+       m.ty += user_movey + clipmovey;
+
+       if(!current_fontinfo || (unsigned)charid >= current_fontinfo->num_glyphs || !current_fontinfo->glyphs[charid]) {
+           msg("<error> Invalid charid %d for font %s", charid, current_font_id);
+           return gFalse;
+       }
+       gfxcolor_t col={0,0,0,0};
+       CharCode glyphid = current_fontinfo->glyphs[charid]->glyphid;
+       device->drawchar(device, current_gfxfont, glyphid, &col, &m);
+    }
 
-    /*int t;
-
-    gfxcolor_t col={255,0,0,0};
-    gfxmatrix_t m = {1,0,0, 0,1,0};
-
-    for(t=0;t<uLen;t++) {
-       device->drawchar(device, 0, u[t], &col, &m);
-    }*/
 
     /* the character itself is going to be passed using the draw functions */
     return gFalse; /* gTrue= is_in_cache? */
 }
 
 void GFXOutputDev::type3D0(GfxState *state, double wx, double wy) {
-    msg("<debug> type3D0 width=%f height=%f", wx, wy);
 }
 void GFXOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
-    msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
-           llx,lly,urx,ury);
 }
 
 void GFXOutputDev::endType3Char(GfxState *state)
@@ -1136,8 +1152,9 @@ void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl
     clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
     clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
     device->startclip(device, clippath); outer_clip_box = 1;
-    if(!config_transparent)
+    if(!config_transparent) {
         device->fill(device, clippath, &white);
+    }
 }
 
 
@@ -1432,7 +1449,7 @@ gfxfont_t* createGfxFont(GfxFont*xpdffont, FontInfo*src)
     memset(font->glyphs, 0, sizeof(gfxglyph_t)*src->num_glyphs);
     font->id = strdup(getFontName(xpdffont));
     int t;
-    double quality = (1024 * 0.05) / src->max_size;
+    double quality = (INTERNAL_FONT_SIZE * 0.05) / src->max_size;
     double scale = 1;
     //printf("%d glyphs\n", font->num_glyphs);
     font->num_glyphs = 0;
@@ -1500,12 +1517,22 @@ void GFXOutputDev::updateFont(GfxState *state)
        return; 
     }  
     char*id = getFontID(gfxFont);
+    msg("<verbose> Updating font to %s", id);
+    if(gfxFont->getType() == fontType3) {
+       infofeature("Type3 fonts");
+       if(!config_extrafontdata) {
+           return;
+       }
+    }
     if(!id) {
        msg("<error> Internal Error: FontID is null");
        return; 
     }
 
     this->current_fontinfo = this->info->getFont(id);
+    if(!this->current_fontinfo->seen) {
+       dumpFontInfo("<verbose>", gfxFont);
+    }
     
     gfxfont_t*font = gfxfontlist_findfont(this->gfxfontlist,id);
     if(!font) {
@@ -1515,6 +1542,8 @@ void GFXOutputDev::updateFont(GfxState *state)
     }
     current_gfxfont = font;
     free(id);
+
+    updateFontMatrix(state);
 }
 
 #define SQR(x) ((x)*(x))
index 0e3d2b3..645283a 100644 (file)
@@ -96,6 +96,7 @@ public:
   //----- update graphics state
 
   virtual void updateFont(GfxState *state);
+  virtual void updateFontMatrix(GfxState *state);
   virtual void updateFillColor(GfxState *state);
   virtual void updateStrokeColor(GfxState *state);
   virtual void updateLineWidth(GfxState *state);
@@ -282,6 +283,7 @@ public:
   int config_break_on_warning;
   int config_remapunicode;
   int config_transparent;
+  int config_extrafontdata;
 
   parameter_t*parameters;
 };
index 7c83566..1d22a8b 100644 (file)
@@ -1,5 +1,6 @@
 #include "SplashTypes.h"
 #include "SplashOutputDev.h"
+#include "SplashPath.h"
 #include "InfoOutputDev.h"
 #include "GfxState.h"
 #include "../log.h"
@@ -10,19 +11,61 @@ InfoOutputDev::InfoOutputDev(XRef*xref)
     num_links = 0;
     num_images = 0;
     num_fonts = 0;
-    id2font = new GHash();
+    id2font = new GHash(1);
     SplashColor white = {255,255,255};
-    //splash = new SplashOutputDev(splashModeRGB8,320,0,white,0,0);
-    //splash->startDoc(xref);
+    splash = new SplashOutputDev(splashModeRGB8,320,0,white,0,0);
+    splash->startDoc(xref);
 }
 InfoOutputDev::~InfoOutputDev() 
 {
+    GHashIter*i;
+    id2font->startIter(&i);
+    GString*key;
+    FontInfo*fontinfo;
+    while(id2font->getNext(&i, &key, (void**)&fontinfo)) {
+       delete fontinfo;
+    }
+    id2font->killIter(&i);
+
     delete id2font;
+    delete splash;
+}
+void FontInfo::grow(int size)
+{
+    if(size >= this->num_glyphs) {
+       this->glyphs = (GlyphInfo**)realloc(this->glyphs, sizeof(GlyphInfo*)*(size));
+       memset(&this->glyphs[this->num_glyphs], 0, sizeof(SplashPath*)*((size)-this->num_glyphs));
+       this->num_glyphs = size;
+    }
+}
+FontInfo::FontInfo()
+{
+    this->charid2glyph = 0;
+    this->seen = 0;
+    this->num_glyphs = 0;
+    this->glyphs = 0;
+}
+FontInfo::~FontInfo()
+{
+    this->font = 0;
+    if(this->charid2glyph) {
+       free(this->charid2glyph);
+       this->charid2glyph = 0;
+    }
+    int t;
+    for(t=0;t<num_glyphs;t++) {
+       if(glyphs[t]) {
+           delete glyphs[t]->path;glyphs[t]->path = 0;
+           delete glyphs[t];
+           glyphs[t]=0;
+       }
+    }
 }
 GBool InfoOutputDev::upsideDown() {return gTrue;}
 GBool InfoOutputDev::useDrawChar() {return gTrue;}
 GBool InfoOutputDev::interpretType3Chars() {return gTrue;}
 GBool InfoOutputDev::useTilingPatternFill() {return gTrue;}
+
 void InfoOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
 {
     double x1,y1,x2,y2;
@@ -50,14 +93,18 @@ double InfoOutputDev::getMaximumFontSize(char*id)
     return info->max_size;
 }
 
-static char*getFontID(GfxFont*font)
+char*getFontID(GfxFont*font)
 {
     Ref*ref = font->getID();
     GString*gstr = font->getName();
     char* fname = gstr==0?0:gstr->getCString();
     char buf[128];
     if(fname==0) {
-       sprintf(buf, "font-%d-%d", ref->num, ref->gen);
+       if(font->getType() == fontType3) {
+           sprintf(buf, "t3font-%d-%d", ref->num, ref->gen);
+       } else {
+           sprintf(buf, "font-%d-%d", ref->num, ref->gen);
+       }
     } else {
        sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
     }
@@ -69,24 +116,44 @@ void InfoOutputDev::updateFont(GfxState *state)
     GfxFont*font = state->getFont();
     if(!font)
        return;
+    if(font->getType() == fontType3) {
+       return;
+    }
     char*id = getFontID(font);
-    
+
     FontInfo*info = (FontInfo*)id2font->lookup(id);
-    if(!info) {
-      GString* idStr = new GString(id);
-      info = new FontInfo;
-      info->font = font;
-      info->max_size = 0;
-      id2font->add(idStr, (void*)info);
-      free(id);
-      num_fonts++;
+    if(info) {
+       /* font already known */
+       free(id);
+       currentfont = info;
+       return;
     }
-    currentfont = info;
 
-    //splash->doUpdateFont(state);
-    //SplashFont* splash_font = splash->getCurrentFont();
+    info = new FontInfo;
+    info->font = font;
+    info->max_size = 0;
+
+    state->setCTM(1.0,0,0,1.0,0,0);
+    splash->updateCTM(state, 0,0,0,0,0,0);
+    state->setTextMat(1.0,0,0,-1.0,0,0);
+    state->setFont(font, 1024.0);
+    splash->doUpdateFont(state);
+    info->splash_font = splash->getCurrentFont();
 
-    //printf("%s: %d chars\n", id, splash_font->getNumChars());
+    if(!info->splash_font) {
+       delete info;
+       return;
+    }
+    GString* idStr = new GString(id);
+    id2font->add(idStr, (void*)info);
+    num_fonts++;
+    currentfont = info;
+    free(id);
+}
+FontInfo* InfoOutputDev::getFont(char*id)
+{
+    return (FontInfo*)id2font->lookup(id);
 }
 
 void InfoOutputDev::drawChar(GfxState *state, double x, double y,
@@ -94,9 +161,6 @@ void InfoOutputDev::drawChar(GfxState *state, double x, double y,
                      double originX, double originY,
                      CharCode code, int nBytes, Unicode *u, int uLen)
 {
-    int render = state->getRender();
-    if (render == 3)
-       return;
     double m11,m21,m12,m22;
     state->getFontTransMat(&m11, &m12, &m21, &m22);
     m11 *= state->getHorizScaling();
@@ -107,7 +171,83 @@ void InfoOutputDev::drawChar(GfxState *state, double x, double y,
     if(currentfont && currentfont->max_size < len) {
        currentfont->max_size = len;
     }
+    currentfont->grow(code+1);
+    GlyphInfo*g = currentfont->glyphs[code];
+    if(!g) {
+       g = currentfont->glyphs[code] = new GlyphInfo();
+       g->path = currentfont->splash_font->getGlyphPath(code);
+       g->unicode = 0;
+    }
+    if(uLen && (u[0]>=32 && u[0]<g->unicode || !g->unicode)) {
+       g->unicode = u[0];
+    }
+
+}
+
+GBool InfoOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
+{
+    GfxFont*font = state->getFont();
+    if(!font)
+       return gTrue;
+    if(font->getType() != fontType3)
+       return gTrue;
+
+    char*id = getFontID(font);
+    currentfont = (FontInfo*)id2font->lookup(id);
+    if(!currentfont) {
+       currentfont = new FontInfo;
+       currentfont->font = font;
+       GString* idStr = new GString(id);
+       id2font->add(idStr, (void*)currentfont);
+       num_fonts++;
+    }
+    currentfont = currentfont;
+    free(id);
+
+    currentfont->grow(code+1);
+    if(!currentfont->glyphs[code]) {
+       currentglyph = currentfont->glyphs[code] = new GlyphInfo();
+       currentglyph->unicode = uLen?u[0]:0;
+       currentglyph->path = new SplashPath();
+       currentglyph->x1=0;
+       currentglyph->y1=0;
+       currentglyph->x2=dx;
+       currentglyph->y2=-dy;
+       return gFalse;
+    } else {
+       return gTrue;
+    }
+}
+
+void InfoOutputDev::type3D0(GfxState *state, double wx, double wy)
+{
+    currentglyph->x1=0;
+    currentglyph->y1=0;
+    currentglyph->x2=wx;
+    currentglyph->y2=-wy;
+}
+
+void InfoOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
+{
+    currentglyph->x1=llx;
+    currentglyph->y1=-lly;
+    currentglyph->x2=urx;
+    currentglyph->y2=-ury;
+}
+
+void InfoOutputDev::endType3Char(GfxState *state)
+{
+    double x1 = currentglyph->x1;
+    double y1 = currentglyph->y1;
+    double x2 = currentglyph->x2;
+    double y2 = currentglyph->y2;
+    currentglyph->path->moveTo(x1,y1);
+    currentglyph->path->lineTo(x2,y1);
+    currentglyph->path->lineTo(x2,y2);
+    currentglyph->path->lineTo(x1,y2);
+    currentglyph->path->close();
 }
+
 void InfoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
                           int width, int height, GBool invert,
                           GBool inlineImg) 
index ab120bf..de69047 100644 (file)
@@ -1,3 +1,23 @@
+/* InfoOutputDev.h
+   A special output device which collects information about a PDF file,
+   like fonts, Type3 glyphs and so on.
+
+   This file is part of swftools.
+
+   Swftools is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   Swftools is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with swftools; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
 #ifndef __infooutputdev_h__
 #define __infooutputdev_h__
 
 #include "OutputDev.h"
 #include "SplashFont.h"
 #include "SplashOutputDev.h"
+#include "SplashPath.h"
 #include "GHash.h"
 
+struct GlyphInfo
+{
+    SplashPath*path;
+    int unicode;
+    int glyphid;
+    double x1,y1,x2,y2;
+};
+
 struct FontInfo
 {
+    FontInfo();
+    ~FontInfo();
+    void grow(int size);
+
     GfxFont*font;
     double max_size;
+    int num_glyphs;
+    GlyphInfo**glyphs;
+    int*charid2glyph;
+    SplashFont*splash_font;
+    char seen;
 };
 
+extern char*getFontID(GfxFont*font);
+
 class InfoOutputDev: public OutputDev 
 {
-  GHash* id2font;
-  FontInfo* currentfont;
-  SplashOutputDev*splash;
-  public:
-  int x1,y1,x2,y2;
-  int num_links;
-  int num_images;
-  int num_fonts;
-
-  InfoOutputDev(XRef*xref);
-  virtual ~InfoOutputDev(); 
-  virtual GBool useTilingPatternFill();
-  virtual GBool upsideDown();
-  virtual GBool useDrawChar();
-  virtual GBool interpretType3Chars();
-  virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2);
-  virtual void drawLink(Link *link, Catalog *catalog);
-  virtual double getMaximumFontSize(char*id);
-  virtual void updateFont(GfxState *state);
-  virtual void drawChar(GfxState *state, double x, double y,
-                       double dx, double dy,
-                       double originX, double originY,
-                       CharCode code, int nBytes, Unicode *u, int uLen);
-  virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
-                            int width, int height, GBool invert,
-                            GBool inlineImg);
-  virtual void drawImage(GfxState *state, Object *ref, Stream *str,
-                        int width, int height, GfxImageColorMap *colorMap,
-                        int *maskColors, GBool inlineImg);
-  virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
-                               int width, int height,
-                               GfxImageColorMap *colorMap,
-                               Stream *maskStr,
-                               int maskWidth, int maskHeight,
-                               GBool maskInvert);
-  virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
-                                   int width, int height,
-                                   GfxImageColorMap *colorMap,
-                                   Stream *maskStr,
-                                   int maskWidth, int maskHeight,
-                                   GfxImageColorMap *maskColorMap);
+    GHash* id2font;
+    FontInfo* currentfont;
+    GlyphInfo* currentglyph;
+    SplashOutputDev*splash;
+    public:
+    int x1,y1,x2,y2;
+    int num_links;
+    int num_images;
+    int num_fonts;
+
+    InfoOutputDev(XRef*xref);
+    virtual ~InfoOutputDev(); 
+    virtual GBool useTilingPatternFill();
+    virtual GBool upsideDown();
+    virtual GBool useDrawChar();
+    virtual GBool interpretType3Chars();
+    virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2);
+    virtual void drawLink(Link *link, Catalog *catalog);
+    virtual double getMaximumFontSize(char*id);
+    virtual void updateFont(GfxState *state);
+
+    virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
+    virtual void type3D0(GfxState *state, double wx, double wy);
+    virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
+    virtual void endType3Char(GfxState *state);
+
+    virtual void drawChar(GfxState *state, double x, double y,
+                         double dx, double dy,
+                         double originX, double originY,
+                         CharCode code, int nBytes, Unicode *u, int uLen);
+    virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+                              int width, int height, GBool invert,
+                              GBool inlineImg);
+    virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+                          int width, int height, GfxImageColorMap *colorMap,
+                          int *maskColors, GBool inlineImg);
+    virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+                                 int width, int height,
+                                 GfxImageColorMap *colorMap,
+                                 Stream *maskStr,
+                                 int maskWidth, int maskHeight,
+                                 GBool maskInvert);
+    virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+                                     int width, int height,
+                                     GfxImageColorMap *colorMap,
+                                     Stream *maskStr,
+                                     int maskWidth, int maskHeight,
+                                     GfxImageColorMap *maskColorMap);
+    virtual FontInfo* getFont(char*id);
 };
 
 #endif //__infooutputdev_h__