gcc on Mac OS X claims -fno-rtti shouldn't be used when compiling C
[swftools.git] / pdf2swf / SWFOutputDev.cc
index 52f00d0..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
@@ -64,6 +64,9 @@
 //swftools header files
 #include "swfoutput.h"
 #include "../lib/log.h"
+#include "../lib/gfxdevice.h"
+#include "../lib/gfxtools.h"
+#include "../lib/gfxfont.h"
 
 #include <math.h>
 
@@ -88,6 +91,7 @@ static int pagepos = 0;
 /* config */
 static double caplinewidth = 3.0;
 static int zoom = 72; /* xpdf: 86 */
+static int forceType0Fonts = 1;
 
 static void printInfoString(Dict *infoDict, char *key, char *fmt);
 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
@@ -111,6 +115,24 @@ struct mapping {
 {"Symbol",                "s050000l"},
 {"ZapfDingbats",          "d050000l"}};
 
+class SWFOutputState {
+    public:
+    int clipping;
+    int textRender;
+    SWFOutputState() {
+       this->clipping = 0;
+       this->textRender = 0;
+    }
+};
+
+typedef struct _fontlist
+{
+    char*id;
+    char*filename;
+    gfxfont_t*font;
+    _fontlist*next;
+} fontlist_t;
+
 class SWFOutputDev:  public OutputDev {
   int outputstarted;
   struct swfoutput output;
@@ -190,6 +212,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,
@@ -203,16 +226,20 @@ 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 clipping[64];
-  int clippos;
+                                  GBool inlineImg, int mask, int *maskColors);
+  int SWFOutputDev::setGfxFont(char*id, char*filename);
+
+  SWFOutputState states[64];
+  int statepos;
 
   int currentpage;
 
@@ -233,13 +260,6 @@ public:
 
   GfxState *laststate;
 
-  int pic_xids[1024];
-  int pic_yids[1024];
-  int pic_ids[1024];
-  int pic_width[1024];
-  int pic_height[1024];
-  int picpos;
-  int pic_id;
   char type3Warning;
 
   char* substitutetarget[256];
@@ -248,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);
@@ -294,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++;
   }
@@ -319,12 +344,9 @@ SWFOutputDev::SWFOutputDev()
     linkinfo = 0;
     pbminfo = 0;
     type3active = 0;
-    clippos = 0;
-    clipping[clippos] = 0;
+    statepos = 0;
     outputstarted = 0;
     xref = 0;
-    picpos = 0;
-    pic_id = 0;
     substitutepos = 0;
     type3Warning = 0;
     user_movex = 0;
@@ -333,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");
 };
@@ -521,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);
 
@@ -561,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)
@@ -576,111 +603,89 @@ 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");}
 //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");}
 
-static void free_outline(SWF_OUTLINE*outline)
-{
-    while(outline) {
-        SWF_OUTLINE*next = outline->link;
-        free(outline);
-        outline = next;
-    }
-}
 
-static void dump_outline(SWF_OUTLINE*outline)
+void dump_outline(gfxline_t*line)
 {
-    double x=0,y=0;
-    while(outline) {
-        double lastx=x,lasty=y;
-        x += (outline->dest.x/(float)0xffff);
-        y += (outline->dest.y/(float)0xffff);
-        if(outline->type == SWF_PATHTYPE_MOVE) {
-            msg("<trace> | moveto %f,%f", x,y);
-        } else if(outline->type == SWF_PATHTYPE_LINE) {
-            msg("<trace> | lineto: %f,%f\n",x,y);
-        } else if(outline->type == SWF_PATHTYPE_BEZIER) {
-            SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
-            float x1 = o2->C.x/(float)0xffff+lastx;
-            float y1 = o2->C.y/(float)0xffff+lasty;
-            float x2 = o2->B.x/(float)0xffff+lastx;
-            float y2 = o2->B.y/(float)0xffff+lasty;
-            msg("<trace> | spline: %f,%f -> %f,%f -> %f,%f\n",x1,y1,x2,y2,x,y);
-        } 
-        outline = outline->link;
+    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;
     }
 }
 
-SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path)
+gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
 {
     int num = path->getNumSubpaths();
     int s,t;
-    bezierpathsegment*start,*last=0;
-    bezierpathsegment*outline = start = (bezierpathsegment*)malloc(sizeof(bezierpathsegment));
     int cpos = 0;
-    double lastx=0,lasty=0;
+    double lastx=0,lasty=0,posx=0,posy=0;
+    int needsfix=0;
     if(!num) {
        msg("<warning> empty path");
-       outline->type = SWF_PATHTYPE_MOVE;
-       outline->dest.x = 0;
-       outline->dest.y = 0;
-       outline->link = 0;
-       return (SWF_OUTLINE*)outline;
+       return 0;
     }
+    gfxdrawer_t draw;
+    gfxdrawer_target_gfxline(&draw);
+
     for(t = 0; t < num; t++) {
        GfxSubpath *subpath = path->getSubpath(t);
        int subnum = subpath->getNumPoints();
+       double bx=0,by=0,cx=0,cy=0;
 
        for(s=0;s<subnum;s++) {
-          double nx,ny;
-          state->transform(subpath->getX(s),subpath->getY(s),&nx,&ny);
-          int x = (int)((nx-lastx)*0xffff);
-          int y = (int)((ny-lasty)*0xffff);
-          if(s==0) 
-          {
-               last = outline;
-               outline->type = SWF_PATHTYPE_MOVE;
-               outline->dest.x = x;
-               outline->dest.y = y;
-               outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
-               outline = (bezierpathsegment*)outline->link;
+          double x,y;
+          state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
+          if(s==0) {
+               if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
+                   draw.lineTo(&draw, lastx, lasty);
+               }
+               draw.moveTo(&draw, x,y);
+               posx = lastx = x; 
+               posy = lasty = y;
                cpos = 0;
-               lastx = nx;
-               lasty = ny;
-          }
-          else if(subpath->getCurve(s) && !cpos)
-          {
-               outline->B.x = x;
-               outline->B.y = y;
+               needsfix = 0;
+          } else if(subpath->getCurve(s) && cpos==0) {
+               bx = x;
+               by = y;
                cpos = 1;
-          } 
-          else if(subpath->getCurve(s) && cpos)
-          {
-               outline->C.x = x;
-               outline->C.y = y;
+          } else if(subpath->getCurve(s) && cpos==1) {
+               cx = x;
+               cy = y;
                cpos = 2;
-          }
-          else
-          {
-               last = outline;
-               outline->dest.x = x;
-               outline->dest.y = y;
-               outline->type = cpos?SWF_PATHTYPE_BEZIER:SWF_PATHTYPE_LINE;
-               outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
-               outline = (bezierpathsegment*)outline->link;
+          } else {
+               posx = x;
+               posy = y;
+               if(cpos==0) {
+                   draw.lineTo(&draw, x,y);
+               } else {
+                   gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
+               }
+               needsfix = 1;
                cpos = 0;
-               lastx = nx;
-               lasty = ny;
           }
        }
     }
-    if(last->link) {free(last->link);}
-    last->link = 0;
-
-    return (SWF_OUTLINE*)start;
+    /* fix non-closed lines */
+    if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
+       draw.lineTo(&draw, lastx, lasty);
+    }
+    gfxline_t*result = (gfxline_t*)draw.result(&draw);
+    return result;
 }
+
 /*----------------------------------------------------------------------------
  * Primitive Graphic routines
  *----------------------------------------------------------------------------*/
@@ -692,111 +697,146 @@ void SWFOutputDev::stroke(GfxState *state)
     int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
     double miterLimit = state->getMiterLimit();
     double width = state->getTransformedLineWidth();
-    struct swfmatrix m;
+
     GfxRGB rgb;
     double opaq = state->getStrokeOpacity();
-    state->getStrokeRGB(&rgb);
-
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m12 = 0; m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
-    
-    if(getLogLevel() >= LOGLEVEL_TRACE)  {
-        msg("<trace> stroke\n");
-        dump_outline(outline);
-    }
-
-    lineJoin = 1; // other line joins are not yet supported by the swf encoder
-                  // TODO: support bevel joints
+    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;
+    else if(lineCap == 2) capType = gfx_capSquare;
 
