win32 compile fixes
[swftools.git] / lib / devices / artsutils.c
index ce005f5..6b284e6 100644 (file)
@@ -1,7 +1,13 @@
+#include "../../config.h"
+#include "../rfxswf.h"
+#include "../gfxdevice.h"
+#include "../gfxtools.h"
+#include "../art/libart.h"
+#include "artsutils.h"
 #include <assert.h>
 #include <math.h>
 
-static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line)
+ArtVpath* gfxline_to_ArtVpath(gfxline_t*line)
 {
     ArtVpath *vec = NULL;
     int pos=0,len=0;
@@ -49,9 +55,9 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line)
        } else if(l2->type == gfx_splineTo) {
            int i;
             int parts = (int)(sqrt(fabs(l2->x-2*l2->sx+x) + fabs(l2->y-2*l2->sy+y))*subfraction);
-            if(!parts) parts = 1;
+           double stepsize = parts?1.0/parts:0;
            for(i=0;i<=parts;i++) {
-               double t = (double)i/(double)parts;
+               double t = (double)i*stepsize;
                vec[pos].code = ART_LINETO;
                vec[pos].x = l2->x*t*t + 2*l2->sx*t*(1-t) + x*(1-t)*(1-t);
                vec[pos].y = l2->y*t*t + 2*l2->sy*t*(1-t) + y*(1-t)*(1-t);
@@ -64,30 +70,39 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line)
        l2 = l2->next;
     }
     vec[pos].code = ART_END;
+    
+    /* fix "dotted" lines */
+    int t;
+    char linepending=0;
+    for(t=0;vec[t].code!=ART_END;t++) {
+       if(t>0 && vec[t-1].code==ART_MOVETO && vec[t].code==ART_LINETO 
+               && vec[t+1].code!=ART_LINETO
+           && vec[t-1].x == vec[t].x
+           && vec[t-1].y == vec[t].y) {
+           vec[t].x += 0.01;
+       }
+       if(vec[t].code==ART_MOVETO)
+           linepending=0;
+       x = vec[t].x;
+       y = vec[t].y;
+    }
 
     // Spot adjacent identical points
+    t = 1;
+    while(t < pos)
     {
-       int j = 1;
-       while(j < pos)
-       {
-           double dx = vec[j].x - vec[j-1].x;
-           double dy = vec[j].y - vec[j-1].y;
-           double d = dx*dx + dy*dy;
-           if ((vec[j-1].x == vec[j].x)
-               && (vec[j-1].y == vec[j].y))
-           {
-               // adjacent identical points; remove one
-               memcpy(&(vec[j]), &(vec[j + 1]), sizeof(vec[j]) * (pos - j));
-               --pos;
-           }
-           else
-           {
-               // different
-               ++j;
-           }
+       if ((vec[t-1].x == vec[t].x) && (vec[t-1].y == vec[t].y)) {
+           // adjacent identical points; remove one
+           memcpy(&(vec[t]), &(vec[t + 1]), sizeof(vec[t]) * (pos - t));
+           pos--;
+       } else {
+           t++;
        }
     }
 
+    /* adjacency remover disabled for now, pending code inspection */
+    return vec;
+
     // Check for further non-adjacent identical points. We don't want any
     // points other than the first and last points to exactly match.
     //
@@ -134,7 +149,7 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line)
     return vec;
 }
 
-static void show_path(ArtSVP*path)
+void show_path(ArtSVP*path)
 {
     int t;
     printf("Segments: %d\n", path->n_segs);
@@ -152,7 +167,7 @@ static void show_path(ArtSVP*path)
     printf("\n");
 }
 
-static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)
+ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)
 {
     ArtVpath* vec = gfxline_to_ArtVpath(line);
     if(perturb) {
@@ -162,9 +177,71 @@ static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)
     }
     ArtSVP *svp = art_svp_from_vpath(vec);
     free(vec);
