int flashversion=5;
int splinemaxerror=1;
int fontsplinemaxerror=1;
+int filloverlap=0;
+float minlinewidth=0.1;
static char storefont = 0;
static int flag_protected = 0;
static int currentswfid = 0;
static int depth = 1;
static int startdepth = 1;
+static int linewidth = 0;
static SHAPE* shape;
static int shapeid = -1;
char fillstylechanged = 0;
+int bboxrectpos = -1;
+SRECT bboxrect;
+
static void startshape(struct swfoutput* obj);
static void starttext(struct swfoutput* obj);
-static void endshape();
+static void endshape(int clip);
static void endtext(struct swfoutput* obj);
// matrix multiplication. changes p0
}
return 0;
}
+static int moveto(TAG*tag, float x, float y)
+{
+ plotxy p;
+ p.x = x;
+ p.y = y;
+ return moveto(tag, p);
+}
+static void addPointToBBox(int px, int py)
+{
+ SPOINT p;
+ p.x = px;
+ p.y = py;
+ if(fill) {
+ swf_ExpandRect(&bboxrect, p);
+ } else {
+ swf_ExpandRect3(&bboxrect, p, linewidth*3/2);
+ }
+}
// write a line-to command into the swf
static void lineto(TAG*tag, plotxy p0)
are plots */
swf_ShapeSetLine (tag, shape, rx,ry);
- //swf_ExpandRect3(boundingBox, px, py, linewidth);
- //swf_ExpandRect3(boundingBox, swflastx, swflasty, linewidth);
+ addPointToBBox(swflastx,swflasty);
+ addPointToBBox(px,py);
shapeisempty = 0;
swflastx+=rx;
swflasty+=ry;
}
+static void lineto(TAG*tag, float x, float y)
+{
+ plotxy p;
+ p.x = x;
+ p.y = y;
+ lineto(tag, p);
+}
+
// write a spline-to command into the swf
static void splineto(TAG*tag, plotxy control,plotxy end)
{
+ int lastlastx = swflastx;
+ int lastlasty = swflasty;
+
int cx = ((int)(control.x*20)-swflastx);
int cy = ((int)(control.y*20)-swflasty);
swflastx += cx;
int ey = ((int)(end.y*20)-swflasty);
swflastx += ex;
swflasty += ey;
- if(cx || cy || ex || ey)
+
+ if(cx || cy || ex || ey) {
swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
+ addPointToBBox(lastlastx ,lastlasty );
+ addPointToBBox(lastlastx+cx,lastlasty+cy);
+ addPointToBBox(lastlastx+cx+ex,lastlasty+cy+ey);
+ }
shapeisempty = 0;
}
y += (outline->dest.y/(float)0xffff);
if(outline->type == SWF_PATHTYPE_MOVE)
{
- if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
+ //if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
+ if(filloverlap && !init && fill && output->drawmode != DRAWMODE_EOFILL) {
/* drawmode=FILL (not EOFILL) means that
seperate shapes do not cancel each other out.
On SWF side, we need to start a new shape for each
closed polygon, because SWF only knows EOFILL.
*/
- endshape();
+ endshape(0);
startshape(output);
startFill();
}
int back = 0;
if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
- endshape();
+ endshape(0);
startshape(output);
SWF_OUTLINE *last, *tmp=outline;
plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
for(nr=0;nr<2;nr++) {
int dir=0;
struct plotxy q0,q1,q2,q3,q4,q5;
+
startFill();
if(line_cap == LINE_CAP_BUTT) {
if(dir) {
if(line_cap == LINE_CAP_BUTT) {
lineto(tag, q0);
- swf_ShapeSetEnd(tag);
- tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
- swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
- depth++;
- shapeid = -1;
+ endshape(depth+2-nr);
startshape(output);
}
p0 = m0;
drawShortPath(output,x,y,m,outline);
if(line_cap == LINE_CAP_BUTT) {
- endshape();
+ endshape(0);
startshape(output);
}
}
need to draw) are very likely to overlap. To avoid that
they cancel each other out at the end points, start a new
shape for the second one */
- endshape();startshape(output);
+ endshape(0);startshape(output);
startFill();
}
static const int CHARDATAMAX = 8192;
struct chardata {
int charid;
- int fontid;
+ int fontid; /* TODO: use a SWFFONT instead */
int x;
int y;
int size;
static SRECT getcharacterbbox(SWFFONT*font)
{
SRECT r;
+ char debug = 0;
memset(&r, 0, sizeof(r));
int t;
- printf("\n");
+ if(debug) printf("\n");
for(t=0;t<chardatapos;t++)
{
+ if(chardata[t].fontid != font->id) {
+ msg("<error> Internal error: fontid %d != fontid %d", chardata[t].fontid, font->id);
+ exit(1);
+ }
SRECT b = font->layout->bounds[chardata[t].charid];
b.xmin *= chardata[t].size;
b.ymin *= chardata[t].size;
b.ymin += chardata[t].y;
b.xmax += chardata[t].x;
b.ymax += chardata[t].y;
- printf("(%d,%d,%d,%d) -> (%d,%d,%d,%d)\n",
- font->layout->bounds[chardata[t].charid].xmin,
- font->layout->bounds[chardata[t].charid].ymin,
- font->layout->bounds[chardata[t].charid].xmax,
- font->layout->bounds[chardata[t].charid].ymax,
- b.xmin,
- b.ymin,
- b.xmax,
- b.ymax);
+
+ /* until we solve the INTERNAL_SCALING problem (see below)
+ make sure the bounding box is big enough */
+ b.xmin -= 20;
+ b.ymin -= 20;
+ b.xmax += 20;
+ b.ymax += 20;
+
+ if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
+ font->layout->bounds[chardata[t].charid].xmin/20.0,
+ font->layout->bounds[chardata[t].charid].ymin/20.0,
+ font->layout->bounds[chardata[t].charid].xmax/20.0,
+ font->layout->bounds[chardata[t].charid].ymax/20.0,
+ b.xmin/20.0,
+ b.ymin/20.0,
+ b.xmax/20.0,
+ b.ymax/20.0,
+ chardata[t].fontid,
+ font->id,
+ chardata[t].charid
+ );
swf_ExpandRect2(&r, &b);
}
- printf("-----> (%d,%d,%d,%d)\n",
- r.xmin,
- r.ymin,
- r.xmax,
- r.ymax);
+ if(debug) printf("-----> (%f,%f,%f,%f)\n",
+ r.xmin/20.0,
+ r.ymin/20.0,
+ r.xmax/20.0,
+ r.ymax/20.0);
return r;
}
fontlist_t*next;
} *fontlist = 0;
+/* todo: why don't higher values (64, 1024) work here? */
#define FONT_INTERNAL_SIZE 1
/* process a character. */
}
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid<0)
starttext(obj);
so we better start a new shape here if the polygon is filled
*/
if(shapeid>=0 && fill && !ignoredraworder) {
- endshape();
+ endshape(0);
}
if(shapeid<0)
if(textid>=0)
endtext(output);
if(shapeid>=0)
- endshape();
+ endshape(0);
assert(shapeid<0);
startshape(output);
stopFill();
return charnr;
}
- /* the following is technically wrong, and only works if the font encoding
- is US-ASCII based. It's needed for fonts which return broken unicode
- indices */
-/* if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
- return font->ascii2glyph[charnr];
- }*/
+ if(font->encoding != FONT_ENCODING_UNICODE) {
+ /* the following only works if the font encoding
+ is US-ASCII based. It's needed for fonts which return broken unicode
+ indices */
+ if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
+ return font->ascii2glyph[charnr];
+ }
+ }
return -1;
}
if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
return;
+ /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
+ with multiple fonts */
+ endtext(obj);
+
iterator = fontlist;
while(iterator) {
if(!strcmp((char*)iterator->swffont->name,fontid)) {
return;
}
- swf_SetLoadFontParameters(0,/*skip unused*/0,/*full unicode*/1);
+ swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
SWFFONT*swffont = swf_LoadFont(filename);
if(swffont == 0) {
swffont->layout->bounds[iii].xmax/20.0,
swffont->layout->bounds[iii].ymax/20.0
);
+ int t;
+ for(t=0;t<swffont->maxascii;t++) {
+ if(swffont->ascii2glyph[t] == iii)
+ msg("<debug> | - maps to %d",t);
+ }
}
}
obj->fontm22 == m22)
return;
if(textid>=0)
- endtext(obj);
+ endtext(obj);
obj->fontm11 = m11;
obj->fontm12 = m12;
obj->fontm21 = m21;
tag = swf_InsertTag(tag,ST_DEFINESHAPE);
swf_ShapeNew(&shape);
- linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
+ linestyleid = swf_ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
rgb.r = obj->fillrgb.r;
rgb.g = obj->fillrgb.g;
rgb.b = obj->fillrgb.b;
swf_SetU16(tag,shapeid); // ID
/* TODO: patch back */
+ bboxrectpos = tag->len;
r.xmin = 0;
r.ymin = 0;
r.xmax = 20*sizex;
r.ymax = 20*sizey;
-
swf_SetRect(tag,&r);
+
+ memset(&bboxrect, 0, sizeof(bboxrect));
swf_SetShapeStyles(tag,shape);
swf_ShapeCountBits(shape,NULL,NULL);
swf_SetShapeBits(tag,shape);
+ /* TODO: do we really need this? */
swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
swflastx=swflasty=0;
lastwasfill = 0;
static void starttext(struct swfoutput*obj)
{
if(shapeid>=0)
- endshape();
+ endshape(0);
textid = ++currentswfid;
swflastx=swflasty=0;
}
+
+
+/* TODO: move to ../lib/rfxswf */
+void changeRect(TAG*tag, int pos, SRECT*newrect)
+{
+ /* determine length of old rect */
+ tag->pos = pos;
+ tag->readBit = 0;
+ SRECT old;
+ swf_GetRect(tag, &old);
+ swf_ResetReadBits(tag);
+ int pos_end = tag->pos;
+
+ int len = tag->len - pos_end;
+ U8*data = (U8*)malloc(len);
+ memcpy(data, &tag->data[pos_end], len);
+ tag->writeBit = 0;
+ tag->len = pos;
+ swf_SetRect(tag, newrect);
+ swf_SetBlock(tag, data, len);
+ free(data);
+ tag->pos = tag->readBit = 0;
+}
+
+void fixAreas()
+{
+ if(!shapeisempty && fill &&
+ (bboxrect.xmin == bboxrect.xmax ||
+ bboxrect.ymin == bboxrect.ymax) &&
+ minlinewidth >= 0.001
+ ) {
+ msg("<debug> Shape has size 0");
+
+ if(bboxrect.xmin == bboxrect.xmax && bboxrect.ymin == bboxrect.ymax) {
+ /* this thing comes down to a single dot- nothing to fix here */
+ return;
+ }
+
+ float x=0,y=0;
+ if(bboxrect.xmin == bboxrect.xmax) {
+ x = minlinewidth;
+ } else {
+ y = minlinewidth;
+ }
+ /* warning: doing this inside endshape() is dangerous */
+ moveto(tag, bboxrect.xmin/20.0 , bboxrect.ymin/20.0);
+ lineto(tag, bboxrect.xmax/20.0 + x, bboxrect.ymin/20.0);
+ lineto(tag, bboxrect.xmax/20.0 + x, bboxrect.ymax/20.0 + y);
+ lineto(tag, bboxrect.xmin/20.0 , bboxrect.ymax/20.0 + y);
+ lineto(tag, bboxrect.xmin/20.0 , bboxrect.ymin/20.0);
+ }
+
+}
-static void endshape()
+static void endshape(int clipdepth)
{
if(shapeid<0)
return;
- swf_ShapeSetEnd(tag);
- if(shapeisempty) {
+ if(!clipdepth)
+ fixAreas();
+
+ if(shapeisempty ||
+ (bboxrect.xmin == bboxrect.xmax && bboxrect.ymin == bboxrect.ymax))
+ {
// delete the tag again, we didn't do anything
TAG*todel = tag;
tag = tag->prev;
swf_DeleteTag(todel);
- } else {
- /* TODO: fix bounding box */
- tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
- swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
+ shapeid = -1;
+ bboxrectpos = -1;
+ return;
}
+
+ swf_ShapeSetEnd(tag);
+
+ changeRect(tag, bboxrectpos, &bboxrect);
+
+ tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
+ if(clipdepth)
+ swf_ObjectPlaceClip(tag,shapeid,depth++,NULL,NULL,NULL,clipdepth);
+ else
+ swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
+
shapeid = -1;
+ bboxrectpos = -1;
}
static void endpage(struct swfoutput*obj)
{
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
endtext(obj);
while(clippos)
obj->fillrgb.b == b &&
obj->fillrgb.a == a) return;
if(shapeid>=0)
- endshape();
+ endshape(0);
obj->fillrgb.r = r;
obj->fillrgb.g = g;
obj->strokergb.a == a) return;
if(shapeid>=0)
- endshape();
+ endshape(0);
obj->strokergb.r = r;
obj->strokergb.g = g;
obj->strokergb.b = b;
obj->strokergb.a = a;
}
-void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
+void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
{
- if(obj->linewidth == (u16)(linewidth*20))
+ if(linewidth == (u16)(_linewidth*20))
return;
if(shapeid>=0)
- endshape();
- obj->linewidth = (u16)(linewidth*20);
+ endshape(0);
+ linewidth = (u16)(_linewidth*20);
}
if(textid>=0)
endtext(obj);
if(shapeid>=0)
- endshape();
+ endshape(0);
if(clippos >= 127)
{
void swfoutput_endclip(swfoutput*obj)
{
if(textid>=0)
- endtext(obj);
+ endtext(obj);
if(shapeid>=0)
- endshape();
+ endshape(0);
if(!clippos) {
msg("<error> Invalid end of clipping region");
}
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
- endtext(obj);
+ endtext(obj);
if(opennewwindow)
actions = action_GetUrl(0, url, "_parent");
ActionTAG* actions;
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
- endtext(obj);
+ endtext(obj);
actions = action_GotoFrame(0, page);
actions = action_End(actions);
char mouseover = 1;
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
- endtext(obj);
+ endtext(obj);
if(!strncmp(tmp, "call:", 5))
{
myshapeid = ++currentswfid;
tag = swf_InsertTag(tag,ST_DEFINESHAPE);
swf_ShapeNew(&shape);
- //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
+ //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
//fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
swf_SetU16(tag, myshapeid);
{
TAG*oldtag;
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
- endtext(obj);
+ endtext(obj);
int bitid = ++currentswfid;
oldtag = tag;
JPEGBITS*jpeg;
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
- endtext(obj);
+ endtext(obj);
int bitid = ++currentswfid;
oldtag = tag;
{
TAG*oldtag;
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
- endtext(obj);
+ endtext(obj);
int bitid = ++currentswfid;
oldtag = tag;
TAG*oldtag;
U8*mem2 = 0;
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
- endtext(obj);
+ endtext(obj);
if(sizex&3)
{
{
if(id<0) return;
if(shapeid>=0)
- endshape();
+ endshape(0);
if(textid>=0)
- endtext(obj);
+ endtext(obj);
drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
}
+void swfoutput_setparameter(char*name, char*value)
+{
+ if(!strcmp(name, "drawonlyshapes")) {
+ drawonlyshapes = atoi(value);
+ } else if(!strcmp(name, "ignoredraworder")) {
+ ignoredraworder = atoi(value);
+ } else if(!strcmp(name, "filloverlap")) {
+ filloverlap = atoi(value);
+ } else if(!strcmp(name, "linksopennewwindow")) {
+ opennewwindow = atoi(value);
+ } else if(!strcmp(name, "opennewwindow")) {
+ opennewwindow = atoi(value);
+ } else if(!strcmp(name, "storeallcharacters")) {
+ storeallcharacters = atoi(value);
+ } else if(!strcmp(name, "enablezlib")) {
+ enablezlib = atoi(value);
+ } else if(!strcmp(name, "insertstop")) {
+ insertstoptag = atoi(value);
+ } else if(!strcmp(name, "flashversion")) {
+ flashversion = atoi(value);
+ } else if(!strcmp(name, "minlinewidth")) {
+ minlinewidth = atof(value);
+ } else if(!strcmp(name, "jpegquality")) {
+ int val = atoi(value);
+ if(val<0) val=0;
+ if(val>100) val=100;
+ jpegquality = val;
+ } else if(!strcmp(name, "splinequality")) {
+ int v = atoi(value);
+ v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
+ if(v<1) v = 1;
+ splinemaxerror = v;
+ } else if(!strcmp(name, "fontquality")) {
+ int v = atoi(value);
+ v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
+ if(v<1) v = 1;
+ fontsplinemaxerror = v;
+ } else {
+ fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);
+ }
+}
+