-    if(((lineCap==1) && (lineJoin==1)) || width<=caplinewidth) {
-       /* FIXME- if the path is smaller than 2 segments, we could ignore
-          lineJoin */
-       swfoutput_setdrawmode(&output, DRAWMODE_STROKE);
-       swfoutput_drawpath(&output, outline, &m);
-    } else {
-       swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
-                                       (char)(rgb.b*255), (char)(opaq*255));
+    gfx_joinType joinType = gfx_joinRound;
+    if(lineJoin == 0) joinType = gfx_joinMiter;
+    else if(lineJoin == 1) joinType = gfx_joinRound;
+    else if(lineJoin == 2) joinType = gfx_joinBevel;
 
-       //swfoutput_setlinewidth(&output, 1.0); //only for debugging
-       //swfoutput_setstrokecolor(&output, 0, 255, 0, 255); //likewise, see below
-       //swfoutput_setfillcolor(&output, 255, 0, 0, 255); //likewise, see below
+    gfxline_t*line= gfxPath_to_gfxline(state, path, 0);
+    
+    int dashnum = 0;
+    double dashphase = 0;
+    double * ldash = 0;
+    state->getLineDash(&ldash, &dashnum, &dashphase);
+
+    if(dashnum && ldash) {
+       float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
+       int t;
+       double cut = 0;
+       int fixzero = 0;
+       msg("<trace> %d dashes", dashnum);
+       msg("<trace> |  phase: %f", dashphase);
+       for(t=0;t<dashnum;t++) {
+           dash[t] = ldash[t];
+           msg("<trace> |  d%-3d: %f", t, ldash[t]);
+       }
+       dash[dashnum] = -1;
+       if(getLogLevel() >= LOGLEVEL_TRACE) {
+           dump_outline(line);
+       }
 
-       swfoutput_drawpath2poly(&output, outline, &m, lineJoin, lineCap, width, miterLimit);
-       updateLineWidth(state);  //reset
-       updateStrokeColor(state); //reset
-       updateFillColor(state);  //reset
+       gfxline_t*line2 = gfxtool_dash_line(line, dash, dashphase);
+       gfxline_free(line);
+       line = line2;
+       msg("<trace> After dashing:");
+    }
+    
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
+       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,
+               col.r,col.g,col.b,col.a,
+               gray
+               );
+        dump_outline(line);
     }
-    free_outline(outline);
+   
+    swfoutput_drawgfxline(&output, line, width, &col, capType, joinType, miterLimit);
+    gfxline_free(line);
 }
 void SWFOutputDev::fill(GfxState *state) 
 {
     GfxPath * path = state->getPath();
-    struct swfmatrix m;
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m12 = 0; m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
+    double opaq = state->getFillOpacity();
+    GfxRGB rgb;
+    state->getFillRGB(&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);
+
+    gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
 
     if(getLogLevel() >= LOGLEVEL_TRACE)  {
-        msg("<trace> fill\n");
-        dump_outline(outline);
+        msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
+        dump_outline(line);
     }
 
-    swfoutput_setdrawmode(&output, DRAWMODE_FILL);
-    swfoutput_drawpath(&output, outline, &m);
-    free_outline(outline);
+    swfoutput_fillgfxline(&output, line, &col);
+    gfxline_free(line);
 }
 void SWFOutputDev::eoFill(GfxState *state) 
 {
     GfxPath * path = state->getPath();
-    struct swfmatrix m;
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m12 = 0; m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
+    double opaq = state->getFillOpacity();
+    GfxRGB rgb;
+    state->getFillRGB(&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);
+
+    gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
 
     if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> eofill\n");
-        dump_outline(outline);
+        dump_outline(line);
     }
 
-    swfoutput_setdrawmode(&output, DRAWMODE_EOFILL);
-    swfoutput_drawpath(&output, outline, &m);
-    free_outline(outline);
+    swfoutput_fillgfxline(&output, line, &col);
+    gfxline_free(line);
 }
 void SWFOutputDev::clip(GfxState *state) 
 {
     GfxPath * path = state->getPath();
-    struct swfmatrix m;
-    m.m11 = 1; m.m22 = 1;
-    m.m12 = 0; m.m21 = 0; 
-    m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
+    gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
 
     if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> clip\n");
-        dump_outline(outline);
+        dump_outline(line);
     }
 
