added test+fix for transparency group stacking
[swftools.git] / lib / pdf / GFXOutputDev.cc
index 62aa8c7..2f4a2cf 100644 (file)
@@ -599,6 +599,7 @@ GFXOutputDev::GFXOutputDev(InfoOutputDev*info, PDFDoc*doc)
     this->config_remapunicode=0;
     this->config_transparent=0;
     this->config_extrafontdata = 0;
+    this->config_drawonlyshapes = 0;
     this->config_disable_polygon_conversion = 0;
     this->config_multiply = 1;
     this->page2page = 0;
@@ -615,6 +616,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,"drawonlyshapes")) {
+        this->config_drawonlyshapes = atoi(value);
     } else if(!strcmp(key,"extrafontdata")) {
         this->config_extrafontdata = atoi(value);
     } else if(!strcmp(key,"convertgradients")) {
@@ -1219,20 +1222,21 @@ gfxcolor_t getFillColor(GfxState * state)
     return col;
 }
 
-void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line) 
+void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line, char evenodd) 
 {
     gfxcolor_t col = getFillColor(state);
 
     if(getLogLevel() >= LOGLEVEL_TRACE)  {
-        msg("<trace> fill %02x%02x%02x%02x", col.r, col.g, col.b, col.a);
+        msg("<trace> %sfill %02x%02x%02x%02x%s", evenodd?"eo":"", col.r, col.g, col.b, col.a);
         dump_outline(line);
     }
     device->fill(device, line, &col);
 }
 
-void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line) 
+void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line, char evenodd) 
 {
     if(getLogLevel() >= LOGLEVEL_TRACE)  {
+        msg("<trace> %sclip", evenodd?"eo":"");
         dump_outline(line);
     }
     gfxbbox_t bbox = gfxline_getbbox(line);
@@ -1252,7 +1256,7 @@ void GFXOutputDev::clip(GfxState *state)
        gfxline_free(line);
        line = line2;
     }
-    clipToGfxLine(state, line);
+    clipToGfxLine(state, line, 0);
     gfxline_free(line);
 }
 
@@ -1260,7 +1264,7 @@ void GFXOutputDev::eoClip(GfxState *state)
 {
     GfxPath * path = state->getPath();
     gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey);
-    clipToGfxLine(state, line);
+    clipToGfxLine(state, line, 1);
     gfxline_free(line);
 }
 void GFXOutputDev::clipToStrokePath(GfxState *state)
@@ -1412,10 +1416,35 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y,
     gfxmatrix_t m = this->current_font_matrix;
     this->transformXY(state, x-originX, y-originY, &m.tx, &m.ty);
     //m.tx += originX; m.ty += originY;
-    
-    msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d render=%d glyphid=%d font=%08x",m.tx,m.ty,(charid&127)>=32?charid:'?', charid, u, uLen, font->isCIDFont(), render, glyphid, current_gfxfont);
 
