fixed bounding box bug
[swftools.git] / pdf2swf / SWFOutputDev.cc
index b14e633..020dc8f 100644 (file)
@@ -114,6 +114,16 @@ struct mapping {
 {"Symbol",                "s050000l"},
 {"ZapfDingbats",          "d050000l"}};
 
+class SWFOutputState {
+    public:
+    int clipping;
+    int textRender;
+    SWFOutputState() {
+       this->clipping = 0;
+       this->textRender = 0;
+    }
+};
+
 class SWFOutputDev:  public OutputDev {
   int outputstarted;
   struct swfoutput output;
@@ -193,6 +203,7 @@ public:
   //----- text drawing
   virtual void beginString(GfxState *state, GString *s) ;
   virtual void endString(GfxState *state) ;
+  virtual void endTextObject(GfxState *state);
   virtual void drawChar(GfxState *state, double x, double y,
                        double dx, double dy,
                        double originX, double originY,
@@ -206,16 +217,18 @@ public:
                         int width, int height, GfxImageColorMap *colorMap,
                         int *maskColors, GBool inlineImg);
   
-  virtual GBool beginType3Char(GfxState *state,
-                              CharCode code, Unicode *u, int uLen);
+  virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
   virtual void endType3Char(GfxState *state);
 
+  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);
+
   private:
   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GfxImageColorMap*colorMap, GBool invert,
                                   GBool inlineImg, int mask, int *maskColors);
-  int clipping[64];
-  int clippos;
+  SWFOutputState states[64];
+  int statepos;
 
   int currentpage;
 
@@ -315,8 +328,7 @@ SWFOutputDev::SWFOutputDev()
     linkinfo = 0;
     pbminfo = 0;
     type3active = 0;
-    clippos = 0;
-    clipping[clippos] = 0;
+    statepos = 0;
     outputstarted = 0;
     xref = 0;
     substitutepos = 0;
@@ -575,6 +587,21 @@ static void dumpFontInfo(char*loglevel, GfxFont*font)
 //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");}
 //void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");}
 
+
+void dump_outline(gfxline_t*line)
+{
+    while(line) {
+       if(line->type == gfx_moveTo) {
+           msg("<debug> |     moveTo %.2f %.2f", line->x,line->y);
+       } else if(line->type == gfx_lineTo) {
+           msg("<debug> |     lineTo %.2f %.2f", line->x,line->y);
+       } else if(line->type == gfx_splineTo) {
+           msg("<debug> |     splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
+       }
+       line = line->next;
+    }
+}
+
 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
 {
     int num = path->getNumSubpaths();
@@ -631,22 +658,8 @@ gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
     if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
        draw.lineTo(&draw, lastx, lasty);
     }
-    return (gfxline_t*)draw.result(&draw);
-}
-
-
-void dump_outline(gfxline_t*line)
-{
-    while(line) {
-       if(line->type == gfx_moveTo) {
-           msg("<debug> |     moveTo %.2f %.2f", line->x,line->y);
-       } else if(line->type == gfx_lineTo) {
-           msg("<debug> |     lineTo %.2f %.2f", line->x,line->y);
-       } else if(line->type == gfx_splineTo) {
-           msg("<debug> |     splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
-       }
-       line = line->next;
-    }
+    gfxline_t*result = (gfxline_t*)draw.result(&draw);
+    return result;
 }
 
 /*----------------------------------------------------------------------------
@@ -663,13 +676,16 @@ void SWFOutputDev::stroke(GfxState *state)
 
     GfxRGB rgb;
     double opaq = state->getStrokeOpacity();
-    state->getStrokeRGB(&rgb);
+    if(type3active)
+       state->getFillRGB(&rgb);
+    else
+       state->getStrokeRGB(&rgb);
     gfxcolor_t col;
     col.r = (unsigned char)(rgb.r*255);
     col.g = (unsigned char)(rgb.g*255);
     col.b = (unsigned char)(rgb.b*255);
     col.a = (unsigned char)(opaq*255);
-    
+   
     gfx_capType capType = gfx_capRound;
     if(lineCap == 0) capType = gfx_capButt;
     else if(lineCap == 1) capType = gfx_capRound;
@@ -710,11 +726,15 @@ void SWFOutputDev::stroke(GfxState *state)
     }
     
     if(getLogLevel() >= LOGLEVEL_TRACE)  {
-        msg("<trace> stroke width=%f join=%s cap=%s dashes=%d\n",
+       double gray;
+       state->getStrokeGray(&gray);
+        msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
                width,
                lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
                lineCap==0?"butt": (lineJoin==1?"round":"square"),
-               dashnum
+               dashnum,
+               col.r,col.g,col.b,col.a,
+               gray
                );
         dump_outline(line);
     }
@@ -777,7 +797,7 @@ void SWFOutputDev::clip(GfxState *state)
     }
 
     swfoutput_startclip(&output, line);
-    clipping[clippos] ++;
+    states[statepos].clipping++;
     gfxline_free(line);
 }
 void SWFOutputDev::eoClip(GfxState *state) 
@@ -791,7 +811,7 @@ void SWFOutputDev::eoClip(GfxState *state)
     }
 
     swfoutput_startclip(&output, line);
-    clipping[clippos] ++;
+    states[statepos].clipping++;
     gfxline_free(line);
 }
 
@@ -833,24 +853,41 @@ GBool SWFOutputDev::useGradients()
     return gTrue;
 }
 
+char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
+                      "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
+
 void SWFOutputDev::beginString(GfxState *state, GString *s) 
 { 
+    int render = state->getRender();
+    msg("<trace> beginString(%s) render=%d", s->getCString(), render);
     double m11,m21,m12,m22;
 //    msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
     state->getFontTransMat(&m11, &m12, &m21, &m22);
     m11 *= state->getHorizScaling();
     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());
+    states[statepos].textRender = render;
 }
 
+static int textCount = 0;
+
 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
                        double dx, double dy,
                        double originX, double originY,
                        CharCode c, Unicode *_u, int uLen)
 {
+    textCount++;
+
+    int render = state->getRender();
     // check for invisible text -- this is used by Acrobat Capture
-    if ((state->getRender() & 3) == 3)
+    if (render == 3)
        return;
+
+    if(states[statepos].textRender != render)
+       msg("<error> Internal error: drawChar.render!=beginString.render");
+
     GfxRGB rgb;
     double opaq = state->getFillOpacity();
     state->getFillRGB(&rgb);
@@ -865,6 +902,7 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
 
     if(font->getType() == fontType3) {
        /* type 3 chars are passed as graphics */
+       msg("<debug> type3 char at %f/%f", x, y);
        return;
     }
     double x1,y1;