-    swfoutput_startclip(&output, outline, &m);
-    clipping[clippos] ++;
-    free_outline(outline);
+    swfoutput_startclip(&output, line);
+    states[statepos].clipping++;
+    gfxline_free(line);
 }
 void SWFOutputDev::eoClip(GfxState *state) 
 {
     GfxPath * path = state->getPath();
-    struct swfmatrix m;
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m12 = 0; m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
+    gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
 
     if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> eoclip\n");
-        dump_outline(outline);
+        dump_outline(line);
     }
 
-    swfoutput_startclip(&output, outline, &m);
-    clipping[clippos] ++;
-    free_outline(outline);
+    swfoutput_startclip(&output, line);
+    states[statepos].clipping++;
+    gfxline_free(line);
 }
 
 /* pass through functions for swf_output */
@@ -817,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() 
 {
@@ -837,29 +888,82 @@ GBool SWFOutputDev::useGradients()
     return gTrue;
 }
 
+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();
+    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], makeStringPrintable(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);
+    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);
+
     Gushort *CIDToGIDMap = 0;
     GfxFont*font = state->getFont();
 
     if(font->getType() == fontType3) {
        /* type 3 chars are passed as graphics */
+       msg("<debug> type3 char at %f/%f", x, y);
        return;
     }
     double x1,y1;
@@ -889,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;
@@ -899,30 +1002,55 @@ 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\"\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name));
-       swfoutput_drawchar(&output, x1, y1, name, CIDToGIDMap[c], u);
+       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);
+       c = CIDToGIDMap[c];
     } 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));
-       swfoutput_drawchar(&output, x1, y1, name, c, u);
+       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)
+{
+    if(states[statepos].textRender != state->getRender())
+       msg("<error> Internal error: drawChar.render!=beginString.render");
+    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;
@@ -1123,23 +1251,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) 
@@ -1180,7 +1310,7 @@ char* SWFOutputDev::searchFont(char*name)
 void SWFOutputDev::updateLineWidth(GfxState *state)
 {
     double width = state->getTransformedLineWidth();
-    swfoutput_setlinewidth(&output, width);
+    //swfoutput_setlinewidth(&output, width);
 }
 
 void SWFOutputDev::updateLineCap(GfxState *state)
@@ -1199,8 +1329,7 @@ void SWFOutputDev::updateFillColor(GfxState *state)
     double opaq = state->getFillOpacity();
     state->getFillRGB(&rgb);
 
-    swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
-                                   (char)(rgb.b*255), (char)(opaq*255));
+    //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
 }
 
 void SWFOutputDev::updateStrokeColor(GfxState *state) 
@@ -1208,9 +1337,7 @@ 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));
+    //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
 }
 
 void FoFiWrite(void *stream, char *data, int len)
@@ -1251,8 +1378,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");
@@ -1260,9 +1386,11 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
       }
 #ifdef XPDF_101
       Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
+      if(!cvt) return 0;
       cvt->convertToType1(f);
 #else
       FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
+      if(!cvt) return 0;
       cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
 #endif
       //cvt->convertToCIDType0("test", f);
@@ -1346,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;
@@ -1374,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;
@@ -1415,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;
@@ -1448,18 +1576,22 @@ char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
        fontname = "Times-Roman";
     }
     filename = searchFont(fontname);
+    if(!filename) {
+       msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
+       return 0;
+    }
 
     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
        msg("<fatal> Too many fonts in file.");
        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)
@@ -1497,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) 
 {
@@ -1513,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;
     }
 
@@ -1534,6 +1701,7 @@ void SWFOutputDev::updateFont(GfxState *state)
            type3Warning = gTrue;
            showFontError(gfxFont, 2);
        }
+       free(fontid);
        return;
     }
 
