gcc on Mac OS X claims -fno-rtti shouldn't be used when compiling C
[swftools.git] / pdf2swf / SWFOutputDev.cc
index 020dc8f..43f106f 100644 (file)
@@ -29,7 +29,7 @@
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
-#ifdef HAVE_FONTCONFIG_H
+#ifdef HAVE_FONTCONFIG
 #include <fontconfig.h>
 #endif
 //xpdf header files
@@ -65,7 +65,8 @@
 #include "swfoutput.h"
 #include "../lib/log.h"
 #include "../lib/gfxdevice.h"
-#include "gfxtools.h"
+#include "../lib/gfxtools.h"
+#include "../lib/gfxfont.h"
 
 #include <math.h>
 
@@ -90,7 +91,7 @@ static int pagepos = 0;
 /* config */
 static double caplinewidth = 3.0;
 static int zoom = 72; /* xpdf: 86 */
-static int forceType0Fonts = 0;
+static int forceType0Fonts = 1;
 
 static void printInfoString(Dict *infoDict, char *key, char *fmt);
 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
@@ -124,6 +125,14 @@ class SWFOutputState {
     }
 };
 
+typedef struct _fontlist
+{
+    char*id;
+    char*filename;
+    gfxfont_t*font;
+    _fontlist*next;
+} fontlist_t;
+
 class SWFOutputDev:  public OutputDev {
   int outputstarted;
   struct swfoutput output;
@@ -227,6 +236,8 @@ public:
   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GfxImageColorMap*colorMap, GBool invert,
                                   GBool inlineImg, int mask, int *maskColors);
+  int SWFOutputDev::setGfxFont(char*id, char*filename);
+
   SWFOutputState states[64];
   int statepos;
 
@@ -257,6 +268,11 @@ public:
 
   int user_movex,user_movey;
   int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
+
+  gfxline_t* current_text_stroke;
+  char* current_font_id;
+  gfxfont_t* current_gfxfont;
+  fontlist_t* fontlist;
 };
 
 static char*getFontID(GfxFont*font);
@@ -303,7 +319,7 @@ class InfoOutputDev:  public OutputDev
       GfxFont*font = state->getFont();
       if(!font)
           return;
-      char*id = getFontID(font);
+      /*char*id = getFontID(font);*/
       /* FIXME*/
       num_fonts++;
   }
@@ -339,6 +355,8 @@ SWFOutputDev::SWFOutputDev()
     user_clipy1 = 0;
     user_clipx2 = 0;
     user_clipy2 = 0;
+    current_text_stroke = 0;
+    fontlist = 0;
     memset(&output, 0, sizeof(output));
 //    printf("SWFOutputDev::SWFOutputDev() \n");
 };
@@ -527,13 +545,14 @@ static void showFontError(GfxFont*font, int nr)
 
 static void dumpFontInfo(char*loglevel, GfxFont*font)
 {
-  char* name = getFontID(font);
+  char* id = getFontID(font);
+  char* name = getFontName(font);
   Ref* r=font->getID();
-  msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, getFontName(font), r->num,r->gen);
+  msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
 
   GString*gstr  = font->getTag();
    
-  msg("%s| Tag: %s\n", loglevel, name);
+  msg("%s| Tag: %s\n", loglevel, id);
   
   if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
 
@@ -567,10 +586,12 @@ static void dumpFontInfo(char*loglevel, GfxFont*font)
   
   Ref embRef;
   GBool embedded = font->getEmbeddedFontID(&embRef);
-  if(font->getEmbeddedFontName())
-    name = font->getEmbeddedFontName()->getCString();
+  char*embeddedName=0;
+  if(font->getEmbeddedFontName()) {
+    embeddedName = font->getEmbeddedFontName()->getCString();
+  }
   if(embedded)
-   msg("%s| Embedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num);
+   msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
 
   gstr = font->getExtFontFile();
   if(gstr)
@@ -582,6 +603,9 @@ static void dumpFontInfo(char*loglevel, GfxFont*font)
   if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
   if(font->isItalic()) msg("%s| is italic\n", loglevel);
   if(font->isBold()) msg("%s| is bold\n", loglevel);
+
+  free(id);
+  free(name);
 }
 
 //void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");}