-    if(render == RENDER_FILL || render == RENDER_INVISIBLE) {
+    msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d render=%d glyphid=%d font=%08x",m.tx,m.ty,(charid&127)>=32?charid:'?', charid, u, uLen, font->isCIDFont(), render, glyphid, current_gfxfont);
+    
+    if((render == RENDER_FILL && !config_drawonlyshapes) || render == RENDER_INVISIBLE) {
+       int space = this->current_fontinfo->space_char;
+       if(config_extrafontdata && space>=0 && m.m00 && !m.m01) {
+           /* space char detection */
+           if(last_char_gfxfont == current_gfxfont && 
+              last_char_y == m.ty &&
+              !last_char_was_space) {
+               double expected_x = last_char_x + current_gfxfont->glyphs[last_char].advance*m.m00;
+               int space = this->current_fontinfo->space_char;
+               if(m.tx - expected_x >= m.m00*64) {
+                   msg("<debug> There's a %f (%f) pixel gap between char %d and char %d, I'm inserting a space here", 
+                           m.tx-expected_x, 
+                           (m.tx-expected_x)/m.m00,
+                           last_char, glyphid);
+                   gfxmatrix_t m2 = m;
+                   m2.tx = expected_x + (m.tx - expected_x - current_gfxfont->glyphs[space].advance*m.m00)/2;
+                   if(m2.tx < expected_x) m2.tx = expected_x;
+                   device->drawchar(device, current_gfxfont, space, &col, &m2);
+               }
+           }
+           last_char_gfxfont = current_gfxfont;
+           last_char = glyphid;
+           last_char_x = m.tx;
+           last_char_y = m.ty;
+           last_char_was_space = GLYPH_IS_SPACE(&current_gfxfont->glyphs[glyphid]);
+       }
        device->drawchar(device, current_gfxfont, glyphid, &col, &m);
     } else {
        msg("<debug> Drawing glyph %d as shape", charid);
@@ -1453,11 +1482,11 @@ void GFXOutputDev::endString(GfxState *state)
           however */
        device->setparameter(device, "mark","TXT");
        if((render&3) == RENDER_FILL) {
-           fillGfxLine(state, current_text_stroke);
+           fillGfxLine(state, current_text_stroke, 0);
            gfxline_free(current_text_stroke);
            current_text_stroke = 0;
        } else if((render&3) == RENDER_FILLSTROKE) {
-           fillGfxLine(state, current_text_stroke);
+           fillGfxLine(state, current_text_stroke, 0);
            strokeGfxline(state, current_text_stroke,0);
            gfxline_free(current_text_stroke);
            current_text_stroke = 0;
@@ -1477,7 +1506,7 @@ void GFXOutputDev::endTextObject(GfxState *state)
     
     if(current_text_clip) {
        device->setparameter(device, "mark","TXT");
-       clipToGfxLine(state, current_text_clip);
+       clipToGfxLine(state, current_text_clip, 0);
        device->setparameter(device, "mark","");
        gfxline_free(current_text_clip);
        current_text_clip = 0;
@@ -1601,6 +1630,8 @@ void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl
     states[statepos].dashPattern = 0;
     states[statepos].dashLength = 0;
     states[statepos].dashStart = 0;
+    
+    this->last_char_gfxfont = 0;
 }
 
 
@@ -1846,6 +1877,13 @@ void GFXOutputDev::restoreState(GfxState *state) {
   }
   if(states[statepos].state!=state) {
       msg("<fatal> bad state nesting");
+      if(verbose) {
+         int t;
+         for(t=0;t<=statepos;t++) {
+             printf("%08x ", states[t].state);
+         }
+         printf("\n");
+      }
       exit(1);
   }
   states[statepos].state=0;
@@ -2473,7 +2511,7 @@ void GFXOutputDev::fill(GfxState *state)
         gfxline_free(line);
         line = line2;
     }
-    fillGfxLine(state, line);
+    fillGfxLine(state, line, 0);
     gfxline_free(line);
 }
 
@@ -2484,7 +2522,7 @@ void GFXOutputDev::eoFill(GfxState *state)
 
     GfxPath * path = state->getPath();
     gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey);
-    fillGfxLine(state, line);
+    fillGfxLine(state, line, 1);
     gfxline_free(line);
 }
 
@@ -2504,8 +2542,8 @@ void addGlobalFont(const char*filename)
     memset(f, 0, sizeof(fontfile_t));
     f->filename = filename;
     int len = strlen(filename);
-    char*r1 = strrchr(filename, '/');
-    char*r2 = strrchr(filename, '\\');
+    char*r1 = strrchr((char*)filename, '/');
+    char*r2 = strrchr((char*)filename, '\\');
     if(r2>r1)
         r1 = r2;
     if(r1) {
@@ -2623,11 +2661,7 @@ void GFXOutputDev::endTransparencyGroup(GfxState *state)
     
     this->device = states[statepos].olddevice;
     if(!this->device) {
-       msg("<fatal> Bad state nesting in transparency group");
-       msg("<fatal> Notice: this is a known problem, which will be fixed in 0.9.1");
-       msg("<fatal> In the meantime, please convert the file with -s poly2bitmap");
-       restoreState(state);
-       this->device = states[statepos].olddevice;
+       msg("<error> Invalid state nesting");
     }
     states[statepos].olddevice = 0;