X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fdevices%2Fswf.c;h=25598606a7d2a2273fc355f27e61bfa5575c0248;hb=44ea6868c89dc150533a36361a7d76ac461278fb;hp=6027af204a42661c0122640cbd4196491c94abc7;hpb=2f3e5dcf6e11c1639efdd1df44b43889292a595f;p=swftools.git diff --git a/lib/devices/swf.c b/lib/devices/swf.c index 6027af2..2559860 100644 --- a/lib/devices/swf.c +++ b/lib/devices/swf.c @@ -76,6 +76,7 @@ typedef struct _swfoutput_internal double config_dumpfonts; double config_ppmsubpixels; double config_jpegsubpixels; + int config_simpleviewer; int config_opennewwindow; int config_ignoredraworder; int config_drawonlyshapes; @@ -155,6 +156,8 @@ typedef struct _swfoutput_internal int bboxrectpos; SRECT bboxrect; + SRECT pagebbox; + chardata_t chardata[CHARDATAMAX]; int chardatapos; int firstpage; @@ -277,7 +280,7 @@ static U16 getNewID(gfxdevice_t* dev) static U16 getNewDepth(gfxdevice_t* dev) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; - if(i->depth == 65535) { + if(i->depth == 65520) { if(!id_error) { msg(" Depth Table overflow"); msg(" This file is too complex to render- SWF only supports 65536 shapes at once"); @@ -703,7 +706,7 @@ static void endtext(gfxdevice_t*dev) SRECT r; r = getcharacterbbox(dev, i->swffont, &i->fontmatrix); - + r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); swf_SetMatrix(i->tag,&i->fontmatrix); @@ -760,8 +763,8 @@ static void setfontscale(gfxdevice_t*dev,double m11,double m12, double m21,doubl double ifs = 1.0 / (i->current_font_size*GLYPH_SCALE); MATRIX m; - m.sx = (U32)((m11*ifs)*65536); m.r1 = (U32)((m21*ifs)*65536); - m.r0 = (U32)((m12*ifs)*65536); m.sy = (U32)((m22*ifs)*65536); + m.sx = (S32)((m11*ifs)*65536); m.r1 = (S32)((m21*ifs)*65536); + m.r0 = (S32)((m12*ifs)*65536); m.sy = (S32)((m22*ifs)*65536); /* this is the position of the first char to set a new fontmatrix- we hope that it's close enough to all other characters using the font, so we use its position as origin for the matrix */ @@ -791,9 +794,9 @@ static void draw_watermark(gfxdevice_t*dev, gfxbbox_t r, char drawall) for(y=0;y>y)&1)) { - if(!drawall && lrand48()%5) + if(!drawall && rand()%5) continue; - unsigned int b = lrand48(); + unsigned int b = rand(); moveto(dev, i->tag, x*sx+tx+((b>>1)&1)/20.0, y*sy+ty+((b>>3)&1)/20.0); lineto(dev, i->tag, x*sx+px+tx+((b>>2)&1)/20.0, y*sy+ty+((b>>3)&1)/20.0); lineto(dev, i->tag, x*sx+px+tx+((b>>2)&1)/20.0, y*sy+py+ty+((b>>4)&1)/20.0); @@ -830,7 +833,7 @@ static void insert_watermark(gfxdevice_t*dev, char drawall) if(drawall) { swfoutput_setfillcolor(dev, 0,0,255,192); } else { - swfoutput_setfillcolor(dev, lrand48(),lrand48(),lrand48(),(lrand48()&127)+128); + swfoutput_setfillcolor(dev, rand(),rand(),rand(),(rand()&127)+128); } startshape(dev); startFill(dev); @@ -864,11 +867,98 @@ static void endpage(gfxdevice_t*dev) i->pagefinished = 1; } +static void addViewer(gfxdevice_t* dev) +{ + swfoutput_internal*i = (swfoutput_internal*)dev->internal; + + SHAPE*s; + RGBA button_colors[3]= {{0xbf,0x00,0x00,0x80},{0xbf,0x20,0x20,0xc0}, {0xbf,0xc0,0xc0,0xff}}; + int ids[6]; + int button_sizex = 20; + int button_sizey = 20; + int t; + RGBA black = {255,0,0,0}; + for(t=0;t<6;t++) { + i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3); + swf_ShapeNew(&s); + int ls1 = swf_ShapeAddLineStyle(s,40,&black); + int fs1 = swf_ShapeAddSolidFillStyle(s,&button_colors[t/2]); + int shapeid = ids[t] = getNewID(dev); + swf_SetU16(i->tag,shapeid); + SRECT r; + r.xmin = -20*button_sizex; + r.xmax = 20*button_sizex; + r.ymin = 0; + r.ymax = 40*button_sizey; + swf_SetRect(i->tag,&r); // set shape bounds + swf_SetShapeHeader(i->tag,s); // write all styles to tag + swf_ShapeSetAll(i->tag,s,0*button_sizex,0,ls1,fs1,0); + swf_ShapeSetLine(i->tag,s,(1-(t&1)*2)*20*button_sizex,20*button_sizey); + swf_ShapeSetLine(i->tag,s,-(1-(t&1)*2)*20*button_sizex,20*button_sizey); + swf_ShapeSetLine(i->tag,s,0,-40*button_sizey); + swf_ShapeSetEnd(i->tag); // finish drawing + swf_ShapeFree(s); // clean shape structure (which isn't needed anymore after writing the tag) + } + ActionTAG*a1=0,*a2=0,*a3=0; + a1 = action_NextFrame(a1); + a1 = action_Stop(a1); + a1 = action_End(a1); + + a2 = action_PreviousFrame(a2); + a2 = action_Stop(a2); + a2 = action_End(a2); + + a3 = action_Stop(a3); + a3 = action_End(a3); + + i->tag = swf_InsertTag(i->tag, ST_DOACTION); + swf_ActionSet(i->tag,a3); + + i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON); + int buttonid1 = getNewID(dev); + swf_SetU16(i->tag, buttonid1); + swf_ButtonSetRecord(i->tag,BS_UP|BS_HIT,ids[0],1,NULL,NULL); + swf_ButtonSetRecord(i->tag,BS_OVER,ids[2],1,NULL,NULL); + swf_ButtonSetRecord(i->tag,BS_DOWN,ids[4],1,NULL,NULL); + swf_SetU8(i->tag,0); // end of button records + swf_ActionSet(i->tag,a1); + + i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON); + int buttonid2 = getNewID(dev); + swf_SetU16(i->tag, buttonid2); + swf_ButtonSetRecord(i->tag,BS_UP|BS_HIT,ids[1],1,NULL,NULL); + swf_ButtonSetRecord(i->tag,BS_OVER,ids[3],1,NULL,NULL); + swf_ButtonSetRecord(i->tag,BS_DOWN,ids[5],1,NULL,NULL); + swf_SetU8(i->tag,0); // end of button records + swf_ActionSet(i->tag,a2); + + i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2); + MATRIX m; + swf_GetMatrix(0, &m); + m.tx = button_sizex*20+200; + swf_ObjectPlace(i->tag, buttonid2, 65534,&m,0,0); + i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2); + m.tx = button_sizex*20+200+200; + swf_ObjectPlace(i->tag, buttonid1, 65535,&m,0,0); +} + + void swf_startframe(gfxdevice_t*dev, int width, int height) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; + if(i->firstpage) { + if(i->config_protect) { + i->tag = swf_InsertTag(i->tag, ST_PROTECT); + i->config_protect = 0; + } + if(i->config_simpleviewer) { + addViewer(dev); + } + } + if(!i->firstpage && !i->pagefinished) endpage(dev); + msg(" Starting new SWF page of size %dx%d", width, height); swf_GetMatrix(0, &i->page_matrix); @@ -880,17 +970,17 @@ void swf_startframe(gfxdevice_t*dev, int width, int height) i->max_y = height; i->watermarks = 0; - /* set clipping/background rectangle */ - /* TODO: this should all be done in SWFOutputDev */ - //setBackground(dev, x1, y1, x2, y2); + /* create a bbox structure with the page size. This is used + for clipping shape and text bounding boxes. As we don't want to + generate bounding boxes which extend beyond the movie size (in + order to not confuse Flash), we clip everything against i->pagebbox */ + i->pagebbox.xmin = 0; + i->pagebbox.ymin = 0; + i->pagebbox.xmax = width*20; + i->pagebbox.ymax = height*20; /* increase SWF's bounding box */ - SRECT r; - r.xmin = 0; - r.ymin = 0; - r.xmax = width*20; - r.ymax = height*20; - swf_ExpandRect2(&i->swf->movieSize, &r); + swf_ExpandRect2(&i->swf->movieSize, &i->pagebbox); i->lastframeno = i->frameno; i->firstpage = 0; @@ -960,7 +1050,7 @@ void gfxdevice_swf_init(gfxdevice_t* dev) dev->name = "swf"; - dev->internal = init_internal_struct(); + dev->internal = init_internal_struct(); // set config to default values dev->startpage = swf_startframe; dev->endpage = swf_endframe; @@ -980,15 +1070,13 @@ void gfxdevice_swf_init(gfxdevice_t* dev) swfoutput_internal*i = (swfoutput_internal*)dev->internal; i->dev = dev; - RGBA rgb; - msg(" initializing swf output\n", i->max_x,i->max_y); i->swffont = 0; i->swf = (SWF*)rfx_calloc(sizeof(SWF)); - i->swf->fileVersion = i->config_flashversion; - i->swf->frameRate = i->config_framerate*0x100; + i->swf->fileVersion = 0; + i->swf->frameRate = 0x80; i->swf->movieSize.xmin = 0; i->swf->movieSize.ymin = 0; i->swf->movieSize.xmax = 0; @@ -996,14 +1084,12 @@ void gfxdevice_swf_init(gfxdevice_t* dev) i->swf->firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR); i->tag = i->swf->firstTag; + RGBA rgb; rgb.a = rgb.r = rgb.g = rgb.b = 0xff; rgb.r = 0; swf_SetRGB(i->tag,&rgb); i->startdepth = i->depth = 0; - - if(i->config_protect) - i->tag = swf_InsertTag(i->tag, ST_PROTECT); } static void startshape(gfxdevice_t*dev) @@ -1034,11 +1120,7 @@ static void startshape(gfxdevice_t*dev) i->bboxrectpos = i->tag->len; /* changed later */ - r.xmin = 0; - r.ymin = 0; - r.xmax = 20*i->max_x; - r.ymax = 20*i->max_y; - swf_SetRect(i->tag,&r); + swf_SetRect(i->tag,&i->pagebbox); memset(&i->bboxrect, 0, sizeof(i->bboxrect)); @@ -1102,7 +1184,7 @@ void cancelshape(gfxdevice_t*dev) i->shapeid = -1; i->bboxrectpos = -1; -// i->currentswfid--; // this was an *exceptionally* bad idea +// i->currentswfid--; // doesn't work, for some reason } void fixAreas(gfxdevice_t*dev) @@ -1188,7 +1270,8 @@ static void endshape(gfxdevice_t*dev) swf_ShapeSetEnd(i->tag); - changeRect(dev, i->tag, i->bboxrectpos, &i->bboxrect); + SRECT r = swf_ClipRect(i->pagebbox, i->bboxrect); + changeRect(dev, i->tag, i->bboxrectpos, &r); msg(" Placing shape ID %d", i->shapeid); @@ -1234,6 +1317,9 @@ void swfoutput_finalize(gfxdevice_t*dev) if(i->tag && i->tag->id == ST_END) return; //already done + i->swf->fileVersion = i->config_flashversion; + i->swf->frameRate = i->config_framerate*0x100; + if(i->config_bboxvars) { TAG* tag = swf_InsertTag(i->swf->firstTag, ST_DOACTION); ActionTAG*a = 0; @@ -1282,6 +1368,7 @@ void swfoutput_finalize(gfxdevice_t*dev) iterator = iterator->next; } + i->tag = swf_InsertTag(i->tag,ST_END); TAG* tag = i->tag->prev; @@ -1499,8 +1586,8 @@ void swfoutput_linktourl(gfxdevice_t*dev, const char*url, gfxline_t*points) actions = action_GetUrl(actions, url, i->config_linktarget); } actions = action_End(actions); - - drawlink(dev, actions, 0, points,0); + + drawlink(dev, actions, 0, points, 0); } void swfoutput_linktopage(gfxdevice_t*dev, int page, gfxline_t*points) { @@ -1523,7 +1610,7 @@ void swfoutput_linktopage(gfxdevice_t*dev, int page, gfxline_t*points) actions = action_End(actions); } - drawlink(dev, actions, 0, points,0); + drawlink(dev, actions, 0, points, 0); } /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets @@ -1573,19 +1660,22 @@ void swfoutput_namedlink(gfxdevice_t*dev, char*name, gfxline_t*points) actions2 = action_End(actions2); } - drawlink(dev, actions1, actions2, points,mouseover); + drawlink(dev, actions1, actions2, points, mouseover); swf_ActionFree(actions1); swf_ActionFree(actions2); free(tmp); } -static void drawgfxline(gfxdevice_t*dev, gfxline_t*line) +static void drawgfxline(gfxdevice_t*dev, gfxline_t*line, int fill) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; gfxcoord_t lastx=0,lasty=0,px=0,py=0; char lastwasmoveto; int lines= 0, splines=0; + + i->fill = fill; + while(1) { if(!line) break; @@ -1642,13 +1732,14 @@ static void drawlink(gfxdevice_t*dev, ActionTAG*actions1, ActionTAG*actions2, gf r.ymin = (int)(bbox.ymin*20); r.xmax = (int)(bbox.xmax*20); r.ymax = (int)(bbox.ymax*20); + r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); swf_SetShapeStyles(i->tag,i->shape); swf_ShapeCountBits(i->shape,NULL,NULL); swf_SetShapeBits(i->tag,i->shape); swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0); i->swflastx = i->swflasty = 0; - drawgfxline(dev, points); + drawgfxline(dev, points, 1); swf_ShapeSetEnd(i->tag); /* shape2 */ @@ -1664,13 +1755,14 @@ static void drawlink(gfxdevice_t*dev, ActionTAG*actions1, ActionTAG*actions2, gf r.ymin = (int)(bbox.ymin*20); r.xmax = (int)(bbox.xmax*20); r.ymax = (int)(bbox.ymax*20); + r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); swf_SetShapeStyles(i->tag,i->shape); swf_ShapeCountBits(i->shape,NULL,NULL); swf_SetShapeBits(i->tag,i->shape); swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0); i->swflastx = i->swflasty = 0; - drawgfxline(dev, points); + drawgfxline(dev, points, 1); swf_ShapeSetEnd(i->tag); if(!mouseover) @@ -1708,6 +1800,8 @@ static void drawlink(gfxdevice_t*dev, ActionTAG*actions1, ActionTAG*actions2, gf swf_ButtonPostProcess(i->tag, 1); } } + char name[80]; + sprintf(name, "link%d", buttonid); msg(" Placing link ID %d", buttonid); i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2); @@ -1721,9 +1815,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,0); + swf_ObjectPlace(i->tag, buttonid, getNewDepth(dev),&m,0,name); } else { - swf_ObjectPlace(i->tag, buttonid, getNewDepth(dev),&i->page_matrix,0,0); + swf_ObjectPlace(i->tag, buttonid, getNewDepth(dev),&i->page_matrix,0,name); } } @@ -1850,6 +1944,8 @@ int swf_setparameter(gfxdevice_t*dev, const char*name, const char*value) i->config_dumpfonts = atoi(value); } else if(!strcmp(name, "animate")) { i->config_animate = atoi(value); + } else if(!strcmp(name, "simpleviewer")) { + i->config_simpleviewer = atoi(value); } else if(!strcmp(name, "next_bitmap_is_jpeg")) { i->jpeg = 1; } else if(!strcmp(name, "jpegquality")) { @@ -1879,9 +1975,7 @@ int swf_setparameter(gfxdevice_t*dev, const char*name, const char*value) i->config_linkcolor.a = NIBBLE(value[6])<<4 | NIBBLE(value[7]); } else if(!strcmp(name, "help")) { printf("\nSWF layer options:\n"); - printf("jpegdpi= resolution adjustment for jpeg images\n"); printf("jpegsubpixels= resolution adjustment for jpeg images (same as jpegdpi, but in pixels)\n"); - printf("ppmdpi= resolution adjustment for lossless images\n"); printf("ppmsubpixels= shortcut for setting both jpegsubpixels and ppmsubpixels\n"); printf("drawonlyshapes convert everything to shapes (currently broken)\n"); @@ -2080,13 +2174,14 @@ static void swf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxm int fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1); swf_SetU16(i->tag, myshapeid); SRECT r = gfxline_getSWFbbox(line); + r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); swf_SetShapeStyles(i->tag,shape); swf_ShapeCountBits(shape,NULL,NULL); swf_SetShapeBits(i->tag,shape); swf_ShapeSetAll(i->tag,shape,UNDEFINED_COORD,UNDEFINED_COORD,0,fsid,0); i->swflastx = i->swflasty = UNDEFINED_COORD; - drawgfxline(dev, line); + drawgfxline(dev, line, 1); swf_ShapeSetEnd(i->tag); swf_ShapeFree(shape); @@ -2111,12 +2206,13 @@ static void drawoutline(gfxdevice_t*dev, gfxline_t*line) swf_SetU16(i->tag,myshapeid); SRECT r = gfxline_getSWFbbox(line); + r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); swf_SetShapeStyles(i->tag,shape); swf_ShapeCountBits(shape,NULL,NULL); swf_SetShapeBits(i->tag,shape); swf_ShapeSetAll(i->tag,shape,UNDEFINED_COORD,UNDEFINED_COORD,lsid,0,0); - drawgfxline(dev, line); + drawgfxline(dev, line, 1); swf_ShapeSetEnd(i->tag); swf_ShapeFree(shape); @@ -2154,6 +2250,7 @@ static void swf_startclip(gfxdevice_t*dev, gfxline_t*line) } swf_SetU16(i->tag,myshapeid); SRECT r = gfxline_getSWFbbox(line); + r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); swf_SetShapeStyles(i->tag,shape); swf_ShapeCountBits(shape,NULL,NULL); @@ -2161,7 +2258,7 @@ static void swf_startclip(gfxdevice_t*dev, gfxline_t*line) swf_ShapeSetAll(i->tag,shape,UNDEFINED_COORD,UNDEFINED_COORD,0,fsid,0); i->swflastx = i->swflasty = UNDEFINED_COORD; i->shapeisempty = 1; - drawgfxline(dev, line); + drawgfxline(dev, line, 1); if(i->shapeisempty) { /* an empty clip shape is equivalent to a shape with no area */ int x = line?line->x:0; @@ -2378,7 +2475,7 @@ static void swf_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcol swfoutput_setlinewidth(dev, width); startshape(dev); stopFill(dev); - drawgfxline(dev, line); + drawgfxline(dev, line, 0); if(i->config_normalize_polygon_positions) { free(line); //account for _move @@ -2417,8 +2514,7 @@ static void swf_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color) swfoutput_setfillcolor(dev, color->r, color->g, color->b, color->a); startshape(dev); startFill(dev); - i->fill=1; - drawgfxline(dev, line); + drawgfxline(dev, line, 1); if(i->currentswfid==2 && r.xmin==0 && r.ymin==0 && r.xmax==i->max_x && r.ymax==i->max_y) { if(i->config_watermark) { @@ -2488,13 +2584,14 @@ static void swf_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*grad int fsid = swf_ShapeAddGradientFillStyle(shape,&m,swfgradient,type==gfxgradient_radial); swf_SetU16(i->tag, myshapeid); SRECT r = gfxline_getSWFbbox(line); + r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); swf_SetShapeStyles(i->tag,shape); swf_ShapeCountBits(shape,NULL,NULL); swf_SetShapeBits(i->tag,shape); swf_ShapeSetAll(i->tag,shape,UNDEFINED_COORD,UNDEFINED_COORD,0,fsid,0); i->swflastx = i->swflasty = UNDEFINED_COORD; - drawgfxline(dev, line); + drawgfxline(dev, line, 1); swf_ShapeSetEnd(i->tag); swf_ShapeFree(shape); @@ -2515,7 +2612,7 @@ static SWFFONT* gfxfont_to_swffont(gfxfont_t*font, const char* id) swffont->version = 2; swffont->name = (U8*)strdup(id); swffont->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT)); - swffont->layout->ascent = 0; /* ? */ + swffont->layout->ascent = 0; swffont->layout->descent = 0; swffont->layout->leading = 0; swffont->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*font->num_glyphs); @@ -2583,17 +2680,21 @@ static SWFFONT* gfxfont_to_swffont(gfxfont_t*font, const char* id) swf_ExpandRect2(&bounds, &swffont->layout->bounds[t]); } - if(bounds.ymin < 0 && bounds.ymax > 0) { - swffont->layout->ascent = -bounds.ymin; - swffont->layout->descent = bounds.ymax; - swffont->layout->leading = bounds.ymax - bounds.ymin; - } else { - swffont->layout->ascent = (bounds.ymax - bounds.ymin)/2; - swffont->layout->descent = (bounds.ymax - bounds.ymin)/2; - swffont->layout->leading = bounds.ymax - bounds.ymin; - } - swffont->layout->descent= (bounds.ymax - bounds.ymin); - swffont->layout->ascent = 0; + + + /* Flash player will use the advance value from the char, and the ascent/descent values + from the layout for text selection. + ascent will extend the char into negative y direction, from the baseline, while descent + will extend in positive y direction, also from the baseline. + The baseline is defined as the y-position zero + */ + + swffont->layout->ascent = -bounds.ymin; + if(swffont->layout->ascent < 0) + swffont->layout->ascent = 0; + swffont->layout->descent = bounds.ymax; + if(swffont->layout->descent < 0) + swffont->layout->descent = 0; swffont->layout->leading = bounds.ymax - bounds.ymin; return swffont; @@ -2722,6 +2823,9 @@ static void swf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t* msg(" Moving character origin to %f %f\n", matrix->tx, matrix->ty); endtext(dev); setfontscale(dev, matrix->m00, matrix->m01, matrix->m10, matrix->m11, matrix->tx, matrix->ty, 1); + /* since we just moved the char origin to the current char's position, + it now has the relative position (0,0) */ + x = y = 0; } if(i->shapeid>=0)