@@ -833,6 +857,17 @@ SWFOutputDev::~SWFOutputDev()
 {
     swfoutput_destroy(&output);
     outputstarted = 0;
+
+    fontlist_t*l = this->fontlist;
+    while(l) {
+       fontlist_t*next = l->next;
+       l->next = 0;
+       gfxfont_free(l->font);
+       free(l->id);
+       free(l->filename);
+       free(l);
+       l = next;
+    }
 };
 GBool SWFOutputDev::upsideDown() 
 {
@@ -856,6 +891,32 @@ GBool SWFOutputDev::useGradients()
 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
                       "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
 
+static char tmp_printstr[4096];
+char* makeStringPrintable(char*str)
+{
+    int len = strlen(str);
+    int dots = 0;
+    if(len>=80) {
+       len = 80;
+       dots = 1;
+    }
+    int t;
+    for(t=0;t<len;t++) {
+       char c = str[t];
+       if(c<32 || c>124) {
+           c = '.';
+       }
+       tmp_printstr[t] = c;
+    }
+    if(dots) {
+       tmp_printstr[len++] = '.';
+       tmp_printstr[len++] = '.';
+       tmp_printstr[len++] = '.';
+    }
+    tmp_printstr[len] = 0;
+    return tmp_printstr;
+}
+
 void SWFOutputDev::beginString(GfxState *state, GString *s) 
 { 
     int render = state->getRender();
@@ -867,7 +928,7 @@ void SWFOutputDev::beginString(GfxState *state, GString *s)
     m21 *= state->getHorizScaling();
     swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
     if(render != 3 && render != 0)
-       msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], s->getCString());
+       msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));
     states[statepos].textRender = render;
 }
 
@@ -932,9 +993,8 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
     if(font->isCIDFont()) {
        GfxCIDFont*cfont = (GfxCIDFont*)font;
 
-       if(font->getType() == fontCIDType2) {
+       if(font->getType() == fontCIDType2)
            CIDToGIDMap = cfont->getCIDToGID();
-       }
     } else {
        Gfx8BitFont*font8;
        font8 = (Gfx8BitFont*)font;
@@ -942,14 +1002,14 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
        if(enc && enc[c])
           name = enc[c];
     }
     if (CIDToGIDMap) {
        msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\" render=%d\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name), render);
-       swfoutput_drawchar(&output, x1, y1, name, CIDToGIDMap[c], u, &col);
+       c = CIDToGIDMap[c];
     } else {
        msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\" render=%d\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name), render);
-       swfoutput_drawchar(&output, x1, y1, name, c, u, &col);
     }
+
+    swfoutput_drawchar(&output, x1, y1, name, c, u, &col);
 }
 
 void SWFOutputDev::endString(GfxState *state) 
@@ -959,6 +1019,8 @@ void SWFOutputDev::endString(GfxState *state)
 
 void SWFOutputDev::endTextObject(GfxState *state)
 {
+    if(states[statepos].textRender != state->getRender())
+       msg("<error> Internal error: drawChar.render!=beginString.render");
     msg("<trace> endTextObject()");
 }
 