@@ -1547,7 +1715,7 @@ void SWFOutputDev::updateFont(GfxState *state)
     if(embedded &&
        (gfxFont->getType() == fontType1 ||
        gfxFont->getType() == fontType1C ||
-       //gfxFont->getType() == fontCIDType0C ||
+       (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
        gfxFont->getType() == fontTrueType ||
        gfxFont->getType() == fontCIDType2
        ))
@@ -1565,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;
     }
        
@@ -1578,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))
@@ -1637,7 +1811,7 @@ unsigned char* antialize(unsigned char*data, int width, int height, int newwidth
 
 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GfxImageColorMap*colorMap, GBool invert,
-                                  GBool inlineImg, int mask)
+                                  GBool inlineImg, int mask, int*maskColors)
 {
   FILE *fi;
   int c;
@@ -1688,22 +1862,21 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
   }
 
   if(mask) {
-      int yes=0,i,j;
+      int i,j;
       unsigned char buf[8];
-      int xid = 0;
-      int yid = 0;
       int x,y;
       unsigned char*pic = new unsigned char[width*height];
       RGBA pal[256];
       GfxRGB rgb;
       state->getFillRGB(&rgb);
+
       memset(pal,255,sizeof(pal));
-      pal[0].r = (int)(rgb.r*255); pal[0].g = (int)(rgb.g*255); 
-      pal[0].b = (int)(rgb.b*255); pal[0].a = 255;
-      pal[1].r = 0; pal[1].g = 0; pal[1].b = 0; pal[1].a = 0;
+      pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
+      pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
+      pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
+      pal[0].a = 255;              pal[1].a = 0;
+
       int numpalette = 2;
-      xid += pal[1].r*3 + pal[1].g*11 + pal[1].b*17;
-      yid += pal[1].r*7 + pal[1].g*5 + pal[1].b*23;
       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
       for (y = 0; y < height; ++y)
@@ -1713,173 +1886,120 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
            if(invert) 
                buf[0]=1-buf[0];
            pic[width*y+x] = buf[0];
-           xid+=x*buf[0]+1;
-           yid+=y*buf[0]*3+1;
       }
       
       /* the size of the drawn image is added to the identifier
         as the same image may require different bitmaps if displayed
         at different sizes (due to antialiasing): */
-      if(type3active) {
-         xid += realwidth;
-         yid += realheight;
-      }
       int t,found = -1;
