From 275179c87d277416cfcc0d7a346ed60c4545ba31 Mon Sep 17 00:00:00 2001 From: Matthias Kramm Date: Mon, 26 Oct 2009 14:36:18 -0700 Subject: [PATCH] merged in fontalignzones branch --- lib/devices/swf.c | 153 ++++++---- lib/example/Makefile | 7 +- lib/example/alignzones.c | 245 ++++++++++++++++ lib/example/buttontest.c | 8 +- lib/example/hexfont.c | 4 +- lib/modules/swfaction.c | 6 +- lib/modules/swfdraw.c | 16 +- lib/modules/swfshape.c | 53 ++++ lib/modules/swftext.c | 720 ++++++++++++++++++++++++++++++++++------------ lib/rfxswf.c | 66 ++++- lib/rfxswf.h | 18 +- src/Makefile.in | 2 +- src/swfdump.c | 59 +++- src/swfextract.c | 4 +- 14 files changed, 1067 insertions(+), 294 deletions(-) create mode 100644 lib/example/alignzones.c diff --git a/lib/devices/swf.c b/lib/devices/swf.c index 4f691b6..42bb610 100644 --- a/lib/devices/swf.c +++ b/lib/devices/swf.c @@ -203,6 +203,8 @@ typedef struct _swfoutput_internal char* mark; } swfoutput_internal; + +static const int NO_FONT3=0; static void swf_fillbitmap(gfxdevice_t*driver, gfxline_t*line, gfximage_t*img, gfxmatrix_t*move, gfxcxform_t*cxform); static int swf_setparameter(gfxdevice_t*driver, const char*key, const char*value); @@ -537,7 +539,7 @@ static inline int colorcompare(RGBA*a,RGBA*b) return 1; } -static SRECT getcharacterbbox(chararray_t*chardata, MATRIX* m) +static SRECT getcharacterbbox(chararray_t*chardata, MATRIX* m, int flashversion) { SRECT r; char debug = 0; @@ -546,17 +548,19 @@ static SRECT getcharacterbbox(chararray_t*chardata, MATRIX* m) int t; if(debug) printf("\n"); + double div = 1.0 / 1024.0; + if(flashversion>=8 && !NO_FONT3) { + div = 1.0 / 20480.0; + } + 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 = floor((b.xmin*(double)chr->size) *div); + b.ymin = floor((b.ymin*(double)chr->size) *div); + b.xmax = ceil((b.xmax*(double)chr->size) *div); + b.ymax = ceil((b.ymax*(double)chr->size) *div); b.xmin += chr->x; b.ymin += chr->y; @@ -725,7 +729,7 @@ static void chararray_writetotag(chararray_t*_chardata, TAG*tag) newfont = &font; tag->writeBit = 0; // Q&D - swf_TextSetInfoRecord(tag, newfont, chr->size, newcolor, newx,newy); + swf_TextSetInfoRecord(tag, newfont, chr->size, newcolor, newx, newy); } lastfont = chr->font; @@ -814,7 +818,7 @@ static void chararray_writetodev(gfxdevice_t*dev, chararray_t*array, MATRIX*matr i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT2); swf_SetU16(i->tag, textid); SRECT r; - r = getcharacterbbox(array, matrix); + r = getcharacterbbox(array, matrix, i->config_flashversion); r = swf_ClipRect(i->pagebbox, r); swf_SetRect(i->tag,&r); swf_SetMatrix(i->tag, matrix); @@ -834,6 +838,8 @@ static void chararray_writetodev(gfxdevice_t*dev, chararray_t*array, MATRIX*matr swf_SetU32(i->tag, 0);//thickness swf_SetU32(i->tag, 0);//sharpness + //swf_SetU32(i->tag, 0x20000);//thickness + //swf_SetU32(i->tag, 0x800000);//sharpness swf_SetU8(i->tag, 0);//reserved } if(invisible && i->config_flashversion>=8) { @@ -865,45 +871,6 @@ static void endtext(gfxdevice_t*dev) i->textmode = 0; } -/* 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; - m12 *= 1024; - m21 *= 1024; - m22 *= 1024; - swfoutput_internal*i = (swfoutput_internal*)dev->internal; - if(i->lastfontm11 == m11 && - i->lastfontm12 == m12 && - i->lastfontm21 == m21 && - i->lastfontm22 == m22 && !force) - return; - if(i->textmode) - endtext(dev); - - i->lastfontm11 = m11; - i->lastfontm12 = m12; - i->lastfontm21 = m21; - i->lastfontm22 = m22; - - double xsize = sqrt(m11*m11 + m12*m12); - double ysize = sqrt(m21*m21 + m22*m22); - i->current_font_size = (xsize>ysize?xsize:ysize)*1; - if(i->current_font_size < 1) - i->current_font_size = 1; - double ifs = 1.0 / (i->current_font_size*GLYPH_SCALE); - - MATRIX m; - 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 */ - m.tx = x*20; - m.ty = y*20; - i->fontmatrix = m; -} - static int watermark2_width=47; static int watermark2_height=11; static int watermark2[47] = {95,1989,71,0,2015,337,1678,0,2015,5,1921,320,1938,25,2006,1024, @@ -1507,8 +1474,20 @@ void swfoutput_finalize(gfxdevice_t*dev) } int used = iterator->swffont->use && iterator->swffont->use->used_glyphs; if(used) { - mtag = swf_InsertTag(mtag, ST_DEFINEFONT2); - swf_FontSetDefine2(mtag, iterator->swffont); + if(i->config_flashversion<8 || NO_FONT3) { + mtag = swf_InsertTag(mtag, ST_DEFINEFONT2); + swf_FontSetDefine2(mtag, iterator->swffont); + } else { + mtag = swf_InsertTag(mtag, ST_DEFINEFONT3); + swf_FontSetDefine2(mtag, iterator->swffont); + + swf_FontCreateAlignZones(iterator->swffont); + + if(iterator->swffont->alignzones) { + mtag = swf_InsertTag(mtag, ST_DEFINEFONTALIGNZONES); + swf_FontSetAlignZones(mtag, iterator->swffont); + } + } } } @@ -2180,7 +2159,7 @@ int swf_setparameter(gfxdevice_t*dev, const char*name, const char*value) printf("linkcolor==7)\n"); + printf("enablezlib switch on zlib compression (also done if flashversion>=6)\n"); printf("bboxvars store the bounding box of the SWF file in actionscript variables\n"); printf("dots Take care to handle dots correctly\n"); printf("reordertags=0/1 (default: 1) perform some tag optimizations\n"); @@ -2810,13 +2789,13 @@ static void swf_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*grad swf_FreeGradient(swfgradient);free(swfgradient); } -static SWFFONT* gfxfont_to_swffont(gfxfont_t*font, const char* id) +static SWFFONT* gfxfont_to_swffont(gfxfont_t*font, const char* id, int version) { SWFFONT*swffont = (SWFFONT*)rfx_calloc(sizeof(SWFFONT)); int t; SRECT bounds = {0,0,0,0}; swffont->id = -1; - swffont->version = 2; + swffont->version = version; swffont->name = (U8*)strdup(id); swffont->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT)); swffont->layout->ascent = 0; @@ -2856,10 +2835,12 @@ static SWFFONT* gfxfont_to_swffont(gfxfont_t*font, const char* id) swf_Shape01DrawerInit(&draw, 0); line = font->glyphs[t].line; + const double scale = GLYPH_SCALE; while(line) { FPOINT c,to; - c.x = line->sx * GLYPH_SCALE; c.y = line->sy * GLYPH_SCALE; - to.x = line->x * GLYPH_SCALE; to.y = line->y * GLYPH_SCALE; + c.x = line->sx * scale; c.y = -line->sy * scale; + //to.x = floor(line->x * scale); to.y = floor(-line->y * scale); + to.x = line->x * scale; to.y = -line->y * scale; if(line->type == gfx_moveTo) { draw.moveTo(&draw, &to); } else if(line->type == gfx_lineTo) { @@ -2915,12 +2896,8 @@ static SWFFONT* gfxfont_to_swffont(gfxfont_t*font, const char* id) 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->ascent = bounds.ymin<0?-bounds.ymin:0; + swffont->layout->descent = bounds.ymax>0?bounds.ymax:0; swffont->layout->leading = bounds.ymax - bounds.ymin; /* if the font has proper ascent/descent values (>0) and those define @@ -2950,7 +2927,7 @@ static void swf_addfont(gfxdevice_t*dev, gfxfont_t*font) l = l->next; } l = (fontlist_t*)rfx_calloc(sizeof(fontlist_t)); - l->swffont = gfxfont_to_swffont(font, font->id); + l->swffont = gfxfont_to_swffont(font, font->id, (i->config_flashversion>=8 && !NO_FONT3)?3:2); l->next = 0; if(last) { last->next = l; @@ -3005,6 +2982,56 @@ static void swf_switchfont(gfxdevice_t*dev, const char*fontid) return; } +/* 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; + m12 *= 1024; + m21 *= 1024; + m22 *= 1024; + swfoutput_internal*i = (swfoutput_internal*)dev->internal; + if(i->lastfontm11 == m11 && + i->lastfontm12 == m12 && + i->lastfontm21 == m21 && + i->lastfontm22 == m22 && !force) + return; + if(i->textmode) + endtext(dev); + + i->lastfontm11 = m11; + i->lastfontm12 = m12; + i->lastfontm21 = m21; + i->lastfontm22 = m22; + + double xsize = sqrt(m11*m11 + m12*m12); + double ysize = sqrt(m21*m21 + m22*m22); + + int extrazoom = 1; + if(i->config_flashversion>=8 && !NO_FONT3) + extrazoom = 20; + + i->current_font_size = (xsize>ysize?xsize:ysize)*extrazoom; + if(i->current_font_size < 1) + i->current_font_size = 1; + + MATRIX m; + swf_GetMatrix(0, &m); + + if(m21 || m12 || fabs(m11+m22)>0.001) { + double ifs = (double)extrazoom/(i->current_font_size); + 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 */ + m.tx = x*20; + m.ty = y*20; + i->fontmatrix = m; +} + + static void swf_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix) { swfoutput_internal*i = (swfoutput_internal*)dev->internal; diff --git a/lib/example/Makefile b/lib/example/Makefile index 4f73cb0..f96acca 100644 --- a/lib/example/Makefile +++ b/lib/example/Makefile @@ -1,7 +1,7 @@ # Makefile RFXSWF = ../librfxswf.a ../libbase.a -LDLIBS = -L/usr/X11R6/lib -ljpeg -lm -lz -lX11 -lfreetype -lt1 +LDLIBS = -L/opt/local/lib/ -L/usr/X11R6/lib -ljpeg -lm -lz -lX11 -lfreetype -lt1 #CFLAGS = -funsigned-char CC = gcc CXX = g++ @@ -14,7 +14,7 @@ DBFLAGS = -g2 %.swf: % ./$< -all: sound jpegtest box shape1 transtest zlibtest sprites buttontest dumpfont text glyphshape edittext protect hexfont +all: alignzones.swf movies: sound.swf jpegtest.swf box.swf shape1.swf transtest.swf zlibtest.swf sprites.swf buttontest.swf dumpfont.swf text.swf glyphshape.swf edittext.swf @@ -51,6 +51,9 @@ transtest: $(RFXSWF) transtest.o $(RFXSWF) hexfont: $(RFXSWF) hexfont.o $(RFXSWF) $(CC) -o hexfont hexfont.o $(RFXSWF) $(LDLIBS) $(DBFLAGS) +alignzones: $(RFXSWF) alignzones.o $(RFXSWF) + $(CC) -o alignzones alignzones.o $(RFXSWF) $(LDLIBS) $(DBFLAGS) + text.o: demofont.c text: $(RFXSWF) text.o $(RFXSWF) $(CC) -o text text.o $(RFXSWF) $(LDLIBS) $(DBFLAGS) diff --git a/lib/example/alignzones.c b/lib/example/alignzones.c new file mode 100644 index 0000000..57ce262 --- /dev/null +++ b/lib/example/alignzones.c @@ -0,0 +1,245 @@ +/* hexfont.c + + Example for how to construct an SWF font from another SWF font. + + Part of the swftools package. + + Copyright (c) 2004 Matthias Kramm + + This file is distributed under the GPL, see file COPYING for details + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include "../rfxswf.h" + +static void write_font(SWFFONT * font, char *filename) +{ + SWF swf; + TAG *t; + SRECT r; + RGBA rgb; + int f; + int useDefineFont2 = 1; + int storeGlyphNames = 1; + +#define WRITEFONTID 8888 + font->id = WRITEFONTID; + + memset(&swf, 0x00, sizeof(SWF)); + + swf.fileVersion = 9; + swf.frameRate = 0x4000; + + t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR); + swf.firstTag = t; + rgb.r = 0xef; + rgb.g = 0xef; + rgb.b = 0xff; + swf_SetRGB(t, &rgb); + + t = swf_InsertTag(t, ST_DEFINEFONT3); + swf_FontSetDefine2(t, font); + + t = swf_InsertTag(t, ST_DEFINEFONTALIGNZONES); + swf_SetU16(t, font->id); + swf_SetU8(t, 0); //thin + int i; + for(i=0;i<256;i++) { + swf_SetU8(t, 2); + swf_SetF16(t, 82.0 / 1024.0); + swf_SetF16(t, 82.0 / 1024.0); + swf_SetF16(t, ((i%16/2)*82.0) / 1024.0); + swf_SetF16(t, ((i/16/2)*82.0) / 1024.0); + /* + if(i<128 && (i&15)<8) { + swf_SetF16(t, 0.0); + swf_SetF16(t, 0.0); + swf_SetF16(t, 640.0 / 1024.0); + swf_SetF16(t, 640.0 / 1024.0); + } else if(i<128 && (i&15)>=8) { + swf_SetF16(t, 0.0 / 1024.0); + swf_SetF16(t, 0.0 / 1024.0); + swf_SetF16(t, 330.0 / 1024.0); + swf_SetF16(t, 640.0 / 1024.0); + } else if(i>=128 && (i&15)<8) { + swf_SetF16(t, 0.0 / 1024.0); + swf_SetF16(t, 0.0 / 1024.0); + swf_SetF16(t, 640.0 / 1024.0); + swf_SetF16(t, 330.0 / 1024.0); + } else { + swf_SetF16(t, 0.0 / 1024.0); + swf_SetF16(t, 0.0 / 1024.0); + swf_SetF16(t, 330.0 / 1024.0); + swf_SetF16(t, 330.0 / 1024.0); + }*/ + swf_SetU8(t, 3); // x and y + } + + int s; + int xmax = 0; + int ymax = 0; + int ypos = 1; + U8 gbits, abits; + int x, y, c; + int range = font->maxascii; + + c = 0; + range = 256; + + xmax = 1280; + ymax = 1280*20; + + swf.movieSize.xmax = xmax * 20; + swf.movieSize.ymax = ymax; + + t = swf_InsertTag(t, ST_DEFINETEXT); + swf_SetU16(t, font->id + 1); // ID + r.xmin = 0; + r.ymin = 0; + r.xmax = swf.movieSize.xmax; + r.ymax = swf.movieSize.ymax; + swf_SetRect(t, &r); + swf_SetMatrix(t, NULL); + abits = swf_CountBits(xmax * 16, 0); + gbits = 8; + swf_SetU8(t, gbits); + swf_SetU8(t, abits); + + rgb.r = 0x00; + rgb.g = 0x00; + rgb.b = 0x00; + ypos = 2; + + int textscale = 1024; + for (y = 0; y < ((range + 15) / 16); y++) { + for (x = 0; x < 16; x++) { + //swf_TextSetInfoRecord(t, font, textscale, &rgb, x*64*20+64*20+10+(x+y)*20, y*64*20+128*20+10+(x^y)*20); + swf_TextSetInfoRecord(t, font, textscale, &rgb, x*64*20+64*20+10, y*64*20+128*20+10); + int g = y * 16 + x; + swf_SetU8(t, 1); + swf_SetBits(t, g, gbits); + swf_SetBits(t, 0, abits); + swf_ResetWriteBits(t); + } + } + swf_SetU8(t, 0); + + t = swf_InsertTag(t, ST_CSMTEXTSETTINGS); + swf_SetU16(t, font->id + 1); + swf_SetU8(t, (1<<3)//grid + |0x40//flashtype + ); + swf_SetU32(t, 0x20000);//thickness + swf_SetU32(t, 0x800000);//sharpness + swf_SetU8(t, 0);//reserved + + t = swf_InsertTag(t, ST_PLACEOBJECT2); + swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL); + + t = swf_InsertTag(t, ST_SHOWFRAME); + t = swf_InsertTag(t, ST_END); + + f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644); + if FAILED + (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n"); + close(f); + + swf_FreeTags(&swf); +} + + +int main() +{ + SWFFONT hexfont; + + memset(&hexfont, 0, sizeof(hexfont)); + hexfont.name = (U8*)"HexFont"; + hexfont.layout = malloc(sizeof(SWFLAYOUT)); + hexfont.numchars = 256; + hexfont.maxascii = 256; + hexfont.encoding = 32; + hexfont.glyph2ascii = malloc(sizeof(U16)*256); + hexfont.ascii2glyph = malloc(sizeof(int)*256); + hexfont.glyph = malloc(sizeof(SWFGLYPH)*256); + hexfont.glyphnames = malloc(sizeof(char*)*256); + hexfont.layout->bounds = malloc(sizeof(SRECT)*256); + hexfont.layout->kerningcount = 0; + hexfont.layout->kerning = 0; + int t; + int ymax =-0x7fffffff; + int ymin = 0x7fffffff; + for(t=0;t<256;t++) + { + drawer_t _draw,*draw=&_draw; + swf_Shape01DrawerInit(draw, 0); + int x,y; + FPOINT d; + int rx = 0;//t&15; + int ry = 0;//(t&15)^0x05; +#define S {d.x*=20*4+2;d.y*=20*4+2;} + if(1) { + for(x=0;x<8;x++) + for(y=0;y<8;y++) { + if((x^y)&1) { + d.x=x;d.y=-y; S;draw->moveTo(draw, &d); + d.x=x+1;d.y=-y; S;draw->lineTo(draw, &d); + d.x=x+1;d.y=-y-1; S;draw->lineTo(draw, &d); + d.x=x;d.y=-y-1; S;draw->lineTo(draw, &d); + d.x=x;d.y=-y; S;draw->lineTo(draw, &d); + } + } + } else { + d.x=0;d.y=-0; S;draw->moveTo(draw, &d); + d.x=0;d.y=-8; S;draw->lineTo(draw, &d); + d.x=8;d.y=-8; S;draw->lineTo(draw, &d); + d.x=8;d.y=-0; S;draw->lineTo(draw, &d); + d.x=0;d.y=-0; S;draw->lineTo(draw, &d); + + d.x=1;d.y=-1; S;draw->moveTo(draw, &d); + d.x=7;d.y=-1; S;draw->lineTo(draw, &d); + d.x=7;d.y=-7; S;draw->lineTo(draw, &d); + d.x=1;d.y=-7; S;draw->lineTo(draw, &d); + d.x=1;d.y=-1; S;draw->lineTo(draw, &d); + } + draw->finish(draw); + hexfont.glyph[t].shape = swf_ShapeDrawerToShape(draw); + hexfont.layout->bounds[t] = swf_ShapeDrawerGetBBox(draw); + hexfont.glyph[t].advance = hexfont.layout->bounds[t].xmax + hexfont.layout->bounds[t].xmin; + draw->dealloc(draw); + + hexfont.glyph2ascii[t] = t; + hexfont.ascii2glyph[t] = t; + hexfont.glyphnames[t] = 0; + if(hexfont.layout->bounds[t].ymax > ymax) + ymax = hexfont.layout->bounds[t].ymax; + if(hexfont.layout->bounds[t].ymin < ymin) + ymin = hexfont.layout->bounds[t].ymin; + + if(t>=0xe4) { + /* breaks flashtype, but not (non-flashtype) definefont2 */ + //hexfont.glyph2ascii[t] = 0; + } + } + hexfont.layout->ascent = ymin<0?-ymin:0; + hexfont.layout->descent = ymax>0?ymax:0; + hexfont.layout->leading = hexfont.layout->ascent + hexfont.layout->descent; + + write_font(&hexfont, "alignzones.swf"); + return 0; +} + diff --git a/lib/example/buttontest.c b/lib/example/buttontest.c index 76ba207..1823817 100644 --- a/lib/example/buttontest.c +++ b/lib/example/buttontest.c @@ -30,7 +30,7 @@ TAG* t; #define ID_BUTTON 31 -int useDefineButton2 = 0; // set this to 1 to use DefineButton2 Tags +int useDefineButton2 = 1; // set this to 1 to use DefineButton2 Tags // instead of DefineButton1 int main (int argc,char ** argv) @@ -46,7 +46,7 @@ int main (int argc,char ** argv) memset(&swf,0x00,sizeof(SWF)); // set global movie parameters - swf.fileVersion = 4; // make flash 4 compatible swf + swf.fileVersion = 8; // make flash 4 compatible swf swf.frameRate = 0x1900; // about 0x19 frames per second swf.movieSize.xmax = 20*width; // flash units: 1 pixel = 20 units @@ -116,8 +116,8 @@ int main (int argc,char ** argv) swf_ButtonSetRecord(t,BS_DOWN,36,1,NULL,NULL); swf_SetU8(t,0); // end of button records - swf_ButtonSetCondition(t, BC_OVERDOWN_OVERUP); - swf_ActionSet(t,actiontoset); + swf_ButtonSetCondition(t, BC_IDLE_OVERUP); + swf_ActionSet(t,actiontoset); swf_ButtonPostProcess(t, 1); // don't forget! } diff --git a/lib/example/hexfont.c b/lib/example/hexfont.c index bf5695b..1712112 100644 --- a/lib/example/hexfont.c +++ b/lib/example/hexfont.c @@ -30,11 +30,11 @@ int main() { char* hex = "0123456789ABCDEF"; - SWFFONT* font = swf_LoadFont("Courier.swf"); + SWFFONT* font = swf_LoadFont("../../doc/Courier.swf"); SWFFONT hexfont; memset(&hexfont, 0, sizeof(hexfont)); - hexfont.name = "HexFont"; + hexfont.name = (char*)"HexFont"; hexfont.layout = malloc(sizeof(SWFLAYOUT)); hexfont.numchars = 256; hexfont.maxascii = 256; diff --git a/lib/modules/swfaction.c b/lib/modules/swfaction.c index e16b3a4..fb7474d 100644 --- a/lib/modules/swfaction.c +++ b/lib/modules/swfaction.c @@ -182,7 +182,6 @@ ActionTAG* swf_ActionGet(TAG*tag) void swf_ActionFree(ActionTAG*action) { if(!action) { - fprintf(stderr, "Warning: freeing zero action"); return; } action = action->parent; @@ -208,9 +207,10 @@ void swf_ActionFree(ActionTAG*action) void swf_ActionSet(TAG*tag, ActionTAG*action) { - if(action) { - action=action->parent; + if(!action) { + return; } + action=action->parent; while(action) { swf_SetU8(tag, action->op); diff --git a/lib/modules/swfdraw.c b/lib/modules/swfdraw.c index 333fdb9..ae04aee 100644 --- a/lib/modules/swfdraw.c +++ b/lib/modules/swfdraw.c @@ -97,8 +97,8 @@ static void fixEndPoint(drawer_t*draw) static void swf_ShapeDrawerMoveTo(drawer_t*draw, FPOINT * to) { SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal; - int x = to->x*20+0.001; - int y = to->y*20+0.001; + int x = floor(to->x*20); + int y = floor(to->y*20); /* we need to write moveto always- it might be that it signals the end of a polygon, otherwise @@ -119,8 +119,8 @@ static void swf_ShapeDrawerMoveTo(drawer_t*draw, FPOINT * to) static void swf_ShapeDrawerLineTo(drawer_t*draw, FPOINT * to) { SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal; - int x = to->x*20+0.001; - int y = to->y*20+0.001; + int x = floor(to->x*20); + int y = floor(to->y*20); if(sdraw->lastx < sdraw->bbox.xmin) sdraw->bbox.xmin = sdraw->lastx; if(sdraw->lasty < sdraw->bbox.ymin) sdraw->bbox.ymin = sdraw->lasty; if(sdraw->lastx > sdraw->bbox.xmax) sdraw->bbox.xmax = sdraw->lastx; @@ -137,10 +137,10 @@ static void swf_ShapeDrawerLineTo(drawer_t*draw, FPOINT * to) static void swf_ShapeDrawerSplineTo(drawer_t*draw, FPOINT * c1, FPOINT* to) { SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal; - int tx = c1->x*20+0.001; - int ty = c1->y*20+0.001; - int x = to->x*20+0.001; - int y = to->y*20+0.001; + int tx = floor(c1->x*20); + int ty = floor(c1->y*20); + int x = floor(to->x*20); + int y = floor(to->y*20); if(sdraw->lastx < sdraw->bbox.xmin) sdraw->bbox.xmin = sdraw->lastx; if(sdraw->lasty < sdraw->bbox.ymin) sdraw->bbox.ymin = sdraw->lasty; if(sdraw->lastx > sdraw->bbox.xmax) sdraw->bbox.xmax = sdraw->lastx; diff --git a/lib/modules/swfshape.c b/lib/modules/swfshape.c index deb9b3a..afa069c 100644 --- a/lib/modules/swfshape.c +++ b/lib/modules/swfshape.c @@ -888,6 +888,59 @@ void swf_ShapeSetBitmapRect(TAG*tag, U16 gfxid, int width, int height) swf_ShapeFree(shape); } +void swf_ShapeSetRectangle(TAG*tag, U16 shapeid, int width, int height, RGBA*rgba) +{ + RGBA white={255,255,255,255}; + if(!rgba) { + rgba = &white; + } + SHAPE* s; + swf_ShapeNew(&s); + int fs = swf_ShapeAddSolidFillStyle(s, rgba); + swf_SetU16(tag,shapeid); + SRECT r; + r.xmin = 0; + r.xmax = 0; + r.ymin = width; + r.ymax = height; + swf_SetRect(tag,&r); + swf_SetShapeHeader(tag,s); + swf_ShapeSetAll(tag,s,0,0,0,fs,0); + swf_ShapeSetLine(tag,s,width,0); + swf_ShapeSetLine(tag,s,0,height); + swf_ShapeSetLine(tag,s,-width,0); + swf_ShapeSetLine(tag,s,0,-height); + swf_ShapeSetEnd(tag); + swf_ShapeFree(s); +} + +void swf_ShapeSetRectangleWithBorder(TAG*tag, U16 shapeid, int width, int height, RGBA*rgba, int linewidth, RGBA*linecolor) +{ + RGBA white={255,255,255,255}; + if(!rgba) { + rgba = &white; + } + SHAPE* s; + swf_ShapeNew(&s); + int fs = swf_ShapeAddSolidFillStyle(s, rgba); + int ls = swf_ShapeAddLineStyle(s, linewidth, linecolor); + swf_SetU16(tag,shapeid); + SRECT r; + r.xmin = 0; + r.xmax = 0; + r.ymin = width; + r.ymax = height; + swf_SetRect(tag,&r); + swf_SetShapeHeader(tag,s); + swf_ShapeSetAll(tag,s,0,0,ls,fs,0); + swf_ShapeSetLine(tag,s,width,0); + swf_ShapeSetLine(tag,s,0,height); + swf_ShapeSetLine(tag,s,-width,0); + swf_ShapeSetLine(tag,s,0,-height); + swf_ShapeSetEnd(tag); + swf_ShapeFree(s); +} + void swf_Shape2ToShape(SHAPE2*shape2, SHAPE*shape) { TAG*tag = swf_InsertTag(0,0); diff --git a/lib/modules/swftext.c b/lib/modules/swftext.c index 6bd59f0..912e8fa 100644 --- a/lib/modules/swftext.c +++ b/lib/modules/swftext.c @@ -113,7 +113,7 @@ int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*s n = 0; while (t) { - if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) { + if (swf_isFontTag(t)) { n++; if (FontCallback) { U16 id; @@ -373,6 +373,76 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag) return font->id; } +static float F16toFloat(U16 x) +{ + TAG t; + t.data = (void*)&x; + t.readBit = 0; + t.pos = 0; + t.len = 2; + return swf_GetF16(&t); +} + +static float floatToF16(float f) +{ + U16 u = 0; + TAG t; + t.data = (void*)&u; + t.len = 0; + t.memsize = 2; + t.writeBit = 0; + swf_SetF16(&t, f); + return u; +} + +int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag) +{ + U16 fid; + swf_SetTagPos(tag, 0); + fid = swf_GetU16(tag); + + if (fid == id) { + font->alignzone_flags = swf_GetU8(tag); + font->alignzones = rfx_calloc(sizeof(ALIGNZONE)*font->numchars); + int i=0; + while(tag->pos < tag->len) { + if(i>=font->numchars) + break; + int nr = swf_GetU8(tag); // should be 2 + if(nr!=1 && nr!=2) { + fprintf(stderr, "rfxswf: Can't parse alignzone tags with %d zones", nr); + break; + } + U16 x = swf_GetU16(tag); + U16 y = swf_GetU16(tag); + U16 dx = (nr==2)?swf_GetU16(tag):0xffff; + U16 dy = (nr==2)?swf_GetU16(tag):0xffff; + U8 xy = swf_GetU8(tag); + +#ifdef DEBUG_RFXSWF + if((!(xy&1) && (x!=0 || (dx!=0 && dx!=0xffff))) || + (!(xy&2) && (y!=0 || (dy!=0 && dy!=0xffff)))) { + fprintf(stderr, "Warning: weird combination of alignzone bits and values (%d x:%04x-%04x y:%04x-%04x)\n", xy, + x,dx,y,dy); + } +#endif + if(!(xy&1)) { + x = 0xffff; + dx = 0xffff; + } else if(!(xy&2)) { + y = 0xffff; + dy = 0xffff; + } + font->alignzones[i].x = x; + font->alignzones[i].y = y; + font->alignzones[i].dx = dx; + font->alignzones[i].dy = dy; + i++; + } + } + return id; +} + #define FEDTJ_PRINT 0x01 #define FEDTJ_MODIFY 0x02 @@ -502,6 +572,10 @@ int swf_FontExtract(SWF * swf, int id, SWFFONT * *font) nid = swf_FontExtract_DefineFont2(id, f, t); break; + case ST_DEFINEFONTALIGNZONES: + nid = swf_FontExtract_DefineFontAlignZones(id, f, t); + break; + case ST_DEFINEFONTINFO: case ST_DEFINEFONTINFO2: nid = swf_FontExtract_DefineFontInfo(id, f, t); @@ -1029,6 +1103,27 @@ int swf_FontSetDefine2(TAG * tag, SWFFONT * f) return 0; } +void swf_FontSetAlignZones(TAG*t, SWFFONT *f) +{ + swf_SetU16(t, f->id); + swf_SetU8(t, f->alignzone_flags); + int i; + for(i=0;inumchars;i++) { + ALIGNZONE*a = &f->alignzones[i]; + U8 flags = 0; + if((a->x & a->dx)!=0xffff) + flags |= 1; + if((a->y & a->dy)!=0xffff) + flags |= 2; + swf_SetU8(t, 2); + if(flags&1) swf_SetU16(t, a->x); else swf_SetU16(t, 0); + if(flags&2) swf_SetU16(t, a->y); else swf_SetU16(t, 0); + if((flags&1) && a->dx!=0xffff) swf_SetU16(t, a->dx); else swf_SetU16(t, 0); + if((flags&2) && a->dy!=0xffff) swf_SetU16(t, a->dy); else swf_SetU16(t, 0); + swf_SetU8(t, flags); + } +} + void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading) { f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT)); @@ -1348,183 +1443,6 @@ SWFFONT *swf_ReadFont(const char *filename) } } -void swf_WriteFont(SWFFONT * font, char *filename) -{ - SWF swf; - TAG *t; - SRECT r; - RGBA rgb; - int f; - int useDefineFont2 = 0; - int storeGlyphNames = 1; - - if (font->layout) - useDefineFont2 = 1; /* the only thing new in definefont2 - is layout information. */ - - font->id = WRITEFONTID; //"FN" - - memset(&swf, 0x00, sizeof(SWF)); - - swf.fileVersion = 9; - swf.frameRate = 0x4000; - - /* if we use DefineFont1 to store the characters, - we have to build a textfield to store the - advance values. While at it, we can also - make the whole .swf viewable */ - - /* we now always create viewable swfs, even if we - did use definefont2 -mk */ - t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR); - swf.firstTag = t; - rgb.r = 0xef; - rgb.g = 0xef; - rgb.b = 0xff; - swf_SetRGB(t, &rgb); - if (!useDefineFont2) { - t = swf_InsertTag(t, ST_DEFINEFONT); - swf_FontSetDefine(t, font); - t = swf_InsertTag(t, ST_DEFINEFONTINFO); - swf_FontSetInfo(t, font); - } else { - t = swf_InsertTag(t, ST_DEFINEFONT2); - swf_FontSetDefine2(t, font); - } - if(font->name) { - t = swf_InsertTag(t, ST_NAMECHARACTER); - swf_SetU16(t, WRITEFONTID); - swf_SetString(t, (char*)font->name); - t = swf_InsertTag(t, ST_EXPORTASSETS); - swf_SetU16(t, 1); - swf_SetU16(t, WRITEFONTID); - swf_SetString(t, (char*)font->name); - - t = swf_AddAS3FontDefine(t, WRITEFONTID, (char*)font->name); - } - - if (storeGlyphNames && font->glyphnames) { - int c; - t = swf_InsertTag(t, ST_GLYPHNAMES); - swf_SetU16(t, WRITEFONTID); - swf_SetU16(t, font->numchars); - for (c = 0; c < font->numchars; c++) { - if (font->glyphnames[c]) - swf_SetString(t, font->glyphnames[c]); - else - swf_SetString(t, ""); - } - } - - if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always - { - int textscale = 400; - int s; - int xmax = 0; - int ymax = 0; - int ypos = 1; - U8 gbits, abits; - int x, y, c; - int range = font->maxascii; - - c = 0; - if (useDefineFont2 && range > 256) { - range = 256; - } - - for (s = 0; s < range; s++) { - int g = font->ascii2glyph[s]; - if (g >= 0) { - if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) { - xmax = (font->glyph[g].advance * textscale / 20) / 64; - } - c++; - } - if ((s & 15) == 0) { - if (c) { - ypos++; - } - c = 0; - } - } - ymax = ypos * textscale * 2; - - swf.movieSize.xmax = xmax * 20; - swf.movieSize.ymax = ymax; - - t = swf_InsertTag(t, ST_DEFINETEXT); - - swf_SetU16(t, font->id + 1); // ID - - r.xmin = 0; - r.ymin = 0; - r.xmax = swf.movieSize.xmax; - r.ymax = swf.movieSize.ymax; - - swf_SetRect(t, &r); - - swf_SetMatrix(t, NULL); - - abits = swf_CountBits(xmax * 16, 0); - gbits = 8; - - swf_SetU8(t, gbits); - swf_SetU8(t, abits); - - rgb.r = 0x00; - rgb.g = 0x00; - rgb.b = 0x00; - ypos = 1; - for (y = 0; y < ((range + 15) / 16); y++) { - int c = 0, lastx = -1; - for (x = 0; x < 16; x++) { - int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1; - if (g >= 0 && font->glyph[g].shape) { - c++; - if (lastx < 0) - lastx = x * xmax; - } - } - if (c) { - swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2); - for (x = 0; x < 16; x++) { - int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1; - if (g >= 0 && font->glyph[g].shape) { - if (lastx != x * xmax) { - swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0); - } - swf_SetU8(t, 1); - swf_SetBits(t, g, gbits); - swf_SetBits(t, font->glyph[g].advance / 20, abits); - lastx = x * xmax + (font->glyph[g].advance / 20); - swf_ResetWriteBits(t); - } - } - ypos++; - } - } - swf_SetU8(t, 0); - - - t = swf_InsertTag(t, ST_PLACEOBJECT2); - - swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL); - - t = swf_InsertTag(t, ST_SHOWFRAME); - - } - - t = swf_InsertTag(t, ST_END); - - f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644); - if FAILED - (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n"); - close(f); - - swf_FreeTags(&swf); -} - - void swf_SetEditText(TAG * tag, U16 flags, SRECT r, const char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, const char *variable) { swf_SetRect(tag, &r); @@ -1629,10 +1547,11 @@ SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, } /* now set the text params- notice that a font size of - 1024 means that the glyphs will be displayed exactly - as they would be in/with a defineshape. (Try to find - *that* in the flash specs) + 1024 (or 1024*20 for definefont3) means that the glyphs will + be displayed exactly as they would be in/with a defineshape. + This is not documented in the specs. */ + /* set the actual text- notice that we just pass our scale parameter over, as TextSetCharRecord calculates with percent, too */ @@ -1657,8 +1576,8 @@ void swf_FontCreateLayout(SWFFONT * f) f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT)); f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT)); - f->layout->ascent = -32767; - f->layout->descent = -32767; + f->layout->ascent = 0; + f->layout->descent = 0; for (t = 0; t < f->numchars; t++) { SHAPE2 *shape2; @@ -1683,12 +1602,52 @@ void swf_FontCreateLayout(SWFFONT * f) f->glyph[t].advance = width; if (-bbox.ymin > f->layout->ascent) - f->layout->ascent = bbox.ymin; + f->layout->ascent = -bbox.ymin; if (bbox.ymax > f->layout->descent) f->layout->descent = bbox.ymax; } } +#define FONTALIGN_THIN +#define FONTALIGN_MEDIUM +#define FONTALIGN_THICK + +void swf_FontCreateAlignZones(SWFFONT * f) +{ + if(f->alignzones) + return; + + f->alignzones = (ALIGNZONE*)rfx_calloc(sizeof(ALIGNZONE)*f->numchars); + f->alignzone_flags = 0; // thin + + if(!f->layout) { + int t; + for(t=0;tnumchars;t++) { + // just align the baseline + f->alignzones[t].x = 0xffff; + f->alignzones[t].y = 0; + f->alignzones[t].dx = 0xffff; + f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0); + } + } else { + int t; + for(t=0;tnumchars;t++) { + // just align the baseline + f->alignzones[t].x = 0xffff; + f->alignzones[t].y = 0; + f->alignzones[t].dx = 0xffff; + f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0); + } + } + +/* + "-^_~\xad\xaf+`\xac\xb7\xf7" //chars for which to detect one y value + "#=:;\xb1" //chars for which to detect two y values + "\"\xa8" //chars for which to detect two x values +*/ +} + + void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text) { U8 *s = (U8 *) text; @@ -1731,3 +1690,396 @@ void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text) advance += font->glyph[g].advance * size / 100.0 / 20.0; } } + +void swf_WriteFont_AS3(SWFFONT * font, char *filename) +{ + if(!font->layout) + swf_FontCreateLayout(font); + + SWF swf; + memset(&swf, 0, sizeof(SWF)); + swf.fileVersion = 9; + swf.frameRate = 0x4000; + swf.movieSize.xmax = 200; + swf.movieSize.ymax = 200; + + if(!font->id) font->id=1; + + TAG *tag; + swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3); + swf_FontSetDefine2(tag, font); + + char*name = font->name?(char*)font->name:"font"; + + tag = swf_InsertTag(tag, ST_NAMECHARACTER); + swf_SetU16(tag, font->id); + swf_SetString(tag, name); + tag = swf_InsertTag(tag, ST_EXPORTASSETS); + swf_SetU16(tag, 1); + swf_SetU16(tag, font->id); + swf_SetString(tag, name); + tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name); + + tag = swf_InsertTag(tag, ST_END); + swf_SaveSWF(&swf, filename); + swf_FreeTags(&swf); +} + +void swf_WriteFont(SWFFONT * font, char *filename) +{ + if(!font->layout) + swf_FontCreateLayout(font); + + char viewer = 1; + U16 id = 1; + U16 depth = 1; + + font->id = id++; + + SWF swf; + memset(&swf, 0, sizeof(SWF)); + swf.fileVersion = 8; + swf.frameRate = 0x4000; + swf.movieSize.xmax = 1024*20; + swf.movieSize.ymax = 768*20; + + TAG *tag; + swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR); + swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff); + + tag = swf_InsertTag(tag, ST_DEFINEFONT3); + swf_FontSetDefine2(tag, font); + + if(font->glyphnames) { + int c; + tag = swf_InsertTag(tag, ST_GLYPHNAMES); + swf_SetU16(tag, font->id); + swf_SetU16(tag, font->numchars); + for (c = 0; c < font->numchars; c++) { + if (font->glyphnames[c]) + swf_SetString(tag, font->glyphnames[c]); + else + swf_SetString(tag, ""); + } + } + + if(viewer) + { + RGBA white = {255,255,255,255}; + RGBA black = {255,0,0,0}; + RGBA gray50 = {255,128,128,128}; + RGBA green = {255,0,255,0}; + int t; + SCOORD miny = SCOORD_MAX; + SCOORD maxy = SCOORD_MIN; + double width = 0; + U16 max_advance = 0; + char*flags = rfx_calloc(font->numchars); + double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1)); + double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1)); + int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1)); + for(t=0;tnumchars;t++) { + SHAPE*s = font->glyph[t].shape; + SHAPE2*s2 = swf_ShapeToShape2(s); + SRECT r = swf_GetShapeBoundingBox(s2); + + // inside a definefont3, everything is 20x the resolution: + double rx1 = r.xmin / 20.0; + double ry1 = r.ymin / 20.0; + double rx2 = r.xmax / 20.0; + double ry2 = r.ymax / 20.0; + + xmin[t]= rx1; + xmax[t]= rx2; + + if(ry1maxy) {maxy=ry2;} + swf_Shape2Free(s2);free(s2); + width += font->glyph[t].advance; + if(font->glyph[t].advance>max_advance) + max_advance = font->glyph[t].advance; + } + + if(miny==SCOORD_MAX) miny=maxy=0; + if(miny==maxy) maxy=miny+1; + + /* scale the font so that it's 256 pixels high */ + double scale = (int)((256.0*1024.0/(maxy-miny))*20.0); + double overlarge_factor; + int fontsize; + if(scale > 32767) { + fontsize = 32767; + overlarge_factor = scale / 32767.0; + } else { + fontsize = scale; + overlarge_factor = 1.0; + } + + int textid = id++; + int spriteid = id++; + SRECT r; + r.xmin = 0; + r.ymin = miny*fontsize/1024; + r.xmax = width*fontsize/20480; + r.ymax = maxy*fontsize/1024; + tag = swf_InsertTag(tag, ST_DEFINETEXT); + swf_SetU16(tag, textid); + swf_SetRect(tag, &r); + swf_SetMatrix(tag, NULL); + + U8 abits = 15; + U8 gbits = swf_CountBits(font->numchars, 0); + swf_SetU8(tag, gbits); + swf_SetU8(tag, abits); + + RGBA rgb = {255,0,0,0}; + + swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO); + ActionTAG*array = 0; + double x=0; + array = action_PushString(array, "xpos"); + for(t=0;tnumchars;t++) { + swf_SetU8(tag, 1); + int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60; + array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20); + x += width * overlarge_factor; + swf_SetBits(tag, t, gbits); + swf_SetBits(tag, width, abits); + swf_SetU8(tag, 128); + } + array = action_PushInt(array, x/20); + array = action_PushInt(array, font->numchars+1); + array = action_InitArray(array); + array = action_SetVariable(array); + swf_SetU8(tag, 0); + + if(font->layout) { + tag = swf_InsertTag(tag, ST_DEFINESHAPE2); + SHAPE* s; + swf_ShapeNew(&s); + int ls = swf_ShapeAddLineStyle(s,20,&white); + int shapeid = id++; + swf_SetU16(tag,shapeid); + SRECT r; + r.xmin = 0; + r.xmax = 1024*20; + r.ymin = 0; + r.ymax = 256*20; + swf_SetRect(tag,&r); + swf_SetShapeHeader(tag,s); + swf_ShapeSetAll(tag,s,0,0,ls,0,0); + + /* Ç and  are good chars to test ascent/descent extend */ + int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny); + int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny); + + swf_ShapeSetMove(tag,s,0,y1); + swf_ShapeSetLine(tag,s,width,0); + swf_ShapeSetMove(tag,s,0,y2); + swf_ShapeSetLine(tag,s,width,0); + + swf_ShapeSetEnd(tag); + swf_ShapeFree(s); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL); + } + + /* shapes */ + + for(t=0;tnumchars;t++) { + tag = swf_InsertTag(tag, ST_DEFINESHAPE2); + SHAPE* s; + swf_ShapeNew(&s); + int ls = swf_ShapeAddLineStyle(s,20*2,&black); + int ls2 = swf_ShapeAddLineStyle(s,20*2,&green); + int fs = swf_ShapeAddSolidFillStyle(s, &gray50); + int shapeid = id++; + swf_SetU16(tag,shapeid); + SRECT r; + r.xmin = 0; + r.xmax = 1024*20; + r.ymin = 0; + r.ymax = 512*20; + swf_SetRect(tag,&r); + swf_SetShapeHeader(tag,s); + swf_ShapeSetAll(tag,s,0,0,ls,fs,0); + SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape); + SHAPELINE*l = s2->lines; + int lastx=0,lasty=0; + + double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2; + double y1 = -miny*20*scale*2/20480.0; + double scalex = scale*2/20480.0; + double scaley = scale*2/20480.0; + + while(l) { + int lx = (l->x)*scalex+x1; + int ly = (l->y)*scaley+y1; + int sx = (l->sx)*scalex+x1; + int sy = (l->sy)*scaley+y1; + if(l->type == moveTo) { + swf_ShapeSetMove(tag,s,lx,ly); + } else if(l->type == lineTo) { + swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty); + } else if(l->type == splineTo) { + swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy); + } + lastx = lx; + lasty = ly; + l = l->next; + } + + if(font->alignzones) { + ALIGNZONE*zone = &font->alignzones[t]; + swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO); + if((zone->x&zone->dx)!=0xffff) { + double x = F16toFloat(zone->x)*20480.0*scalex+x1; + double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1; + swf_ShapeSetMove(tag,s,x,0); + swf_ShapeSetLine(tag,s,0,1024*20); + swf_ShapeSetMove(tag,s,dx,0); + swf_ShapeSetLine(tag,s,0,1024*20); + } + if((zone->y&zone->dy)!=0xffff) { + double y = -F16toFloat(zone->y)*20480.0*scaley+y1; + double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1; + swf_ShapeSetMove(tag,s,0,y); + swf_ShapeSetLine(tag,s,1024*20,0); + swf_ShapeSetMove(tag,s,0,dy); + swf_ShapeSetLine(tag,s,1024*20,0); + } + } + + swf_ShapeSetEnd(tag); + swf_ShapeFree(s); + + tag = swf_InsertTag(tag, ST_DEFINESPRITE); + U16 spriteid=id++; + swf_SetU16(tag, spriteid); + swf_SetU16(tag, 1); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL); + tag = swf_InsertTag(tag, ST_END); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + MATRIX m; + swf_GetMatrix(0, &m); + m.ty = 20000; + char txt[80]; + sprintf(txt, "char%d", font->numchars-t); + swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt); + } + + /* marker */ + tag = swf_InsertTag(tag, ST_DEFINESHAPE2); + int shapeid=id++; + RGBA blue = {0xff,0xc0,0xc0,0xff}; + swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue); + tag = swf_InsertTag(tag, ST_DEFINESPRITE); + U16 spriteid2=id++; + swf_SetU16(tag, spriteid2); + swf_SetU16(tag, 1); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL); + tag = swf_InsertTag(tag, ST_END); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker"); + + /* textbar */ + tag = swf_InsertTag(tag, ST_DEFINESPRITE); + swf_SetU16(tag, spriteid); + swf_SetU16(tag, 1); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + MATRIX m; + swf_GetMatrix(0, &m); + m.sx = 65536 * overlarge_factor; + m.sy = 65536 * overlarge_factor; + m.tx = 0; + m.ty = -miny*256*20/(maxy-miny); + swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL); + tag = swf_InsertTag(tag, ST_END); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar"); + + /* marker2 */ + RGBA blue2 = {0x80,0x80,0xff,0x80}; + tag = swf_InsertTag(tag, ST_DEFINESHAPE3); + int shapeid2=id++; + swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white); + tag = swf_InsertTag(tag, ST_DEFINESPRITE); + U16 spriteid3=id++; + swf_SetU16(tag, spriteid3); + swf_SetU16(tag, 1); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL); + tag = swf_InsertTag(tag, ST_END); + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2"); + + +char*data = +" var mouseListener = new Object();" +" var speed = 0;" +" var myx = 0;" +" var currentMouseOver, currentChar;" +" mouseListener.onMouseDown = function() { " +" eval(\"_root.char\"+currentChar)._y = 20000;" +" currentChar = currentMouseOver;" +" var i = currentMouseOver;" +" eval(\"_root.char\"+i)._y = 256;" +" _root.marker2._yscale=256*100;" +" _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;" +" _root.marker2._x=xpos[i]+myx;" +" };" +" mouseListener.onMouseMove = function() { " +" if(_ymouse<256) {" +" speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;" +" } else {" +" speed = 0;" +" }; " +" }; " +" setInterval( function(){ " +" if(_ymouse<256) {" +" var i, x=_xmouse-_root.textbar._x;" +" for(i=xpos.length-1;i>0;i--) {" +" if(x0) {" +" speed=0;" +" } else if(myx+speed<-xpos[0]+1024) {" +" speed=0;" +" }" +" myx+=speed;" +" _root.textbar._x = myx;" +" _root.marker._x += speed;" +" _root.marker2._x += speed;" +" }, 20);" +" Mouse.addListener(mouseListener);" +; + ActionTAG* atag = swf_ActionCompile(data, 6); + + tag = swf_InsertTag(tag, ST_DOACTION); + swf_ActionSet(tag, array); + swf_ActionSet(tag, atag); + swf_SetU8(tag, 0); + swf_ActionFree(atag); + + tag = swf_InsertTag(tag, ST_SHOWFRAME); + + free(flags); + free(xmin); + free(xmax); + } + + tag = swf_InsertTag(tag, ST_END); + + swf.compressed = -1; + swf_SaveSWF(&swf, filename); + swf_FreeTags(&swf); +} + diff --git a/lib/rfxswf.c b/lib/rfxswf.c index 2b46f53..025bcaf 100644 --- a/lib/rfxswf.c +++ b/lib/rfxswf.c @@ -95,6 +95,7 @@ U8 swf_GetU8(TAG * t) #ifdef DEBUG_RFXSWF if ((int)t->pos>=(int)t->len) { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id); + *(int*)0=0; return 0; } #endif @@ -408,32 +409,69 @@ int swf_SetU30String(TAG*tag, const char*str, int l) swf_SetBlock(tag, (void*)str, l); return len; } + float swf_GetF16(TAG * t) { - // D16 is 1-5-10 - // D32 is 1-8-23 U16 f1 = swf_GetU16(t); - if(!f1) return 0; - U32 f2 = (f1&0x8000)<<16; //sign - f2 |= ((f1&0x7c00)<<13)+(0x40000000-(0x4000<<13)); //exp - f2 |= (f1&0x03ff)<<13; //mantissa + if(!(f1&0x3ff)) return 0.0; + + // IEEE 16 is 1-5-10 + // IEEE 32 is 1-8-23 + /* gcc 4.1.2 seems to require a union here. *(float*)u doesn't work */ + union { + U32 u; + float f; + } f2; + + U16 e = (f1>>10)&0x1f; + U16 m = f1&0x3ff; + /* find highest bit in mantissa */ + int h=0; + while(!(m&0x400)) { + m<<=1; + h++; + } + m&=0x3ff; + e -= h; + e += 0x6f; + + f2.u = (f1&0x8000)<<16; //sign + f2.u |= e<<23; //exponent + f2.u |= m<<13; //mantissa return *(float*)&f2; } + void swf_SetF16(TAG * t, float f) { - U32 f1 = *(U32*)&f; - U16 f2 = (f1>>16)&0x8000; - int exp = ((f1>>23)&0xff)-0x80+0x10; - if(exp<0) { + union { + U32 u; + float f; + } v; + v.f = f; + + U16 result = (v.u>>16)&0x8000; //sign + int exp = ((v.u>>23)&0xff)-0x7f+0x10; + U16 m = (v.u>>13)&0x3ff; + //fprintf(stderr, "%f: %04x sign, %d exp, %04x mantissa\n", f, result, exp, m); + if(exp<-10) { + // underflow (clamp to 0.0) + exp = 0; + m = 0; + } else if(exp<0) { + // partial underflow- strip some bits + m = (m|0x400)>>-exp; exp = 0; - fprintf(stderr, "Exponent underflow in FLOAT16 encoding\n"); } else if(exp>=32) { exp = 31; + m = 0x3ff; fprintf(stderr, "Exponent overflow in FLOAT16 encoding\n"); + } else { + exp++; + m = (m>>1)|0x200; } - f2 |= exp<<10; - f2 |= (f1>>13)&0x3ff; - swf_SetU16(t, f2); + result |= exp<<10; + result |= m; + swf_SetU16(t, result); } double swf_GetD64(TAG*tag) diff --git a/lib/rfxswf.h b/lib/rfxswf.h index a3420c9..f586849 100644 --- a/lib/rfxswf.h +++ b/lib/rfxswf.h @@ -475,6 +475,8 @@ int swf_SetFillStyle(TAG * t,FILLSTYLE * f); int swf_SetLineStyle(TAG * t,LINESTYLE * l); +void swf_ShapeSetRectangle(TAG*tag, U16 shapeid, int width, int height, RGBA*rgba); +void swf_ShapeSetRectangleWithBorder(TAG*tag, U16 shapeid, int width, int height, RGBA*rgba, int linewidth, RGBA*linecolor); void swf_ShapeSetBitmapRect(TAG * t, U16 gfxid, int width, int height); //SHAPELINE* swf_ParseShapeData(U8*data, int bits, int fillbits, int linebits); @@ -512,8 +514,8 @@ typedef struct _KERNING } SWFKERNING; typedef struct _SWFLAYOUT -{ S16 ascent; - S16 descent; +{ U16 ascent; + U16 descent; S16 leading; SRECT * bounds; U16 kerningcount; @@ -538,6 +540,12 @@ typedef struct _FONTUSAGE #define FONT_ENCODING_ANSI 2 #define FONT_ENCODING_SHIFTJIS 4 +typedef struct _ALIGNZONE +{ + U16 x,y; + U16 dx,dy; +} ALIGNZONE; + typedef struct _SWFFONT { int id; // -1 = not set U8 version; // 0 = not set, 1 = definefont, 2 = definefont2 @@ -552,6 +560,8 @@ typedef struct _SWFFONT U16 * glyph2ascii; int * ascii2glyph; SWFGLYPH * glyph; + ALIGNZONE * alignzones; + U8 alignzone_flags; U8 language; char ** glyphnames; @@ -601,6 +611,8 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag); int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t); int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t); int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag); +int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag); + int swf_FontIsItalic(SWFFONT * f); int swf_FontIsBold(SWFFONT * f); @@ -618,8 +630,10 @@ int swf_FontUse(SWFFONT* f,U8 * s); int swf_FontSetDefine(TAG * t,SWFFONT * f); int swf_FontSetDefine2(TAG * t,SWFFONT * f); int swf_FontSetInfo(TAG * t,SWFFONT * f); +void swf_FontSetAlignZones(TAG*t, SWFFONT *f); void swf_FontCreateLayout(SWFFONT*f); +void swf_FontCreateAlignZones(SWFFONT * f); void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading); int swf_ParseDefineText(TAG * t, void(*callback)(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA* color), void*self); diff --git a/src/Makefile.in b/src/Makefile.in index 6ef23d1..86cf573 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -53,7 +53,7 @@ swfc-interpolation.$(O): swfc-interpolation.c swfc-interpolation.h ../lib/q.h parser.$(O): parser.yy.c parser.h ../lib/q.h $(C) parser.yy.c -o $@ -../lib/librfxswf$(A): ../lib/modules/swfrender.c ../lib/modules/swfshape.c ../lib/modules/swfbits.c ../lib/rfxswf.c +../lib/librfxswf$(A): ../lib/modules/swfrender.c ../lib/modules/swfshape.c ../lib/modules/swftext.c ../lib/modules/swffont.c ../lib/modules/swfbits.c ../lib/rfxswf.c ../lib/devices/swf.c cd ../lib;$(MAKE) librfxswf$(A);cd - # TODO: include the following rule only if lex is available diff --git a/src/swfdump.c b/src/swfdump.c index 3df34df..acc1806 100644 --- a/src/swfdump.c +++ b/src/swfdump.c @@ -323,7 +323,10 @@ void dumpFont(TAG*tag, char*prefix) int t; for(t=0;tnumchars;t++) { int u = font->glyph2ascii?font->glyph2ascii[t]:-1; - printf("%s== Glyph %d: advance=%d encoding=%d ==\n", prefix, t, font->glyph[t].advance, u); + char ustr[16]; + if(u>=32) sprintf(ustr, " '%c'", u); + else sprintf(ustr, " 0x%02x", u); + printf("%s== Glyph %d: advance=%d encoding=%d%s ==\n", prefix, t, font->glyph[t].advance, u, ustr); SHAPE2* shape = swf_ShapeToShape2(font->glyph[t].shape); SHAPELINE*line = shape->lines; @@ -379,10 +382,12 @@ static SWF swf; static int fontnum = 0; static SWFFONT**fonts; -void textcallback(void*self, int*glyphs, int*ypos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color) +void textcallback(void*self, int*glyphs, int*xpos, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color) { int font=-1,t; - printf(" <%2d glyphs in font %2d size %d, color #%02x%02x%02x%02x> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a); + if(nr<1) + return; + printf(" <%2d glyphs in font %04d size %d, color #%02x%02x%02x%02x at %.2f,%.2f> ",nr, fontid, fontsize, color->r, color->g, color->b, color->a, (startx+xpos[0])/20.0, starty/20.0); for(t=0;tid == fontid) { @@ -990,25 +995,63 @@ static void handleFontAlign1(TAG*tag) printf(" %d glyphs", num); } +#define ALIGN_WITH_GLYPHS static void handleFontAlign2(TAG*tag, char*prefix) { if(!showfonts) return; swf_SetTagPos(tag, 0); - swf_GetU16(tag); + U16 id = swf_GetU16(tag); swf_GetU8(tag); int num = 0; +#ifdef ALIGN_WITH_GLYPHS + SWF swf; + swf.firstTag = tag; + while(swf.firstTag->prev) swf.firstTag = swf.firstTag->prev; + SWFFONT* font = 0; + swf_FontExtract(&swf, id, &font); +#endif + swf_SetTagPos(tag, 3); while(tag->pos < tag->len) { - printf("%sglyph %d) ", prefix, num++); + printf("%sglyph %d) ", prefix, num); int nr = swf_GetU8(tag); // should be 2 int t; for(t=0;tnumchars) { + SHAPE2* shape = swf_ShapeToShape2(font->glyph[num].shape); + SHAPELINE*line = shape->lines; + while(line) { + if(line->type == moveTo) { + printf("%smoveTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0); + } else if(line->type == lineTo) { + printf("%slineTo %.2f %.2f\n", prefix, line->x/20.0, line->y/20.0); + } else if(line->type == splineTo) { + printf("%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix, + line->sx/20.0, line->sy/20.0, + line->x/20.0, line->y/20.0 + ); + } + line = line->next; + } + swf_Shape2Free(shape); + free(shape); + } + if(num==font->numchars-1) break; +#endif + num++; } } diff --git a/src/swfextract.c b/src/swfextract.c index 3550731..4eeca60 100644 --- a/src/swfextract.c +++ b/src/swfextract.c @@ -483,7 +483,7 @@ int isOfType(int t, TAG*tag) if(t == 4 && (tag->id == ST_DEFINESOUND)) { show = 1; } - if(t == 5 && (tag->id == ST_DEFINEFONT || tag->id == ST_DEFINEFONT2)) { + if(t == 5 && (tag->id == ST_DEFINEFONT || tag->id == ST_DEFINEFONT2 || tag->id == ST_DEFINEFONT3)) { show = 1; } return show; @@ -586,8 +586,6 @@ void handlefont(SWF*swf, TAG*tag) printf("Couldn't extract font %d\n", id); return; } - if(!f->layout) - swf_FontCreateLayout(f); swf_WriteFont(f, filename); swf_FontFree(f); -- 1.7.10.4