applied transparency patch
[swftools.git] / lib / pdf / GFXOutputDev.cc
index d3a9e4e..8b114ce 100644 (file)
@@ -185,7 +185,6 @@ void GFXOutputDev::infofeature(const char*feature)
 
 GFXOutputState::GFXOutputState() {
     this->clipping = 0;
-    this->textRender = 0;
     this->createsoftmask = 0;
     this->transparencygroup = 0;
     this->softmask = 0;
@@ -273,6 +272,8 @@ GFXOutputDev::GFXOutputDev(parameter_t*p)
     this->pagepos = 0;
     this->config_use_fontconfig=1;
     this->config_break_on_warning=0;
+    this->config_remapunicode=0;
+    this->config_transparent=0;
     this->do_interpretType3Chars = gTrue;
 
     this->parameters = p;
@@ -286,7 +287,7 @@ GFXOutputDev::GFXOutputDev(parameter_t*p)
     }
 };
 
-void GFXOutputDev::setParameter(char*key, char*value)
+void GFXOutputDev::setParameter(const char*key, const char*value)
 {
     if(!strcmp(key,"rawtext")) {
         this->do_interpretType3Chars = atoi(value)^1;
@@ -294,6 +295,10 @@ void GFXOutputDev::setParameter(char*key, char*value)
        this->config_break_on_warning = atoi(value);
     } else if(!strcmp(key,"fontconfig")) {
         this->config_use_fontconfig = atoi(value);
+    } else if(!strcmp(key,"remapunicode")) {
+        this->config_remapunicode = atoi(value);
+    } else if(!strcmp(p->name,"transparent")) {
+        this->config_transparent = atoi(p->value);
     } else {
         msg("<warning> Ignored parameter: %s=%s", key, value);
     }
@@ -664,6 +669,24 @@ GBool GFXOutputDev::useShadedFills()
     infofeature("shaded fills");
     return gFalse;
 }
+  
+GBool GFXOutputDev::useDrawForm() 
+{ 
+    infofeature("forms");
+    return gFalse; 
+}
+void GFXOutputDev::drawForm(Ref id) 
+{
+    msg("<error> drawForm not implemented");
+}
+GBool GFXOutputDev::needNonText() 
+{ 
+    return gTrue; 
+}
+void GFXOutputDev::endPage() 
+{
+    msg("<verbose> endPage");
+}
 
 #define STROKE_FILL 1
 #define STROKE_CLIP 2
@@ -1003,8 +1026,20 @@ void GFXOutputDev::beginString(GfxState *state, GString *s)
     this->current_font_matrix.ty = 0;
 
     gfxmatrix_t m = this->current_font_matrix;
+}
+
+static gfxline_t* mkEmptyGfxShape(double x, double y)
+{
+    gfxline_t*line = (gfxline_t*)malloc(sizeof(gfxline_t));
+    line->x = x;line->y = y;line->type = gfx_moveTo;line->next = 0;
+    return line;
+}
 
-    states[statepos].textRender = render;
+static char isValidUnicode(int c)
+{
+    if(c>=32 && c<0x2fffe)
+       return 1;
+    return 0;
 }
 
 void GFXOutputDev::drawChar(GfxState *state, double x, double y,
@@ -1019,9 +1054,6 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y,
        return;
     }
 
-    if(states[statepos].textRender != render)
-       msg("<error> Internal error: drawChar.render!=beginString.render");
-
     gfxcolor_t col = getFillColor(state);
 
     Gushort *CIDToGIDMap = 0;
@@ -1088,6 +1120,10 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y,
                FIXNULL(name),c, u, FIXNULL((char*)current_gfxfont->id), current_gfxfont->num_glyphs);
        return;
     }
+    //useless- the font has already been passed to the output device
+    //if(!isValidUnicode(current_gfxfont->glyphs[charid].unicode) && isValidUnicode(u)) {
+    //    current_gfxfont->glyphs[charid].
+    //}
 
     gfxmatrix_t m = this->current_font_matrix;
     state->transform(x, y, &m.tx, &m.ty);
@@ -1106,7 +1142,10 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y,
             l = l->next;
         }
         if(!ok) {
-            msg("<warning> Drawing empty character charid=%d", charid);
+           static int lastemptychar = 0;
+           if(charid != lastemptychar)
+               msg("<warning> Drawing empty character charid=%d u=%d", charid, u);
+           lastemptychar = charid;
         }
     }
 
@@ -1128,6 +1167,9 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y,
        if(render&RENDER_CLIP) {
            gfxline_t*add = gfxline_clone(tglyph);
            current_text_clip = gfxline_append(current_text_clip, add);
+           if(!current_text_clip) {
+               current_text_clip = mkEmptyGfxShape(m.tx, m.ty);
+           }
        }
        gfxline_free(tglyph);
     }
