fixed some error messages.
[swftools.git] / pdf2swf / SWFOutputDev.cc
index 2f2b807..8226c66 100644 (file)
@@ -93,12 +93,6 @@ static int fontnum = 0;
 
 static int config_use_fontconfig = 1;
 
-// swf <-> pdf pages
-// TODO: move into pdf_doc_t
-static int*pages = 0;
-static int pagebuflen = 0;
-static int pagepos = 0;
-
 /* config */
 static double caplinewidth = 3.0;
 static double zoom = 72; /* xpdf: 86 */
@@ -107,6 +101,8 @@ static int forceType0Fonts = 1;
 static void printInfoString(Dict *infoDict, char *key, char *fmt);
 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
 
+static char* lastfontdir = 0;
+
 struct mapping {
     char*pdffont;
     char*filename;
@@ -169,7 +165,7 @@ public:
   virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
 
   void endframe();
-  void* getSWF();
+  void* get(char*name);
 
   //----- get info about output device
 
@@ -302,6 +298,57 @@ public:
   gfxmatrix_t current_font_matrix;
 
   fontlist_t* fontlist;
+
+  int*pages;
+  int pagebuflen;
+  int pagepos;
+
+  friend void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage);
+};
+
+typedef struct _drawnchar
+{
+    gfxcoord_t x,y;
+    int charid;
+    gfxcolor_t color;
+} drawnchar_t;
+
+class CharBuffer
+{
+    drawnchar_t * chars;
+    int buf_size;
+    int num_chars;
+
+public:
+
+    CharBuffer()
+    {
+       buf_size = 32;
+       chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
+       memset(chars, 0, sizeof(drawnchar_t)*buf_size);
+       num_chars = 0;
+    }
+    ~CharBuffer()
+    {
+       free(chars);chars = 0;
+    }
+
+    void grow(int size)
+    {
+       if(size>=buf_size) {
+           buf_size += 32;
+           chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
+       }
+    }
+
+    void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
+    {
+       grow(num_chars);
+       chars[num_chars].x = x;
+       chars[num_chars].y = y;
+       chars[num_chars].color = color;
+       chars[num_chars].charid = charid;
+    }
 };
 
 static char*getFontID(GfxFont*font);
@@ -438,6 +485,9 @@ SWFOutputDev::SWFOutputDev()
     fontlist = 0;
     result = 0;
     outer_clip_box = 0;
+    pages = 0;
+    pagebuflen = 0;
+    pagepos = 0;
     output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
     gfxdevice_swf_init(output);
     /* configure device */
@@ -972,10 +1022,10 @@ int SWFOutputDev::save(char*filename)
     finish();
     return result->save(result, filename);
 }
-void* SWFOutputDev::getSWF()
+void* SWFOutputDev::get(char*name)
 {
     finish();
-    return result->get(result, "swf");
+    return result->get(result, name);
 }
 
 SWFOutputDev::~SWFOutputDev() 
@@ -986,6 +1036,10 @@ SWFOutputDev::~SWFOutputDev()
        this->result->destroy(this->result);
        this->result = 0;
     }
+    
+    if(this->pages) {
+       free(this->pages); this->pages = 0;
+    }
 
     fontlist_t*l = this->fontlist;
     while(l) {
@@ -1128,8 +1182,10 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
 {
     int render = state->getRender();
     // check for invisible text -- this is used by Acrobat Capture
-    if (render == 3)
+    if (render == 3) {
+       msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
        return;
+    }
 
     if(states[statepos].textRender != render)
        msg("<error> Internal error: drawChar.render!=beginString.render");
@@ -1173,8 +1229,9 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
        Gfx8BitFont*font8;
        font8 = (Gfx8BitFont*)font;
        char**enc=font8->getEncoding();
-       if(enc && enc[c])
+       if(enc && enc[c] && strcasecmp(enc[c], "space")) {
           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);
@@ -1183,8 +1240,26 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
        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);
     }
 