-      for(t=0;t<picpos;t++)
-      {
-         if(pic_xids[t] == xid &&
-            pic_yids[t] == yid) {
-             /* if the image was antialiased, the size has changed: */
-             width = pic_width[t];
-             height = pic_height[t];
-             found = t;break;
+      if(type3active) {
+         unsigned char*pic2 = 0;
+         numpalette = 16;
+         
+         pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
+
+         if(!pic2) {
+           delete pic;
+           delete imgStr;
+           return;
          }
-      }
-      if(found<0) {
-         if(type3active) {
-             numpalette = 16;
-             unsigned char*pic2 = 0;
-             
-             pic2 = antialize(pic,width,height,realwidth,realheight, numpalette);
-
-             if(pic2) {
-                 width = realwidth;
-                 height = realheight;
-                 free(pic);
-                 pic = pic2;
-                 /* make a black/white palette */
-                 int t;
-                 GfxRGB rgb2;
-                 rgb2.r = 1 - rgb.r;
-                 rgb2.g = 1 - rgb.g;
-                 rgb2.b = 1 - rgb.b;
-
-                 float r = 255/(numpalette-1);
-                 for(t=0;t<numpalette;t++) {
-                     /*pal[t].r = (U8)(t*r*rgb.r+(numpalette-1-t)*r*rgb2.r);
-                     pal[t].g = (U8)(t*r*rgb.g+(numpalette-1-t)*r*rgb2.g);
-                     pal[t].b = (U8)(t*r*rgb.b+(numpalette-1-t)*r*rgb2.b);
-                     pal[t].a = 255; */
-                     pal[t].r = (U8)(255*rgb.r);
-                     pal[t].g = (U8)(255*rgb.g);
-                     pal[t].b = (U8)(255*rgb.b);
-                     pal[t].a = (U8)(t*r);
-                 }
-             }
+
+         width = realwidth;
+         height = realheight;
+         free(pic);
+         pic = pic2;
+         
+         /* make a black/white palette */
+         GfxRGB rgb2;
+         rgb2.r = 1 - rgb.r;
+         rgb2.g = 1 - rgb.g;
+         rgb2.b = 1 - rgb.b;
+         float r = 255/(numpalette-1);
+         int t;
+         for(t=0;t<numpalette;t++) {
+             pal[t].r = (U8)(255*rgb.r);
+             pal[t].g = (U8)(255*rgb.g);
+             pal[t].b = (U8)(255*rgb.b);
+             pal[t].a = (U8)(t*r);
          }
-         pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, 
-                 x1,y1,x2,y2,x3,y3,x4,y4, numpalette);
-         pic_xids[picpos] = xid;
-         pic_yids[picpos] = yid;
-         pic_width[picpos] = width;
-         pic_height[picpos] = height;
-         if(picpos<1024)
-             picpos++;
-      } else {
-         swfoutput_drawimageagain(&output, pic_ids[found], width, height,
-                 x1,y1,x2,y2,x3,y3,x4,y4);
       }
+
+      RGBA*pic2 = new RGBA[width*height];
+      for (y = 0; y < height; ++y) {
+       for (x = 0; x < width; ++x) {
+         pic2[width*y+x] = pal[pic[y*width+x]];
+       }
+      }
+      swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
+      free(pic2);
       free(pic);
       delete imgStr;
       return;
   } 
 
   int x,y;
-  
-  if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT)
-  {
+
+  if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
       RGBA*pic=new RGBA[width*height];
-      int xid = 0;
-      int yid = 0;
       for (y = 0; y < height; ++y) {
        for (x = 0; x < width; ++x) {
-         int r,g,b,a;
          imgStr->getPixel(pixBuf);
          colorMap->getRGB(pixBuf, &rgb);
-         pic[width*y+x].r = r = (U8)(rgb.r * 255 + 0.5);
-         pic[width*y+x].g = g = (U8)(rgb.g * 255 + 0.5);
-         pic[width*y+x].b = b = (U8)(rgb.b * 255 + 0.5);
-         pic[width*y+x].a = a = 255;//(U8)(rgb.a * 255 + 0.5);
-         xid += x*r+x*b*3+x*g*7+x*a*11;
-         yid += y*r*3+y*b*17+y*g*19+y*a*11;
+         pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
+         pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
+         pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
+         pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
        }
       }
-      int t,found = -1;
-      for(t=0;t<picpos;t++)
-      {
-         if(pic_xids[t] == xid &&
-            pic_yids[t] == yid) {
-             found = t;break;
-         }
-      }
-      if(found<0) {
-         if(str->getKind()==strDCT)
-             pic_ids[picpos] = swfoutput_drawimagejpeg(&output, pic, width, height, 
-                     x1,y1,x2,y2,x3,y3,x4,y4);
-         else
-             pic_ids[picpos] = swfoutput_drawimagelossless(&output, pic, width, height, 
-                     x1,y1,x2,y2,x3,y3,x4,y4);
-         pic_xids[picpos] = xid;
-         pic_yids[picpos] = yid;
-         pic_width[picpos] = width;
-         pic_height[picpos] = height;
-         if(picpos<1024)
-             picpos++;
-      } else {
-         swfoutput_drawimageagain(&output, pic_ids[found], width, height,
-                 x1,y1,x2,y2,x3,y3,x4,y4);
-      }
+      if(str->getKind()==strDCT)
+         swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
+      else
+         swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
       delete pic;
       delete imgStr;
       return;
-  }
-  else
-  {
-      U8*pic = new U8[width*height];
+  } else {
+      RGBA*pic=new RGBA[width*height];
       RGBA pal[256];
       int t;
-      int xid=0,yid=0;
-      for(t=0;t<256;t++)
-      {
-         int r,g,b,a;
+      for(t=0;t<256;t++) {
          pixBuf[0] = t;
          colorMap->getRGB(pixBuf, &rgb);
-         pal[t].r = r = (U8)(rgb.r * 255 + 0.5);
-         pal[t].g = g = (U8)(rgb.g * 255 + 0.5);
-         pal[t].b = b = (U8)(rgb.b * 255 + 0.5);
-         pal[t].a = a = 255;//(U8)(rgb.b * 255 + 0.5);
-         xid += t*r+t*b*3+t*g*7+t*a*11;
-         xid += (~t)*r+t*b*3+t*g*7+t*a*11;
+         /*if(maskColors && *maskColors==t) {
+             msg("<notice> Color %d is transparent", t);
+             if (imgData->maskColors) {
+               *alpha = 0;
+               for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
+                 if (pix[i] < imgData->maskColors[2*i] ||
+                     pix[i] > imgData->maskColors[2*i+1]) {
+                   *alpha = 1;
+                   break;
+                 }
+               }
+             } else {
+               *alpha = 1;
+             }
+             if(!*alpha) {
+                   pal[t].r = 0;
+                   pal[t].g = 0;
+                   pal[t].b = 0;
+                   pal[t].a = 0;
+             }
+         } else*/ {
+             pal[t].r = (U8)(rgb.r * 255 + 0.5);
+             pal[t].g = (U8)(rgb.g * 255 + 0.5);
+             pal[t].b = (U8)(rgb.b * 255 + 0.5);
+             pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
+         }
       }
       for (y = 0; y < height; ++y) {
        for (x = 0; x < width; ++x) {
          imgStr->getPixel(pixBuf);
-         pic[width*y+x] = pixBuf[0];
-         xid += x*pixBuf[0]*7;
-         yid += y*pixBuf[0]*3;
+         pic[width*y+x] = pal[pixBuf[0]];
        }
       }
-      int found = -1;
-      for(t=0;t<picpos;t++)
-      {
-         if(pic_xids[t] == xid &&
-            pic_yids[t] == yid) {
-             found = t;break;
-         }
-      }
-      if(found<0) {
-         pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, 
-                 x1,y1,x2,y2,x3,y3,x4,y4,256);
-         pic_xids[picpos] = xid;
-         pic_yids[picpos] = yid;
-         pic_width[picpos] = width;
-         pic_height[picpos] = height;
-         if(picpos<1024)
-             picpos++;
-      } else {
-         swfoutput_drawimageagain(&output, pic_ids[found], width, height,
-                 x1,y1,x2,y2,x3,y3,x4,y4);
-      }
+      swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
+
       delete pic;
       delete imgStr;
       return;
@@ -1890,14 +2010,19 @@ 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);
+  drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
 }
 
 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",