@@ -906,28 +944,51 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
     }
  
     if (CIDToGIDMap) {
-       msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\"\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name));
+       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);
     } else {
-       msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name));
+       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);
     }
 }
 
-void SWFOutputDev::endString(GfxState *state) { 
+void SWFOutputDev::endString(GfxState *state) 
+{ 
+    msg("<trace> endString()");
 }    
 
-GBool SWFOutputDev::beginType3Char(GfxState *state,
-                              CharCode code, Unicode *u, int uLen)
+void SWFOutputDev::endTextObject(GfxState *state)
+{
+    msg("<trace> endTextObject()");
+}
+
+/* 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
+   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.
+*/
+
+GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
 {
     msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
     type3active = 1;
-    /* the character itself is going to be passed using
-       drawImageMask() */
+    /* the character itself is going to be passed using the draw functions */
     return gFalse; /* gTrue= is_in_cache? */
 }
 
+void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
+    msg("<debug> type3D0 width=%f height=%f", wx, wy);
+}
+void SWFOutputDev::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 SWFOutputDev::endType3Char(GfxState *state)
 {
     type3active = 0;
@@ -1128,23 +1189,25 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
 }
 
 void SWFOutputDev::saveState(GfxState *state) {
-  msg("<debug> saveState\n");
+  msg("<trace> saveState\n");
   updateAll(state);
-  if(clippos<64)
-    clippos ++;
-  else
+  if(statepos>=64) {
     msg("<error> Too many nested states in pdf.");
-  clipping[clippos] = 0;
+    return;
+  }
+  statepos ++;
+  states[statepos].clipping = 0; //? shouldn't this be the current value?
+  states[statepos].textRender = states[statepos-1].textRender;
 };
 
 void SWFOutputDev::restoreState(GfxState *state) {
-  msg("<debug> restoreState\n");
+  msg("<trace> restoreState\n");
   updateAll(state);
-  while(clipping[clippos]) {
+  while(states[statepos].clipping) {
       swfoutput_endclip(&output);
-      clipping[clippos]--;
+      states[statepos].clipping--;
   }
-  clippos--;
+  statepos--;
 }
 
 char* SWFOutputDev::searchFont(char*name) 
@@ -1212,7 +1275,6 @@ void SWFOutputDev::updateStrokeColor(GfxState *state)
     GfxRGB rgb;
     double opaq = state->getStrokeOpacity();
     state->getStrokeRGB(&rgb);
-
     //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
 }
 
@@ -1254,8 +1316,7 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
        msg("<notice> Collection: %s", c.getCString());
     }*/
 
-    if (font->getType() == fontType1C ||
-       font->getType() == fontCIDType0C) {
+    if (font->getType() == fontType1C) {
       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
        fclose(f);
        msg("<error> Couldn't read embedded font file");
@@ -1845,6 +1906,8 @@ void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GBool invert,
                                   GBool inlineImg) 
 {
+  if(states[statepos].textRender & 4) //clipped
+      return;
   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
   drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
 }
@@ -1853,6 +1916,9 @@ void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
                         int width, int height, GfxImageColorMap *colorMap,
                         int *maskColors, GBool inlineImg)
 {
+  if(states[statepos].textRender & 4) //clipped
+      return;
+
   msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
          colorMap?"colorMap":"no colorMap", 
          maskColors?"maskColors":"no maskColors",