From: kramm <kramm>
Date: Sun, 18 Mar 2007 18:22:55 +0000 (+0000)
Subject: applied patches by Rupert Wood
X-Git-Tag: release-0-8-1~17
X-Git-Url: http://git.asbjorn.biz/?a=commitdiff_plain;h=70c85e8a814e75b29883fc347a65f83af370249b;p=swftools.git

applied patches by Rupert Wood
---

diff --git a/lib/devices/arts.c b/lib/devices/arts.c
index 68593c6..510df3e 100644
--- a/lib/devices/arts.c
+++ b/lib/devices/arts.c
@@ -145,6 +145,20 @@ void arts_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
     internal_t*i = (internal_t*)dev->internal;
     ArtSVP* svp = gfxfillToSVP(line, 1);
     
+    if (svp->n_segs > 500)
+    {
+	int lineParts = 0;
+	gfxline_t* lineCursor = line;
+	while(lineCursor != NULL)
+	{
+	    if(lineCursor->type != gfx_moveTo) ++lineParts;
+	    lineCursor = lineCursor->next;
+	}
+	fprintf(stderr, "arts_fill abandonning shape with %d segments (%d line parts)\n", svp->n_segs, lineParts);
+	art_svp_free(svp);
+	return;
+    }
+
     svp = art_svp_rewind_uncrossed(art_svp_uncross(svp),ART_WIND_RULE_ODDEVEN); /*FIXME*/
 
     if(i->clip) {
@@ -164,6 +178,69 @@ void arts_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gfxm
     dbg("arts_fillbitmap");
     internal_t*i = (internal_t*)dev->internal;
     ArtSVP* svp = gfxfillToSVP(line, 1);
+
+    // 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;
+	}
+    }
+
     if(i->clip) {
 	ArtSVP*old = svp;
 	svp = art_svp_intersect(svp, i->clip->svp);
diff --git a/lib/devices/artsutils.c b/lib/devices/artsutils.c
index 8271ffd..ce005f5 100644
--- a/lib/devices/artsutils.c
+++ b/lib/devices/artsutils.c
@@ -65,6 +65,72 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line)
     }
     vec[pos].code = ART_END;
 
+    // Spot adjacent identical points
+    {
+	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;
+	    }
+	}
+    }
+
+    // Check for further non-adjacent identical points. We don't want any
+    // points other than the first and last points to exactly match.
+    //
+    // If we do find matching points, move the second point slightly. This
+    // currently moves the duplicate 2% towards the midpoint of its neighbours
+    // (easier to calculate than 2% down the perpendicular to the line joining
+    // the neighbours) but limiting the change to 0.1 twips to avoid visual
+    // problems when the shapes are large. Note that there is no minimum
+    // change: if the neighbouring points are colinear and equally spaced,
+    // e.g. they were generated as part of a straight spline, then the
+    // duplicate point may not actually move.
+    //
+    // The scan for duplicates algorithm is quadratic in the number of points:
+    // there's probably a better method but the numbers of points is generally
+    // small so this will do for now.
+    {
+	int i = 1, j;
+	for(; i < (pos - 1); ++i)
+	{
+	    for (j = 0; j < i; ++j)
+	    {
+		if ((vec[i].x == vec[j].x)
+		    && (vec[i].y == vec[j].y))
+		{
+		    // points match; shuffle point
+		    double dx = (vec[i-1].x + vec[i+1].x - (vec[i].x * 2.0)) / 100.0;
+		    double dy = (vec[i-1].y + vec[i+1].y - (vec[i].y * 2.0)) / 100.0;
+		    double dxxyy = (dx*dx) + (dy*dy);
+		    if (dxxyy > 0.01)
+		    {
+			// This is more than 0.1 twip's distance; scale down
+			double dscale = sqrt(dxxyy) * 10.0;
+			dx /= dscale;
+			dy /= dscale;
+		    };
+		    vec[i].x += dx;
+		    vec[i].y += dy;
+		    break;
+		}
+	    }
+	}
+    }
+
     return vec;
 }