+
+    // We need to make sure that the SVP we now have bounds an area (i.e. the
+    // source line wound anticlockwise) rather than excludes an area (i.e. the
+    // line wound clockwise). It seems that PDF (or xpdf) is less strict about
+    // this for bitmaps than it is for fill areas.
+    //
+    // To check this, we'll sum the cross products of all pairs of adjacent
+    // lines. If the result is positive, the direction is correct; if not, we
+    // need to reverse the sense of the SVP generated. The easiest way to do
+    // this is to flip the up/down flags of all the segments.
+    //
+    // This is approximate; since the gfxline_t structure can contain any
+    // combination of moveTo, lineTo and splineTo in any order, not all pairs
+    // of lines in the shape that share a point need be described next to each
+    // other in the sequence. For ease, we'll consider only pairs of lines
+    // stored as lineTos and splineTos without intervening moveTos.
+    //
+    // TODO is this a valid algorithm? My vector maths is rusty.
+    //
+    // It may be more correct to instead reverse the line before we feed it
+    // into gfxfilltoSVP. However, this seems equivalent and is easier to
+    // implement!
+    double total_cross_product = 0.0;
+    gfxline_t* cursor = line;
+    if (cursor != NULL)
+    {
+       double x_last = cursor->x;
+       double y_last = cursor->y;
+       cursor = cursor->next;
+
+       while((cursor != NULL) && (cursor->next != NULL))
+       {
+           if (((cursor->type == gfx_lineTo) || (cursor->type == gfx_splineTo))
+               && ((cursor->next->type == gfx_lineTo) || (cursor->next->type == gfx_splineTo)))
+           {
+               // Process these lines
+               //
+               // In this space (x right, y down) the cross-product is
+               // (x1 * y0) - (x0 * y1)
+               double x0 = cursor->x - x_last;
+               double y0 = cursor->y - y_last;
+               double x1 = cursor->next->x - cursor->x;
+               double y1 = cursor->next->y - cursor->y;
+               total_cross_product += (x1 * y0) - (x0 * y1);
+           }
+
+           x_last = cursor->x;
+           y_last = cursor->y;
+           cursor = cursor->next;
+       }
+    }
+    if (total_cross_product < 0.0)
+    {
+       int i = 0;
+       for(; i < svp->n_segs; ++i)
+       {
+           if (svp->segs[i].dir != 0)
+               svp->segs[i].dir = 0;
+           else
+               svp->segs[i].dir = 1;
+       }
+    }
     return svp;
 }
-static ArtSVP* boxToSVP(double x1, double y1,double x2, double y2)
+ArtSVP* boxToSVP(double x1, double y1,double x2, double y2)
 {
     ArtVpath *vec = art_new (ArtVpath, 5+1);
     vec[0].code = ART_MOVETO;
@@ -190,9 +267,10 @@ static ArtSVP* boxToSVP(double x1, double y1,double x2, double y2)
     return svp;
 }
 
-static ArtSVP* gfxstrokeToSVP(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, double miterLimit)
+ArtSVP* gfxstrokeToSVP(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, double miterLimit)
 {
     ArtVpath* vec = gfxline_to_ArtVpath(line);
+
     ArtSVP *svp = art_svp_vpath_stroke (vec,
                        (joint_style==gfx_joinMiter)?ART_PATH_STROKE_JOIN_MITER:
                        ((joint_style==gfx_joinRound)?ART_PATH_STROKE_JOIN_ROUND:
@@ -208,7 +286,7 @@ static ArtSVP* gfxstrokeToSVP(gfxline_t*line, gfxcoord_t width, gfx_capType cap_
     return svp;
 }
 
-static gfxline_t* SVPtogfxline(ArtSVP*svp)
+gfxline_t* SVPtogfxline(ArtSVP*svp)
 {
     int size = 0;
     int t;
@@ -237,4 +315,3 @@ static gfxline_t* SVPtogfxline(ArtSVP*svp)
        return 0;
     }
 }
-