@@ -1905,7 +2030,7 @@ void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   if(colorMap)
       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
              colorMap->getBits(),colorMap->getColorSpace()->getMode());
-  drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0);
+  drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
 }
 
 SWFOutputDev*output = 0; 
@@ -1952,13 +2077,33 @@ static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
   obj.free();
 }
 
+int jpeg_dpi = 0;
+int ppm_dpi = 0;
+
 void pdfswf_setparameter(char*name, char*value)
 {
     msg("<verbose> setting parameter %s to \"%s\"", name, value);
     if(!strcmp(name, "caplinewidth")) {
        caplinewidth = atof(value);
     } else if(!strcmp(name, "zoom")) {
+       char buf[80];
        zoom = atoi(value);
+       sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
+       swfoutput_setparameter("jpegsubpixels", buf);
+       sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
+       swfoutput_setparameter("ppmsubpixels", buf);
+    } else if(!strcmp(name, "jpegdpi")) {
+       char buf[80];
+       jpeg_dpi = atoi(value);
+       sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
+       swfoutput_setparameter("jpegsubpixels", buf);
+    } else if(!strcmp(name, "ppmdpi")) {
+       char buf[80];
+       ppm_dpi = atoi(value);
+       sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
+       swfoutput_setparameter("ppmsubpixels", buf);
+    } else if(!strcmp(name, "forceType0Fonts")) {
+       forceType0Fonts = atoi(value);
     } else if(!strcmp(name, "fontdir")) {
         pdfswf_addfontdir(value);
     } else if(!strcmp(name, "languagedir")) {