-    int charid = getGfxCharID(current_gfxfont, c, name, u);
-    if(charid<0) {
+    int charid = -1;
+   
+    if(uLen<=1) {
+       charid = getGfxCharID(current_gfxfont, c, name, u);
+    } else {
+       charid = getGfxCharID(current_gfxfont, c, 0, -1);
+       if(charid < 0) {
+           /* multiple unicodes- should usually map to a ligature.
+              if the ligature doesn't exist, we need to draw
+              the characters one-by-one. */
+           int t;
+           msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
+           for(t=0;t<uLen;t++) {
+               drawChar(state, x, y, dx, dy, originX, originY, c, _u+t, 1);
+           }
+           return;
+       }
+    }
+
+    if(charid<0 && name) {
        if(strcasecmp(name, "space")) {
            msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)", 
                    FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
@@ -1452,7 +1527,8 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
                     }
                     else if(strstr(s, "last") || strstr(s, "end"))
                     {
-                        page = pagepos>0?pages[pagepos-1]:0;
+                       if(pages && pagepos>0)
+                           page = pages[pagepos-1];
                     }
                     else if(strstr(s, "first") || strstr(s, "top"))
                     {
@@ -1503,13 +1579,19 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
     if(page>0)
     {
         int t;
-        for(t=0;t<pagepos;t++)
-            if(pages[t]==page)
+       int lpage = -1;
+        for(t=1;t<=pagepos;t++) {
+            if(pages[t]==page) {
+               lpage = t;
                 break;
-        if(t!=pagepos) {
+           }
+       }
+        if(lpage>=0) {
            char buf[80];
            sprintf(buf, "page%d", t);
             output->drawlink(output, points, buf);
+       } else {
+           msg("<warning> Invalid link to page %d", page);
        }
     }
     else if(url)
@@ -1842,7 +1924,7 @@ char* searchForSuitableFont(GfxFont*gfxFont)
 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
 {
     char*fontname = 0, *filename = 0;
-    msg("<notice> subsituteFont(%s)", oldname);
+    msg("<notice> substituteFont(%s)", oldname);
 
     if(!(fontname = searchForSuitableFont(gfxFont))) {
        fontname = "Times-Roman";
@@ -2019,7 +2101,12 @@ void SWFOutputDev::updateFont(GfxState *state)
     if(!fileName) {
        char * fontname = getFontName(gfxFont);
        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);
+       
+       if(lastfontdir)
+           msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s/swftools/fonts", fontname, lastfontdir);
+       else
+           msg("<warning> Try specifying one or more font directories");
+
        fileName = substituteFont(gfxFont, fontid);
        if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
        msg("<notice> Font is now %s (%s)", fontid, fileName);
@@ -2532,6 +2619,7 @@ void pdfswf_addfontdir(char*dirname)
 {
 #ifdef HAVE_DIRENT_H
     msg("<notice> Adding %s to font directories", dirname);
+    lastfontdir = strdup(dirname);
     DIR*dir = opendir(dirname);
     if(!dir) {
        msg("<warning> Couldn't open directory %s\n", dirname);
@@ -2668,22 +2756,6 @@ pdf_doc_t* pdf_init(char*filename, char*userPassword)
     return pdf_doc;
 }
 
-static void pdfswf_preparepage(int page)
-{
-    /*FIXME*/
-    if(!pages) {
-       pages = (int*)malloc(1024*sizeof(int));
-       pagebuflen = 1024;
-    } else {
-       if(pagepos == pagebuflen)
-       {
-           pagebuflen+=1024;
-           pages = (int*)realloc(pages, pagebuflen);
-       }
-    }
-    pages[pagepos++] = page;
-}
-
 class MemCheck
 {
     public: ~MemCheck()
@@ -2700,8 +2772,6 @@ void pdf_destroy(pdf_doc_t*pdf_doc)
 
     delete i->doc; i->doc=0;
     
-    free(pages); pages = 0; //FIXME
-
     if(i->info) {
        delete i->info;i->info=0;
     }
@@ -2763,6 +2833,32 @@ void swf_output_endframe(swf_output_t*swf)
     i->outputDev->endframe();
 }
 
+void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
+{
+    swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
+    SWFOutputDev*o = i->outputDev;
+
+    if(pdfpage < 0)
+       return;
+
+    if(!o->pages) {
+       o->pagebuflen = 1024;
+       o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
+       memset(o->pages, -1, o->pagebuflen*sizeof(int));
+    } else {
+       while(pdfpage >= o->pagebuflen)
+       {
+           int oldlen = o->pagebuflen;
+           o->pagebuflen+=1024;
+           o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
+           memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
+       }
+    }
+    o->pages[pdfpage] = outputpage;
+    if(pdfpage>o->pagepos)
+       o->pagepos = pdfpage;
+}
+
 int swf_output_save(swf_output_t*swf, char*filename)
 {
     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
@@ -2770,10 +2866,10 @@ int swf_output_save(swf_output_t*swf, char*filename)
     return ret;
 }
 
-void* swf_output_get(swf_output_t*swf)
+void* swf_output_get(swf_output_t*swf,char*name)
 {
     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
-    void* ret = i->outputDev->getSWF();
+    void* ret = i->outputDev->get(name);
     return ret;
 }