added a workaround for dashing of scaled paths
[swftools.git] / lib / pdf / GFXOutputDev.cc
index 8ee24b4..0fb2591 100644 (file)
@@ -80,6 +80,8 @@
 
 #include <math.h>
 
+#define SQRT2 1.41421356237309504880
+
 typedef struct _fontfile
 {
     const char*filename;
@@ -1026,8 +1028,13 @@ void GFXOutputDev::endPage()
        device->endclip(device);
        outer_clip_box = 0;
     }
+    this->dashPattern = 0;
+    /* notice: we're not fully done yet with this page- there might still be 
+       a few calls to drawLink() yet to come */
 }
 
+static inline double sqr(double x) {return x*x;}
+
 #define STROKE_FILL 1
 #define STROKE_CLIP 2
 void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags)
@@ -1048,7 +1055,7 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags)
     col.g = colToByte(rgb.g);
     col.b = colToByte(rgb.b);
     col.a = (unsigned char)(opaq*255);
-   
+
     gfx_capType capType = gfx_capRound;
     if(lineCap == 0) capType = gfx_capButt;
     else if(lineCap == 1) capType = gfx_capRound;
@@ -1059,28 +1066,37 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags)
     else if(lineJoin == 1) joinType = gfx_joinRound;
     else if(lineJoin == 2) joinType = gfx_joinBevel;
 
-    int dashnum = 0;
-    double dashphase = 0;
-    double * ldash = 0;
-    state->getLineDash(&ldash, &dashnum, &dashphase);
-
     gfxline_t*line2 = 0;
 
-    if(dashnum && ldash) {
-       float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
+    if(this->dashLength && this->dashPattern) {
+       float * dash = (float*)malloc(sizeof(float)*(this->dashLength+1));
        int t;
-       msg("<trace> %d dashes", dashnum);
-       msg("<trace> |  phase: %f", dashphase);
-       for(t=0;t<dashnum;t++) {
-           dash[t] = (float)ldash[t];
-           msg("<trace> |  d%-3d: %f", t, ldash[t]);
+
+        /* try to find out how much the transformation matrix would
+           stretch the dashes, and factor that into the dash lengths.
+           This is not the entirely correct approach- it would be 
+           better to first convert the path to an unscaled version,
+           then apply dashing, and then transform the path using
+           the current transformation matrix. However there are few
+           PDFs which actually stretch a dashed path in a non-orthonormal
+           way */
+        double tx1, ty1, tx2, ty2;
+       this->transformXY(state, 0, 0, &tx1, &ty1);
+       this->transformXY(state, 1, 1, &tx2, &ty2);
+        double f = sqrt(sqr(tx2-tx1)+sqr(ty2-ty1)) / SQRT2;
+
+       msg("<trace> %d dashes", this->dashLength);
+       msg("<trace> |  phase: %f", this->dashStart);
+       for(t=0;t<this->dashLength;t++) {
+           dash[t] = (float)this->dashPattern[t] * f;
+           msg("<trace> |  d%-3d: %f", t, this->dashPattern[t]);
        }
-       dash[dashnum] = -1;
+       dash[this->dashLength] = -1;
        if(getLogLevel() >= LOGLEVEL_TRACE) {
            dump_outline(line);
        }
 
-       line2 = gfxtool_dash_line(line, dash, (float)dashphase);
+       line2 = gfxtool_dash_line(line, dash, (float)(this->dashStart*f));
        line = line2;
        free(dash);
        msg("<trace> After dashing:");
@@ -1091,7 +1107,7 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags)
                width,
                lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
                lineCap==0?"butt": (lineJoin==1?"round":"square"),
-               dashnum,
+               this->dashLength,
                col.r,col.g,col.b,col.a
                );
         dump_outline(line);
@@ -1527,6 +1543,10 @@ void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl
     states[statepos].clipbbox.ymin = x1;
     states[statepos].clipbbox.xmax = x2;
     states[statepos].clipbbox.ymax = y2;
+    
+    this->dashPattern = 0;
+    this->dashLength = 0;
+    this->dashStart = 0;
 }
 
 
@@ -1753,11 +1773,19 @@ void GFXOutputDev::restoreState(GfxState *state) {
   }
   statepos--;
 }
+void GFXOutputDev::updateLineDash(GfxState *state) 
+{
+    state->getLineDash(&this->dashPattern, &this->dashLength, &this->dashStart);
+    msg("<debug> updateLineDash, %d dashes", this->dashLength);
+    if(!this->dashLength) {
+        this->dashPattern = 0;
+    }
+}
 
 void GFXOutputDev::updateLineWidth(GfxState *state)
 {
     double width = state->getTransformedLineWidth();
-    //swfoutput_setlinewidth(&device, width);
 }
 
 void GFXOutputDev::updateLineCap(GfxState *state)
@@ -2175,7 +2203,7 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
 
          width = realwidth;
          height = realheight;
-         free(pic);
+         delete[] pic;
          pic = pic2;
          
          /* make a black/white palette */
@@ -2197,8 +2225,8 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
        }
       }
       drawimagelossless(device, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
-      free(pic2);
-      free(pic);
+      delete[] pic2;
+      delete[] pic;
       delete imgStr;
       if(maskbitmap) free(maskbitmap);
       return;