X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fdevices%2Fswf.c;h=48b054acece7f18dd240d59e585e30742a1662cf;hp=614b2250f47f8e4b7172d034698f789925c8e78f;hb=fc815311aa1bd67877b404493838dfd85a86f596;hpb=0d0018bb20748de8a38d5791bd08a307e2a421d9 diff --git a/lib/devices/swf.c b/lib/devices/swf.c index 614b225..48b054a 100644 --- a/lib/devices/swf.c +++ b/lib/devices/swf.c @@ -44,18 +44,31 @@ #include "../gfxpoly.h" #include "../png.h" -#define CHARDATAMAX 8192 +#define CHARDATAMAX 1024 #define CHARMIDX 0 #define CHARMIDY 0 -typedef struct _chardata { +typedef struct _charatposition { int charid; - int fontid; /* TODO: use a SWFFONT instead */ + SWFFONT*font; int x; int y; int size; RGBA color; -} chardata_t; +} charatposition_t; + +typedef struct _chararray { + charatposition_t chr[CHARDATAMAX+1]; + int pos; + struct _chararray *next; +} chararray_t; + +typedef struct _charbuffer { + MATRIX matrix; + chararray_t*array; + chararray_t*last; + struct _charbuffer *next; +} charbuffer_t; typedef struct _fontlist { @@ -77,6 +90,7 @@ typedef struct _swfoutput_internal double config_ppmsubpixels; double config_jpegsubpixels; char hasbuttons; + int config_invisibletexttofront; int config_dots; int config_simpleviewer; int config_opennewwindow; @@ -89,6 +103,7 @@ typedef struct _swfoutput_internal int config_enablezlib; int config_insertstoptag; int config_watermark; + int config_noclips; int config_flashversion; int config_reordertags; int config_showclipshapes; @@ -126,7 +141,7 @@ typedef struct _swfoutput_internal SHAPE* shape; int shapeid; - int textid; + int textmode; int watermarks; @@ -166,8 +181,9 @@ typedef struct _swfoutput_internal SRECT pagebbox; - chardata_t chardata[CHARDATAMAX]; - int chardatapos; + charbuffer_t* chardata; + charbuffer_t* topchardata; //chars supposed to be above everything else + int firstpage; char pagefinished; @@ -202,6 +218,10 @@ static void swf_addfont(gfxdevice_t*dev, gfxfont_t*font); static void swf_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action); static void swf_startframe(gfxdevice_t*dev, int width, int height); static void swf_endframe(gfxdevice_t*dev); +static void swfoutput_namedlink(gfxdevice_t*dev, char*name, gfxline_t*points); +static void swfoutput_linktopage(gfxdevice_t*dev, int page, gfxline_t*points); +static void swfoutput_linktourl(gfxdevice_t*dev, const char*url, gfxline_t*points); + static gfxresult_t* swf_finish(gfxdevice_t*driver); static swfoutput_internal* init_internal_struct() @@ -216,7 +236,7 @@ static swfoutput_internal* init_internal_struct() i->startdepth = 0; i->linewidth = 0; i->shapeid = -1; - i->textid = -1; + i->textmode = 0; i->frameno = 0; i->lastframeno = 0; @@ -234,7 +254,7 @@ static swfoutput_internal* init_internal_struct() i->fillstylechanged = 0; i->bboxrectpos = -1; - i->chardatapos = 0; + i->chardata = 0; i->firstpage = 1; i->pagefinished = 1; @@ -313,12 +333,38 @@ typedef struct _plotxy double x,y; } plotxy_t; +static inline int twipsnap(double f) +{ + /* if(f < -0x40000000/20.0) { + fprintf(stderr, "Warning: Coordinate underflow (%f)\n", f); + f = -0x40000000/20.0; + } else if(f>0x3fffffff/20.0) { + fprintf(stderr, "Warning: Coordinate overflow (%f)\n", f); + f = 0x3fffffff/20.0; + }*/ + + /* clamp coordinates to a rectangle with the property that we + can represent a line from the upper left corner to the upper + right corner using no more than 64 strokes */ + const double min = -(1<<(18+4))/20.0; + const double max = ((1<<(18+4))-1)/20.0; + if(f < min) { + fprintf(stderr, "Warning: Coordinate underflow (%f)\n", f); + f = min; + } else if(f>max) { + fprintf(stderr, "Warning: Coordinate overflow (%f)\n", f); + f = max; + } + + return (int)(f*20); +} + // write a move-to command into the swf static int movetoxy(gfxdevice_t*dev, TAG*tag, plotxy_t p0) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; - int rx = (int)(p0.x*20); - int ry = (int)(p0.y*20); + int rx = twipsnap(p0.x); + int ry = twipsnap(p0.y); if(rx!=i->swflastx || ry!=i->swflasty || i->fillstylechanged) { swf_ShapeSetMove (tag, i->shape, rx,ry); i->fillstylechanged = 0; @@ -380,8 +426,8 @@ static void addPointToBBox(gfxdevice_t*dev, int px, int py) static void linetoxy(gfxdevice_t*dev, TAG*tag, plotxy_t p0) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; - int px = (int)(p0.x*20); - int py = (int)(p0.y*20); + int px = twipsnap(p0.x); + int py = twipsnap(p0.y); int rx = (px-i->swflastx); int ry = (py-i->swflasty); if(rx|ry) { @@ -419,12 +465,12 @@ static void splineto(gfxdevice_t*dev, TAG*tag, plotxy_t control,plotxy_t end) int lastlastx = i->swflastx; int lastlasty = i->swflasty; - int cx = ((int)(control.x*20)-i->swflastx); - int cy = ((int)(control.y*20)-i->swflasty); + int cx = (twipsnap(control.x)-i->swflastx); + int cy = (twipsnap(control.y)-i->swflasty); i->swflastx += cx; i->swflasty += cy; - int ex = ((int)(end.x*20)-i->swflastx); - int ey = ((int)(end.y*20)-i->swflasty); + int ex = (twipsnap(end.x)-i->swflastx); + int ey = (twipsnap(end.y)-i->swflasty); i->swflastx += ex; i->swflasty += ey; @@ -479,7 +525,7 @@ static void startFill(gfxdevice_t*dev) } } -static inline int colorcompare(gfxdevice_t*dev, RGBA*a,RGBA*b) +static inline int colorcompare(RGBA*a,RGBA*b) { if(a->r!=b->r || @@ -491,58 +537,55 @@ static inline int colorcompare(gfxdevice_t*dev, RGBA*a,RGBA*b) return 1; } -static SRECT getcharacterbbox(gfxdevice_t*dev, SWFFONT*font, MATRIX* m) +static SRECT getcharacterbbox(chararray_t*chardata, MATRIX* m) { - swfoutput_internal*i = (swfoutput_internal*)dev->internal; SRECT r; char debug = 0; memset(&r, 0, sizeof(r)); int t; if(debug) printf("\n"); - for(t=0;tchardatapos;t++) - { - if(i->chardata[t].fontid != font->id) { - msg(" Internal error: fontid %d != fontid %d", i->chardata[t].fontid, font->id); - exit(1); + + while(chardata) { + for(t=0;tpos;t++) { + charatposition_t*chr = &chardata->chr[t]; + SRECT b = chr->font->layout->bounds[chr->charid]; + b.xmin *= chr->size; + b.ymin *= chr->size; + b.xmax *= chr->size; + b.ymax *= chr->size; + + /* divide by 1024, rounding xmax/ymax up */ + b.xmax += 1023; b.ymax += 1023; b.xmin /= 1024; b.ymin /= 1024; b.xmax /= 1024; b.ymax /= 1024; + + b.xmin += chr->x; + b.ymin += chr->y; + b.xmax += chr->x; + b.ymax += chr->y; + + /* 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; + + b = swf_TurnRect(b, m); + + if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d, char %d]\n", + chr->font->layout->bounds[chr->charid].xmin/20.0, + chr->font->layout->bounds[chr->charid].ymin/20.0, + chr->font->layout->bounds[chr->charid].xmax/20.0, + chr->font->layout->bounds[chr->charid].ymax/20.0, + b.xmin/20.0, + b.ymin/20.0, + b.xmax/20.0, + b.ymax/20.0, + chr->font->id, + chr->charid); + swf_ExpandRect2(&r, &b); } - SRECT b = font->layout->bounds[i->chardata[t].charid]; - b.xmin *= i->chardata[t].size; - b.ymin *= i->chardata[t].size; - b.xmax *= i->chardata[t].size; - b.ymax *= i->chardata[t].size; - - /* divide by 1024, rounding xmax/ymax up */ - b.xmax += 1023; b.ymax += 1023; b.xmin /= 1024; b.ymin /= 1024; b.xmax /= 1024; b.ymax /= 1024; - - b.xmin += i->chardata[t].x; - b.ymin += i->chardata[t].y; - b.xmax += i->chardata[t].x; - b.ymax += i->chardata[t].y; - - /* 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; - - b = swf_TurnRect(b, m); - - if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n", - font->layout->bounds[i->chardata[t].charid].xmin/20.0, - font->layout->bounds[i->chardata[t].charid].ymin/20.0, - font->layout->bounds[i->chardata[t].charid].xmax/20.0, - font->layout->bounds[i->chardata[t].charid].ymax/20.0, - b.xmin/20.0, - b.ymin/20.0, - b.xmax/20.0, - b.ymax/20.0, - i->chardata[t].fontid, - font->id, - i->chardata[t].charid - ); - swf_ExpandRect2(&r, &b); + chardata = chardata->next; } if(debug) printf("-----> (%f,%f,%f,%f)\n", r.xmin/20.0, @@ -552,17 +595,27 @@ static SRECT getcharacterbbox(gfxdevice_t*dev, SWFFONT*font, MATRIX* m) return r; } -static void putcharacters(gfxdevice_t*dev, TAG*tag) +static chararray_t*chararray_reverse(chararray_t*buf) +{ + chararray_t*prev = 0; + while(buf) { + chararray_t*next = buf->next; + buf->next = prev; + prev = buf; + buf = next; + } + return prev; +} + +static void chararray_writetotag(chararray_t*_chardata, TAG*tag) { - swfoutput_internal*i = (swfoutput_internal*)dev->internal; - int t; SWFFONT font; RGBA color; - color.r = i->chardata[0].color.r^255; + color.r = _chardata?_chardata->chr[0].color.r^255:0; color.g = 0; color.b = 0; color.a = 0; - int lastfontid; + SWFFONT*lastfont; int lastx; int lasty; int lastsize; @@ -575,17 +628,17 @@ static void putcharacters(gfxdevice_t*dev, TAG*tag) if(tag->id != ST_DEFINETEXT && tag->id != ST_DEFINETEXT2) { - msg(" internal error: putcharacters needs an text tag, not %d\n",tag->id); + msg(" internal error: charbuffer_put needs an text tag, not %d\n",tag->id); exit(1); } - if(!i->chardatapos) { - msg(" putcharacters called with zero characters"); + if(!_chardata) { + msg(" charbuffer_put called with zero characters"); } for(pass = 0; pass < 2; pass++) { charstorepos = 0; - lastfontid = -1; + lastfont = 0; lastx = CHARMIDX; lasty = CHARMIDY; lastsize = -1; @@ -597,114 +650,155 @@ static void putcharacters(gfxdevice_t*dev, TAG*tag) swf_SetU8(tag, advancebits); } - for(t=0;t<=i->chardatapos;t++) - { - if(lastfontid != i->chardata[t].fontid || - lastx!=i->chardata[t].x || - lasty!=i->chardata[t].y || - !colorcompare(dev,&color, &i->chardata[t].color) || - charstorepos==127 || - lastsize != i->chardata[t].size || - t == i->chardatapos) - { - if(charstorepos && pass==0) - { - int s; - for(s=0;s=(1<=(1<writeBit = 0; // Q&D - swf_SetBits(tag, 0, 1); // GLYPH Record - swf_SetBits(tag, charstorepos, 7); // number of glyphs - int s; - for(s=0;schardatapos) - { - RGBA*newcolor=0; - SWFFONT*newfont=0; - int newx = 0; - int newy = 0; - if(lastx != i->chardata[t].x || - lasty != i->chardata[t].y) - { - newx = i->chardata[t].x; - newy = i->chardata[t].y; - if(newx == 0) - newx = SET_TO_ZERO; - if(newy == 0) - newy = SET_TO_ZERO; - } - if(!colorcompare(dev,&color, &i->chardata[t].color)) - { - color = i->chardata[t].color; - newcolor = &color; - } - font.id = i->chardata[t].fontid; - if(lastfontid != i->chardata[t].fontid || lastsize != i->chardata[t].size) - newfont = &font; - - tag->writeBit = 0; // Q&D - swf_TextSetInfoRecord(tag, newfont, i->chardata[t].size, newcolor, newx,newy); - } - - lastfontid = i->chardata[t].fontid; - lastx = i->chardata[t].x; - lasty = i->chardata[t].y; - lastsize = i->chardata[t].size; - } - - if(t==i->chardatapos) - break; - - int advance; - int nextt = t==i->chardatapos-1?t:t+1; - int rel = i->chardata[nextt].x-i->chardata[t].x; - if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) { - advance = rel; - lastx=i->chardata[nextt].x; - } - else { - advance = 0; - lastx=i->chardata[t].x; - } - charids[charstorepos] = i->chardata[t].charid; - charadvance[charstorepos] = advance; - charstorepos ++; - } + chararray_t*chardata = _chardata; + + while(chardata) { + int t; + + assert(!chardata->next || chardata->pos == CHARDATAMAX); + assert(chardata->pos); + + int to = chardata->next?chardata->pos-1:chardata->pos; + + for(t=0;t<=to;t++) + { + char islast = t==chardata->pos; + + charatposition_t*chr = &chardata->chr[t]; + + if(lastfont != chardata->chr[t].font || + lastx!=chardata->chr[t].x || + lasty!=chardata->chr[t].y || + !colorcompare(&color, &chardata->chr[t].color) || + charstorepos==127 || + lastsize != chardata->chr[t].size || + islast) + { + if(charstorepos && pass==0) + { + int s; + for(s=0;s=(1<=(1<writeBit = 0; // Q&D + swf_SetBits(tag, 0, 1); // GLYPH Record + swf_SetBits(tag, charstorepos, 7); // number of glyphs + int s; + for(s=0;sx || + lasty != chr->y) + { + newx = chr->x; + newy = chr->y; + if(newx == 0) + newx = SET_TO_ZERO; + if(newy == 0) + newy = SET_TO_ZERO; + } + if(!colorcompare(&color, &chr->color)) + { + color = chr->color; + newcolor = &color; + } + font.id = chr->font->id; + if(lastfont != chr->font || lastsize != chr->size) + newfont = &font; + + tag->writeBit = 0; // Q&D + swf_TextSetInfoRecord(tag, newfont, chr->size, newcolor, newx,newy); + } + + lastfont = chr->font; + lastx = chr->x; + lasty = chr->y; + lastsize = chr->size; + } + + if(islast) + break; + + int nextx = chr->x; + if(tpos-1) nextx = chardata->chr[t+1].x; + if(t==chardata->pos-1 && chardata->next) nextx = chardata->next->chr[0].x; + int dx = nextx-chr->x; + + int advance; + if(dx>=0 && (dx<(1<<(advancebits-1)) || pass==0)) { + advance = dx; + lastx=nextx; + } else { + advance = 0; + lastx=chr->x; + } + charids[charstorepos] = chr->charid; + charadvance[charstorepos] = advance; + charstorepos ++; + } + chardata = chardata->next; + } } - i->chardatapos = 0; } -static void putcharacter(gfxdevice_t*dev, int fontid, int charid, int x,int y, int size, RGBA color) +static void chararray_destroy(chararray_t*chr) { - swfoutput_internal*i = (swfoutput_internal*)dev->internal; - if(i->chardatapos == CHARDATAMAX) - { - msg(" Character buffer too small. SWF will be slightly bigger"); - endtext(dev); - starttext(dev); + while(chr) { + chararray_t*next = chr->next; + chr->next = 0; + free(chr); + chr = next; + } +} + +static inline int matrix_diff(MATRIX*m1, MATRIX*m2) +{ + return memcmp(m1,m2,sizeof(MATRIX)); +} +static charbuffer_t*charbuffer_append(charbuffer_t*buf, SWFFONT*font, int charid, int x,int y, int size, RGBA color, MATRIX*m) +{ + if(!buf || matrix_diff(&buf->matrix,m)) { + charbuffer_t*n = rfx_calloc(sizeof(charbuffer_t)); + n->matrix = *m; + n->next = buf; + buf = n; + } + if(!buf->last || buf->last->pos == CHARDATAMAX) { + chararray_t*n = rfx_calloc(sizeof(chararray_t)); + if(!buf->array) { + buf->array = buf->last = n; + } else { + buf->last->next = n; + buf->last = n; + } } - i->chardata[i->chardatapos].fontid = fontid; - i->chardata[i->chardatapos].charid = charid; - i->chardata[i->chardatapos].x = x; - i->chardata[i->chardatapos].y = y; - i->chardata[i->chardatapos].color = color; - i->chardata[i->chardatapos].size = size; - i->chardatapos++; + chararray_t*a = buf->last; + a->chr[a->pos].font = font; + a->chr[a->pos].charid = charid; + a->chr[a->pos].x = x; + a->chr[a->pos].y = y; + a->chr[a->pos].color = color; + a->chr[a->pos].size = size; + a->pos++; + return buf; } /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20). @@ -712,30 +806,27 @@ static void putcharacter(gfxdevice_t*dev, int fontid, int charid, int x,int y, i If we set it to low, however, the char positions will be inaccurate */ #define GLYPH_SCALE 1 -static void endtext(gfxdevice_t*dev) +static void chararray_writetodev(gfxdevice_t*dev, chararray_t*array, MATRIX*matrix, char invisible) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; - if(i->textid<0) - return; - + + int textid = getNewID(dev); i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT2); - swf_SetU16(i->tag, i->textid); - + swf_SetU16(i->tag, textid); SRECT r; - r = getcharacterbbox(dev, i->swffont, &i->fontmatrix); + r = getcharacterbbox(array, matrix); r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); + swf_SetMatrix(i->tag, matrix); + msg(" Placing text as ID %d", textid); + chararray_writetotag(array, i->tag); + i->chardata = 0; - swf_SetMatrix(i->tag,&i->fontmatrix); - - msg(" Placing text (%d characters) as ID %d", i->chardatapos, i->textid); - - putcharacters(dev, i->tag); swf_SetU8(i->tag,0); if(i->swf->fileVersion >= 8) { i->tag = swf_InsertTag(i->tag, ST_CSMTEXTSETTINGS); - swf_SetU16(i->tag, i->textid); + swf_SetU16(i->tag, textid); //swf_SetU8(i->tag, /*subpixel grid*/(2<<3)|/*flashtype*/0x40); swf_SetU8(i->tag, /*grid*/(1<<3)|/*flashtype*/0x40); @@ -745,13 +836,36 @@ static void endtext(gfxdevice_t*dev) swf_SetU32(i->tag, 0);//sharpness swf_SetU8(i->tag, 0);//reserved } - i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2); - - swf_ObjectPlace(i->tag,i->textid,getNewDepth(dev),&i->page_matrix,NULL,NULL); - i->textid = -1; + if(invisible && i->config_flashversion>=8) { + i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT3); + swf_ObjectPlaceBlend(i->tag,textid,getNewDepth(dev),&i->page_matrix,NULL,NULL,BLENDMODE_MULTIPLY); + } else { + i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2); + swf_ObjectPlace(i->tag,textid,getNewDepth(dev),&i->page_matrix,NULL,NULL); + } +} + +static void charbuffer_writetodevandfree(gfxdevice_t*dev, charbuffer_t*buf, char invisible) +{ + while(buf) { + charbuffer_t*next = buf->next;buf->next = 0; + chararray_writetodev(dev, buf->array, &buf->matrix, invisible); + chararray_destroy(buf->array); + free(buf); + buf = next; + } +} + +static void endtext(gfxdevice_t*dev) +{ + swfoutput_internal*i = (swfoutput_internal*)dev->internal; + if(!i->textmode) + return; + charbuffer_writetodevandfree(dev, i->chardata, 0);i->chardata = 0; + i->textmode = 0; } -/* set's the matrix which is to be applied to characters drawn by swfoutput_drawchar() */ +/* sets the matrix which is to be applied to characters drawn by swfoutput_drawchar() */ static void setfontscale(gfxdevice_t*dev,double m11,double m12, double m21,double m22,double x, double y, char force) { m11 *= 1024; @@ -764,7 +878,7 @@ static void setfontscale(gfxdevice_t*dev,double m11,double m12, double m21,doubl i->lastfontm21 == m21 && i->lastfontm22 == m22 && !force) return; - if(i->textid>=0) + if(i->textmode) endtext(dev); i->lastfontm11 = m11; @@ -868,11 +982,15 @@ static void endpage(gfxdevice_t*dev) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; if(i->pagefinished) - return; + return; if(i->shapeid>=0) - endshape(dev); - if(i->textid>=0) - endtext(dev); + endshape(dev); + if(i->textmode) + endtext(dev); + if(i->topchardata) { + charbuffer_writetodevandfree(dev, i->topchardata, 1); + i->topchardata=0; + } while(i->clippos) dev->endclip(dev); @@ -1002,6 +1120,7 @@ void swf_startframe(gfxdevice_t*dev, int width, int height) i->lastframeno = i->frameno; i->firstpage = 0; i->pagefinished = 0; + i->chardata = 0; } void swf_endframe(gfxdevice_t*dev) @@ -1172,7 +1291,7 @@ static void starttext(gfxdevice_t*dev) if(i->config_watermark) { insert_watermark(dev, 0); } - i->textid = getNewID(dev); + i->textmode = 1; i->swflastx=i->swflasty=0; } @@ -1416,7 +1535,7 @@ void swfoutput_finalize(gfxdevice_t*dev) /* Add AVM2 actionscript */ if(i->config_flashversion>=9 && - (i->config_insertstoptag || i->hasbuttons)) { + (i->config_insertstoptag || i->hasbuttons) && !i->config_linknameurl) { swf_AddButtonLinks(i->swf, i->config_insertstoptag, i->config_internallinkfunction||i->config_externallinkfunction); } @@ -1555,7 +1674,7 @@ static void swfoutput_setlinewidth(gfxdevice_t*dev, double _linewidth) } -static void drawlink(gfxdevice_t*dev, ActionTAG*,ActionTAG*, gfxline_t*points, char mouseover, const char*url); +static void drawlink(gfxdevice_t*dev, ActionTAG*,ActionTAG*, gfxline_t*points, char mouseover, char*type, const char*url); static void swfoutput_namedlink(gfxdevice_t*dev, char*name, gfxline_t*points); static void swfoutput_linktopage(gfxdevice_t*dev, int page, gfxline_t*points); static void swfoutput_linktourl(gfxdevice_t*dev, const char*url, gfxline_t*points); @@ -1601,7 +1720,7 @@ void swfoutput_linktourl(gfxdevice_t*dev, const char*url, gfxline_t*points) swfoutput_internal*i = (swfoutput_internal*)dev->internal; if(i->shapeid>=0) endshape(dev); - if(i->textid>=0) + if(i->textmode) endtext(dev); /* TODO: escape special characters in url */ @@ -1621,8 +1740,8 @@ void swfoutput_linktourl(gfxdevice_t*dev, const char*url, gfxline_t*points) } actions = action_End(actions); - drawlink(dev, actions, 0, points, 0, url); - + drawlink(dev, actions, 0, points, 0, "url", url); + swf_ActionFree(actions); } void swfoutput_linktopage(gfxdevice_t*dev, int page, gfxline_t*points) @@ -1632,7 +1751,7 @@ void swfoutput_linktopage(gfxdevice_t*dev, int page, gfxline_t*points) if(i->shapeid>=0) endshape(dev); - if(i->textid>=0) + if(i->textmode) endtext(dev); if(!i->config_internallinkfunction || i->config_flashversion>=9) { @@ -1649,7 +1768,7 @@ void swfoutput_linktopage(gfxdevice_t*dev, int page, gfxline_t*points) char name[80]; sprintf(name, "page%d", page); - drawlink(dev, actions, 0, points, 0, name); + drawlink(dev, actions, 0, points, 0, "page", name); swf_ActionFree(actions); } @@ -1666,9 +1785,10 @@ void swfoutput_namedlink(gfxdevice_t*dev, char*name, gfxline_t*points) if(i->shapeid>=0) endshape(dev); - if(i->textid>=0) + if(i->textmode) endtext(dev); + char*type = 0; if(!strncmp(tmp, "call:", 5)) { char*x = strchr(&tmp[5], ':'); @@ -1687,6 +1807,7 @@ void swfoutput_namedlink(gfxdevice_t*dev, char*name, gfxline_t*points) } actions2 = action_End(0); mouseover = 0; + type = "call"; } else { @@ -1699,9 +1820,10 @@ void swfoutput_namedlink(gfxdevice_t*dev, char*name, gfxline_t*points) actions2 = action_PushString(actions2, ""); actions2 = action_SetVariable(actions2); actions2 = action_End(actions2); + type = "subtitle"; } - drawlink(dev, actions1, actions2, points, mouseover, name); + drawlink(dev, actions1, actions2, points, mouseover, type, name); swf_ActionFree(actions1); swf_ActionFree(actions2); @@ -1748,7 +1870,7 @@ static void drawgfxline(gfxdevice_t*dev, gfxline_t*line, int fill) } -static void drawlink(gfxdevice_t*dev, ActionTAG*actions1, ActionTAG*actions2, gfxline_t*points, char mouseover, const char*url) +static void drawlink(gfxdevice_t*dev, ActionTAG*actions1, ActionTAG*actions2, gfxline_t*points, char mouseover, char*type, const char*url) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; RGBA rgb; @@ -1762,6 +1884,11 @@ static void drawlink(gfxdevice_t*dev, ActionTAG*actions1, ActionTAG*actions2, gf int buttonid = getNewID(dev); gfxbbox_t bbox = gfxline_getbbox(points); + if(i->config_linknameurl) { + actions1 = 0; + actions2 = 0; + } + i->hasbuttons = 1; /* shape */ @@ -1866,9 +1993,9 @@ static void drawlink(gfxdevice_t*dev, ActionTAG*actions1, ActionTAG*actions2, gf m = i->page_matrix; m.tx = p.x; m.ty = p.y; - swf_ObjectPlace(i->tag, buttonid, getNewDepth(dev),&m,0,name); + swf_ObjectPlace(i->tag, buttonid, getNewDepth(dev),&m,0,(U8*)name); } else { - swf_ObjectPlace(i->tag, buttonid, getNewDepth(dev),&i->page_matrix,0,name); + swf_ObjectPlace(i->tag, buttonid, getNewDepth(dev),&i->page_matrix,0,(U8*)name); } } @@ -1995,6 +2122,10 @@ int swf_setparameter(gfxdevice_t*dev, const char*name, const char*value) i->config_caplinewidth = atof(value); } else if(!strcmp(name, "linktarget")) { i->config_linktarget = strdup(value); + } else if(!strcmp(name, "invisibletexttofront")) { + i->config_invisibletexttofront = atoi(value); + } else if(!strcmp(name, "noclips")) { + i->config_noclips = atoi(value); } else if(!strcmp(name, "dumpfonts")) { i->config_dumpfonts = atoi(value); } else if(!strcmp(name, "animate")) { @@ -2287,6 +2418,8 @@ static void drawoutline(gfxdevice_t*dev, gfxline_t*line) static void swf_startclip(gfxdevice_t*dev, gfxline_t*line) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; + if(i->config_noclips) + return; endtext(dev); endshape(dev); @@ -2353,7 +2486,9 @@ static void swf_startclip(gfxdevice_t*dev, gfxline_t*line) static void swf_endclip(gfxdevice_t*dev) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; - if(i->textid>=0) + if(i->config_noclips) + return; + if(i->textmode) endtext(dev); if(i->shapeid>=0) endshape(dev); @@ -2514,11 +2649,11 @@ static void swf_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcol if(has_dots) gfxline_fix_short_edges(line); /* we need to convert the line into a polygon */ - gfxpoly_t* poly = gfxpoly_strokeToPoly(line, width, cap_style, joint_style, miterLimit); - gfxline_t*gfxline = gfxpoly_to_gfxline(poly); + gfxpoly_t* poly = gfxpoly_from_stroke(line, width, cap_style, joint_style, miterLimit, DEFAULT_GRID); + gfxline_t*gfxline = gfxline_from_gfxpoly(poly); dev->fill(dev, gfxline, color); gfxline_free(gfxline); - gfxpoly_free(poly); + gfxpoly_destroy(poly); return; } @@ -2559,7 +2694,6 @@ static void swf_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color) gfxbbox_t r = gfxline_getbbox(line); int is_outside_page = !is_inside_page(dev, r.xmin, r.ymin) || !is_inside_page(dev, r.xmax, r.ymax); - //if(i->chardatapos && i->chardata[i->chardatapos-1].color.a) { endtext(dev); if(!i->config_ignoredraworder) @@ -2714,6 +2848,7 @@ static SWFFONT* gfxfont_to_swffont(gfxfont_t*font, const char* id) swf_Shape01DrawerInit(&draw, 0); line = font->glyphs[t].line; + while(line) { FPOINT c,to; c.x = line->sx * GLYPH_SCALE; c.y = line->sy * GLYPH_SCALE; @@ -2882,11 +3017,9 @@ static void swf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t* if(!i->swffont || !i->swffont->name || strcmp((char*)i->swffont->name,font->id)) // not equal to current font { - /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope - with multiple fonts */ - endtext(dev); swf_switchfont(dev, font->id); // set the current font } + if(!i->swffont) { msg(" swf_drawchar: Font is NULL"); return; @@ -2902,7 +3035,7 @@ static void swf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t* i->fontmatrix.r0/65536.0 * i->fontmatrix.r1/65536.0; if(fabs(det) < 0.0005) { /* x direction equals y direction- the text is invisible */ - msg(" Not drawing invisible character character %d (det=%f, m=[%f %f;%f %f]\n", glyph, + msg(" Not drawing invisible character %d (det=%f, m=[%f %f;%f %f]\n", glyph, det, i->fontmatrix.sx/65536.0, i->fontmatrix.r1/65536.0, i->fontmatrix.r0/65536.0, i->fontmatrix.sy/65536.0); @@ -2932,13 +3065,21 @@ static void swf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t* if(i->shapeid>=0) endshape(dev); - if(i->textid<0) + if(!i->textmode) starttext(dev); msg(" Drawing char %d in font %d at %d,%d in color %02x%02x%02x%02x", glyph, i->swffont->id, x, y, color->r, color->g, color->b, color->a); - putcharacter(dev, i->swffont->id, glyph, x, y, i->current_font_size, *(RGBA*)color); + if(color->a == 0 && i->config_invisibletexttofront) { + if(i->config_flashversion>=8) { + // use "multiply" blend mode + color->a = color->r = color->g = color->b = 255; + } + i->topchardata = charbuffer_append(i->topchardata, i->swffont, glyph, x, y, i->current_font_size, *(RGBA*)color, &i->fontmatrix); + } else { + i->chardata = charbuffer_append(i->chardata, i->swffont, glyph, x, y, i->current_font_size, *(RGBA*)color, &i->fontmatrix); + } swf_FontUseGlyph(i->swffont, glyph); return; }