@@ -1137,8 +1179,6 @@ void GFXOutputDev::endString(GfxState *state)
 { 
     int render = state->getRender();
     msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
-    if(states[statepos].textRender != render)
-       msg("<error> Internal error: drawChar.render!=beginString.render");
     
     if(current_text_stroke) {
        /* fillstroke and stroke text rendering objects we can process right
@@ -1168,8 +1208,6 @@ void GFXOutputDev::endTextObject(GfxState *state)
 {
     int render = state->getRender();
     msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
-    if(states[statepos].textRender != render)
-       msg("<error> Internal error: drawChar.render!=beginString.render");
     
     if(current_text_clip) {
        device->setparameter(device, "mark","TXT");
@@ -1285,7 +1323,8 @@ 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;
-    device->fill(device, clippath, &white);
+    if(!config_transparent)
+        device->fill(device, clippath, &white);
 }
 
 
@@ -1483,7 +1522,6 @@ void GFXOutputDev::saveState(GfxState *state) {
       return;
     }
     statepos ++;
-    states[statepos].textRender = states[statepos-1].textRender;
     states[statepos].createsoftmask = states[statepos-1].createsoftmask;
     states[statepos].transparencygroup = states[statepos-1].transparencygroup;
     states[statepos].clipping = 0;
@@ -1496,7 +1534,8 @@ void GFXOutputDev::restoreState(GfxState *state) {
       msg("<error> Invalid restoreState");
       return;
   }
-  msg("<trace> restoreState");
+  msg("<trace> restoreState%s%s", states[statepos].softmask?" (end softmask)":"",
+                                 states[statepos].clipping?" (end clipping)":"");
   if(states[statepos].softmask) {
       clearSoftMask(state);
   }
@@ -1901,7 +1940,7 @@ void GFXOutputDev::setXRef(PDFDoc*doc, XRef *xref)
     this->xref = xref;
 }
 
-int GFXOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
+int GFXOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize, CharCodeToUnicode*ctu)
 {
     gfxfont_t*font = 0;
     fontlist_t*last=0,*l = this->fontlist;
@@ -1929,13 +1968,23 @@ int GFXOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
     double quality = (1024 * 0.05) / maxSize;
    
     msg("<verbose> Loading %s...", filename);
-    font = gfxfont_load(id, filename, quality);
+    font = gfxfont_load(id, filename, 0, quality);
     if(!font) {
        msg("<verbose> Couldn't load Font %s (%s)", filename, id);
        return 0;
     }
     msg("<verbose> Font %s (%s) loaded successfully", filename, id);
 
+    if(this->config_remapunicode && ctu) {
+       int c;
+       for(c=0;c<font->num_glyphs;c++) {
+           Unicode u[8];
+           int uLen = ctu->mapToUnicode(c, u, 8);
+           if(uLen && !isValidUnicode(font->glyphs[c].unicode) && isValidUnicode(u[0]))
+               font->glyphs[c].unicode = u[0];
+       }
+    }
+
     l = new fontlist_t;
     l->font = font;
     l->filename = strdup(filename);
@@ -1981,7 +2030,7 @@ void GFXOutputDev::updateFont(GfxState *state)
 
     /* second, see if this is a font which was used before-
        if so, we are done */
-    if(setGfxFont(fontid, fontname, 0, 0)) {
+    if(setGfxFont(fontid, fontname, 0, 0, gfxFont->getCTU())) {
        free(fontid);
        free(fontname);
        return;
@@ -2054,8 +2103,8 @@ void GFXOutputDev::updateFont(GfxState *state)
 
     //swfoutput_setfont(&device, fontid, fileName);
     
-    if(!setGfxFont(fontid, fontname, 0, 0)) {
-       setGfxFont(fontid, fontname, fileName, maxSize);
+    if(!setGfxFont(fontid, fontname, 0, 0, gfxFont->getCTU())) {
+       setGfxFont(fontid, fontname, fileName, maxSize, gfxFont->getCTU());
     }
    
     if(fileName && del)
@@ -2828,6 +2877,13 @@ static inline Guchar div255(int x) {
   return (Guchar)((x + (x >> 8) + 0x80) >> 8);
 }
 
+static unsigned char clampU8(unsigned char c, unsigned char min, unsigned char max)
+{
+    if(c < min) c = min;
+    if(c > max) c = max;
+    return c;
+}
+
 void GFXOutputDev::clearSoftMask(GfxState *state)
 {
     if(!states[statepos].softmask)
@@ -2903,11 +2959,13 @@ void GFXOutputDev::clearSoftMask(GfxState *state)
                alpha = (77*l1->r + 151*l1->g + 28*l1->b) >> 8;
            }
 
-           /* premultiply alpha */
            l2->a = div255(alpha*l2->a);
-           l2->r = div255(alpha*l2->r);
-           l2->g = div255(alpha*l2->g);
-           l2->b = div255(alpha*l2->b);
+
+           /* DON'T premultiply alpha- this is done by fillbitmap,
+              depending on the output device */
+           //l2->r = div255(alpha*l2->r);
+           //l2->g = div255(alpha*l2->g);
+           //l2->b = div255(alpha*l2->b);
 
            l1++;
            l2++;