X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fdevices%2Fartsutils.c;h=6b284e649881d3a8b9ef86a92895a03ba5616a9c;hb=0784a8a882e7b98299fb6a90f0f9a7ebb322562b;hp=ce005f507fbc5b4edf8fd7d264967a34dad16c7f;hpb=70c85e8a814e75b29883fc347a65f83af370249b;p=swftools.git diff --git a/lib/devices/artsutils.c b/lib/devices/artsutils.c index ce005f5..6b284e6 100644 --- a/lib/devices/artsutils.c +++ b/lib/devices/artsutils.c @@ -1,7 +1,13 @@ +#include "../../config.h" +#include "../rfxswf.h" +#include "../gfxdevice.h" +#include "../gfxtools.h" +#include "../art/libart.h" +#include "artsutils.h" #include #include -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; } } -