@@ -1412,7 +1474,7 @@ char* searchForSuitableFont(GfxFont*gfxFont)
     if (!fcinitcalled) {
         msg("<debug> Initializing FontConfig...");
         fcinitcalled = true;
-       if(FcInit()) {
+       if(!FcInit()) {
             msg("<debug> FontConfig Initialization failed. Disabling.");
             config_use_fontconfig = 0;
             return 0;
@@ -1440,7 +1502,7 @@ char* searchForSuitableFont(GfxFont*gfxFont)
         // if we get an exact match
         if (strcmp((char *)v, name) == 0) {
            if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
-               filename = strdup((char*)v);
+               filename = strdup((char*)v); // mem leak
                char *nfn = strrchr(filename, '/');
                if(nfn) fontname = strdup(nfn+1);
                else    fontname = filename;
@@ -1481,7 +1543,7 @@ char* searchForSuitableFont(GfxFont*gfxFont)
             match = FcFontMatch (0, pattern, &result);
             
             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
-               filename = strdup((char*)v);
+               filename = strdup((char*)v); // mem leak
                char *nfn = strrchr(filename, '/');
                if(nfn) fontname = strdup(nfn+1);
                else    fontname = filename;
@@ -1515,7 +1577,7 @@ char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
     }
     filename = searchFont(fontname);
     if(!filename) {
-       msg("<error> Couldn't find font %s- did you install the default fonts?");
+       msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
        return 0;
     }
 
@@ -1524,12 +1586,12 @@ char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
        exit(1);
     }
     if(oldname) {
-       substitutesource[substitutepos] = oldname;
+       substitutesource[substitutepos] = strdup(oldname); //mem leak
        substitutetarget[substitutepos] = fontname;
        msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
        substitutepos ++;
     }
-    return strdup(filename);
+    return strdup(filename); //mem leak
 }
 
 void unlinkfont(char* filename)
@@ -1567,6 +1629,38 @@ void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
     this->xref = xref;
 }
 
+int SWFOutputDev::setGfxFont(char*id, char*filename)
+{
+    gfxfont_t*font = 0;
+    fontlist_t*last=0,*l = this->fontlist;
+
+    /* TODO: should this be part of the state? */
+    while(l) {
+       last = l;
+       if(!strcmp(l->id, id)) {
+           current_font_id = l->id;
+           current_gfxfont = l->font;
+           font = l->font;
+           return 1;
+       }
+       l = l->next;
+    }
+    if(!filename) return 0;
+    font = gfxfont_load(filename);
+    l = new fontlist_t;
+    l->font = font;
+    l->filename = strdup(filename);
+    l->id = strdup(id);
+    l->next = 0;
+    current_font_id = l->id;
+    current_gfxfont = l->font;
+    if(last) {
+       last->next = l;
+    } else {
+       this->fontlist = l;
+    }
+    return 1;
+}
 
 void SWFOutputDev::updateFont(GfxState *state) 
 {
@@ -1583,18 +1677,21 @@ void SWFOutputDev::updateFont(GfxState *state)
        too often */
     for(t=0;t<substitutepos;t++) {
        if(!strcmp(fontid, substitutesource[t])) {
-           fontid = substitutetarget[t];
+           free(fontid);fontid=0;
+           fontid = strdup(substitutetarget[t]);
            break;
        }
     }
 
     /* second, see if swfoutput already has this font
        cached- if so, we are done */
+    setGfxFont(fontid, 0);
     if(swfoutput_queryfont(&output, fontid))
     {
        swfoutput_setfont(&output, fontid, 0);
        
        msg("<debug> updateFont(%s) [cached]", fontid);
+       free(fontid);
        return;
     }
 
@@ -1604,6 +1701,7 @@ void SWFOutputDev::updateFont(GfxState *state)
            type3Warning = gTrue;
            showFontError(gfxFont, 2);
        }
+       free(fontid);
        return;
     }
 
@@ -1635,12 +1733,13 @@ void SWFOutputDev::updateFont(GfxState *state)
        msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
        msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
        fileName = substituteFont(gfxFont, fontid);
-       if(fontid) { fontid = substitutetarget[substitutepos-1]; /*ugly hack*/};
+       if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
        msg("<notice> Font is now %s (%s)", fontid, fileName);
     }
 
     if(!fileName) {
        msg("<error> Couldn't set font %s\n", fontid);
+       free(fontid);
        return;
     }
        
@@ -1648,11 +1747,16 @@ void SWFOutputDev::updateFont(GfxState *state)
     dumpFontInfo("<verbose>", gfxFont);
 
     swfoutput_setfont(&output, fontid, fileName);
+    
+    if(!setGfxFont(fontid, 0)) {
+       setGfxFont(fontid, fileName);
+    }
    
     if(fileName && del)
        unlinkfont(fileName);
     if(fileName)
         free(fileName);
+    free(fontid);
 }
 
 #define SQR(x) ((x)*(x))