X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fmodules%2Fswftext.c;h=21382756aac8db56566d85e176c88957dab413a8;hb=b69fc4379deedfda6a8ccca568c6bebcf1433150;hp=e5901cb146997579e0da21f13aee042137655c82;hpb=8ff8aea6d9d76a443ab2391671af79e91f780bbc;p=swftools.git diff --git a/lib/modules/swftext.c b/lib/modules/swftext.c index e5901cb..2138275 100644 --- a/lib/modules/swftext.c +++ b/lib/modules/swftext.c @@ -6,10 +6,65 @@ Part of the swftools package. Copyright (c) 2001 Rainer Böhme + Copyright (c) 2003,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 */ + +static U32 readUTF8char(U8**text) +{ + U32 c = 0; + if(!(*(*text) & 0x80)) + return *((*text)++); + + /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */ + if(((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) + { + c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f); + (*text) += 2; + return c; + } + /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */ + if(((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) + { + c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f); + (*text) += 3; + return c; + } + /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if(((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2] && (*text)[3] ) + { + c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f)<<6 | ((*text)[3] & 0x3f); + (*text) += 4; + return c; + } + /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if(((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4]) + { + c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f)<<12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f); + (*text) += 5; + return c; + } + /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */ + if(((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4] && (*text)[5]) + { + c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 | ((*text)[2] & 0x3f)<<18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6; + (*text) += 6; + return c; + } + return *((*text)++); +} #define TF_TEXTCONTROL 0x80 #define TF_HASFONT 0x08 @@ -46,22 +101,26 @@ int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*)) n = 0; while (t) - { if (swf_GetTagID(t)==ST_DEFINEFONTINFO || - swf_GetTagID(t)==ST_DEFINEFONT2) + { + if (swf_GetTagID(t)==ST_DEFINEFONT2 || swf_GetTagID(t)==ST_DEFINEFONT) { n++; if (FontCallback) { U16 id; int l; U8 s[257]; + s[0] = 0; swf_SaveTagPos(t); swf_SetTagPos(t,0); id = swf_GetU16(t); - if(swf_GetTagID(t) == ST_DEFINEFONT2) + if(swf_GetTagID(t) == ST_DEFINEFONT2 || + swf_GetTagID(t) == ST_DEFINEFONTINFO || + swf_GetTagID(t) == ST_DEFINEFONTINFO2) { swf_GetU16(t); - l = swf_GetU8(t); - swf_GetBlock(t,s,l); - s[l] = 0; + l = swf_GetU8(t); + swf_GetBlock(t,s,l); + s[l] = 0; + } (FontCallback)(id,s); @@ -80,7 +139,7 @@ int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t) fid = swf_GetU16(t); if ((!id)||(id==fid)) - { U16 of,*ofs; + { U16 of; int n,i; id = fid; @@ -114,23 +173,18 @@ int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t) int i; if(f->version>1) { - // DefineFont2 doesn't have FontInfo fields - fprintf(stderr, "fixme: FontInfo field for DefineFont2 encountered\n"); - return -1; + /* Especially with Flash MX, DefineFont2 may have FontInfo fields, + too. However, they only add little information to what's already + inside the DefineFont2 tag */ + return id; } - if (l) - { if (f->name) free(f->name); - f->name = (U8*)malloc(l+1); - if (f->name) - { swf_GetBlock(t,f->name,l); - f->name[l] = 0; - } - else - { swf_RestoreTagPos(t); - return -1; - } - } + if (f->name) free(f->name); + + f->name = (U8*)malloc(l+1); + swf_GetBlock(t,f->name,l); + f->name[l] = 0; + flags = swf_GetU8(t); if(flags & 2) f->style |= FONT_STYLE_BOLD; @@ -143,6 +197,10 @@ int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t) if(flags & 32) f->encoding |= FONT_ENCODING_UNICODE; + if(t->id == ST_DEFINEFONTINFO2) { + f->language = swf_GetU8(t); + } + f->glyph2ascii = (U16*)malloc(sizeof(U16)*f->numchars); maxcode = 0; for(i=0; i < f->numchars; i++) { @@ -165,6 +223,31 @@ int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t) return id; } +int swf_FontExtract_GlyphNames(int id,SWFFONT * f,TAG * tag) +{ + U16 fid; + U16 maxcode; + U8 flags; + swf_SaveTagPos(tag); + swf_SetTagPos(tag,0); + + fid = swf_GetU16(tag); + + if (fid==id) + { + int num = swf_GetU16(tag); + int t; + f->glyphnames = malloc(sizeof(char*)*num); + for(t=0;tglyphnames[t] = strdup(swf_GetString(tag)); + } + } + + swf_RestoreTagPos(tag); + return id; +} + + int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag) { int t, glyphcount; @@ -208,11 +291,15 @@ int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag) if(flags1&8) { // wide offsets for(t=0;tglyph[t].shape)); @@ -252,10 +339,12 @@ int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag) font->layout->bounds = malloc(glyphcount*sizeof(SRECT)); for(t=0;tlayout->bounds); + swf_GetRect(tag, &font->layout->bounds[t]); } + kerningcount = swf_GetU16(tag); font->layout->kerningcount = kerningcount; + font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount); if(kerningcount) { font->layout->kerning = @@ -282,15 +371,18 @@ int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag) #define FEDTJ_MODIFY 0x02 #define FEDTJ_CALLBACK 0x04 -int swf_FontExtract_DefineTextCallback(int id,SWFFONT * f,TAG * t,int jobs, - void(*callback)(int*chars, int nr, int fontid)) +static int swf_FontExtract_DefineTextCallback(int id,SWFFONT * f,TAG * t,int jobs, + void(*callback)(void*self, int*chars, int*ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA* color), void*self) { U16 cid; SRECT r; MATRIX m; - U8 gbits, abits, flags; - int fid; + U8 gbits, abits; + int fid=0; + RGBA color; + int x=0,y=0; + int fontsize=0; - fid = 0; + memset(&color, 0, sizeof(color)); swf_SaveTagPos(t); swf_SetTagPos(t,0); @@ -301,53 +393,77 @@ int swf_FontExtract_DefineTextCallback(int id,SWFFONT * f,TAG * t,int jobs, gbits = swf_GetU8(t); abits = swf_GetU8(t); - flags = swf_GetU8(t); + while(1) + { + int flags,num; + flags = swf_GetU8(t); + if(!flags) + break; - while(flags) - { if (flags&TF_TEXTCONTROL) + if (flags&TF_TEXTCONTROL) { if (flags&TF_HASFONT) fid = swf_GetU16(t); if (flags&TF_HASCOLOR) - { swf_GetU8(t); // rgb - swf_GetU8(t); - swf_GetU8(t); - if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_GetU8(t); + { color.r = swf_GetU8(t); // rgb + color.g = swf_GetU8(t); + color.b = swf_GetU8(t); + if (swf_GetTagID(t)==ST_DEFINETEXT2) color.a = swf_GetU8(t); } - if (flags&TF_HASXOFFSET) swf_GetS16(t); - if (flags&TF_HASYOFFSET) swf_GetS16(t); - if (flags&TF_HASFONT) swf_GetU16(t); + if (flags&TF_HASXOFFSET) x = swf_GetS16(t); + if (flags&TF_HASYOFFSET) y = swf_GetS16(t); + if (flags&TF_HASFONT) fontsize = swf_GetU16(t); } - else + + num = swf_GetU8(t); + if(!num) + break; + { int i; int buf[256]; - for (i=0;i + if (id==fid) { if (jobs&FEDTJ_PRINT) { - { int code = f->glyph2ascii[glyph]; + int code = f->glyph2ascii[glyph]; printf("%c",code); } if (jobs&FEDTJ_MODIFY) - /*if (!f->glyph[code].advance)*/ f->glyph[glyph].advance = adv; - } + f->glyph[glyph].advance = adv*20; //? + } else { + if (jobs&FEDTJ_PRINT) { + printf("?"); + } + } + // + buf[i] = glyph; } if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n"); if (jobs&FEDTJ_CALLBACK) - callback(buf, flags, fid); + callback(self, buf, advance, num, fid, fontsize, x, y, &color); + x += xpos; } - flags = swf_GetU8(t); } swf_RestoreTagPos(t); return id; } +int swf_ParseDefineText(TAG * tag, void(*callback)(void*self, int*chars, int*ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA* color), void*self) +{ + return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self); +} int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs) { - return swf_FontExtract_DefineTextCallback(id,f,t,jobs,0); + return swf_FontExtract_DefineTextCallback(id,f,t,jobs,0,0); } int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) @@ -356,9 +472,7 @@ int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) if ((!swf)||(!font)) return -1; - f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f; - if (!f) return -1; - + f = (SWFFONT *)malloc(sizeof(SWFFONT)); memset(f,0x00,sizeof(SWFFONT)); t = swf->firstTag; @@ -375,6 +489,7 @@ int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) break; case ST_DEFINEFONTINFO: + case ST_DEFINEFONTINFO2: nid = swf_FontExtract_DefineFontInfo(id,f,t); break; @@ -382,23 +497,32 @@ int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) case ST_DEFINETEXT2: nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY); break; + + case ST_GLYPHNAMES: + nid = swf_FontExtract_GlyphNames(id,f,t); + break; } if (nid>0) id = nid; t = swf_NextTag(t); } + if(f->id != id) { + free(f); + f=0; + } + font[0] = f; return 0; } int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; } int swf_FontReduce(SWFFONT * f,FONTUSAGE * use) -{ int i,j,num; +{ int i,j; if ((!f)||(!use)) return -1; j = 0; for (i=0;inumchars;i++) if (f->glyph[i].shape) - { if (f->glyph2ascii[i]glyph2ascii[i]maxascii&& use->code[f->glyph2ascii[i]]) { f->ascii2glyph[f->glyph2ascii[i]] = j; f->glyph2ascii[j] = f->glyph2ascii[i]; @@ -419,13 +543,19 @@ int swf_FontReduce(SWFFONT * f,FONTUSAGE * use) return j; } -int swf_FontInitUsage(FONTUSAGE * use) +int swf_FontInitUsage(SWFFONT* f, FONTUSAGE * use) { if (!use) return -1; - memset(use->code,0,sizeof(use->code[0])*MAX_CHAR_PER_FONT); + use->code = malloc(sizeof(use->code[0])*f->maxascii); + memset(use->code,0,sizeof(use->code[0])*f->maxascii); return 0; } -int swf_FontUse(FONTUSAGE * use,U8 * s) +void swf_FontClearUsage(SWFFONT* f, FONTUSAGE * use) +{ if (!use) return; + free(use->code); +} + +int swf_FontUse(SWFFONT*f, FONTUSAGE * use,U8 * s) { if ((!use)||(!s)) return -1; while (s[0]) { use->code[s[0]] = 1; @@ -450,6 +580,10 @@ int swf_FontSetDefine(TAG * t,SWFFONT * f) } for (i=0;inumchars;i++) if (f->glyph[i].shape) @@ -460,6 +594,17 @@ int swf_FontSetDefine(TAG * t,SWFFONT * f) return 0; } +static inline int fontSize(SWFFONT*font) +{ + int t; + int size = 0; + for(t=0;tnumchars;t++) { + int l = (font->glyph[t].shape->bitlen+7)/8; + size += l+1; + } + return size + (font->numchars+1)*2; +} + int swf_FontSetDefine2(TAG *tag, SWFFONT * f) { U8 flags = 0; @@ -467,6 +612,7 @@ int swf_FontSetDefine2(TAG *tag, SWFFONT * f) int pos; int pos2; swf_SetU16(tag, f->id); + if(f->layout) flags |= 128; // haslayout if(f->numchars>256) @@ -475,7 +621,12 @@ int swf_FontSetDefine2(TAG *tag, SWFFONT * f) flags |= 1; // bold if(f->style & FONT_STYLE_ITALIC) flags |= 2; // italic - /* wideoffs 8 */ + if(f->maxascii>=256) + flags |= 4; //wide codecs + if(fontSize(f)>65535) + flags |= 8; //wide offsets + flags |= 8|4; //FIXME: the above check doesn't work + if(f->encoding & FONT_ENCODING_ANSI) flags |= 16; // ansi if(f->encoding & FONT_ENCODING_UNICODE) @@ -497,25 +648,38 @@ int swf_FontSetDefine2(TAG *tag, SWFFONT * f) swf_SetU16(tag, f->numchars); /* font offset table */ pos = tag->len; - for(t=0;tnumchars;t++) + for(t=0;t<=f->numchars;t++) { - swf_SetU16(tag, /* fontoffset */ 0); /*placeholder*/ + if(flags&8) + swf_SetU32(tag, /* fontoffset */ 0); /*placeholder*/ + else + swf_SetU16(tag, /* fontoffset */ 0); /*placeholder*/ } - pos2 = tag->len; - swf_SetU16(tag, 0); //fontcode-fontoffset - for(t=0;tnumchars;t++) { - tag->data[pos + t*2] = (tag->len-pos); - tag->data[pos + t*2 + 1] = (tag->len-pos) >> 8; - swf_SetSimpleShape(tag, f->glyph[t].shape); + + for(t=0;t<=f->numchars;t++) { + if(flags&8) { + tag->data[pos + t*4 ] = (tag->len-pos); + tag->data[pos + t*4 + 1] = (tag->len-pos) >> 8; + tag->data[pos + t*4 + 2] = (tag->len-pos) >> 16; + tag->data[pos + t*4 + 3] = (tag->len-pos) >> 24; + } else { + if(tag->len - pos > 65535) { + fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n"); + exit(1); + } + tag->data[pos + t*2 ] = (tag->len-pos); + tag->data[pos + t*2 + 1] = (tag->len-pos) >> 8; + } + if(tnumchars) + swf_SetSimpleShape(tag, f->glyph[t].shape); } - tag->data[pos2] = tag->len - pos; - tag->data[pos2 + 1] = (tag->len - pos) >> 8; /* font code table */ if(flags & 4) /* wide codes */ { - for(t=0;tnumchars;t++) + for(t=0;tnumchars;t++) { swf_SetU16(tag,f->glyph2ascii[t]); + } } else { for(t=0;tnumchars;t++) swf_SetU8(tag,f->glyph2ascii[t]); @@ -534,11 +698,11 @@ int swf_FontSetDefine2(TAG *tag, SWFFONT * f) swf_SetU16(tag, f->layout->kerningcount); for(t=0;tlayout->kerningcount;t++) { if(flags & 4) /* wide codes */ { - swf_SetU8(tag,f->layout->kerning[t].char1); - swf_SetU8(tag,f->layout->kerning[t].char2); - } else { swf_SetU16(tag,f->layout->kerning[t].char1); swf_SetU16(tag,f->layout->kerning[t].char2); + } else { + swf_SetU8(tag,f->layout->kerning[t].char1); + swf_SetU8(tag,f->layout->kerning[t].char2); } swf_SetU16(tag,f->layout->kerning[t].adjustment); } @@ -565,9 +729,10 @@ int swf_FontSetInfo(TAG * t,SWFFONT * f) if ((!t)||(!f)) return -1; swf_ResetWriteBits(t); swf_SetU16(t,f->id); - l = strlen(f->name); if (l>255) l = 255; + l = f->name?strlen(f->name):0; if (l>255) l = 255; swf_SetU8(t,l); - swf_SetBlock(t,f->name,l); + if(l) + swf_SetBlock(t,f->name,l); if(f->numchars>=256) wide=1; @@ -593,104 +758,6 @@ int swf_FontSetInfo(TAG * t,SWFFONT * f) return 0; } -int swf_FontExport(int handle,SWFFONT * f) -{ int l; - int i; - if (!f) return 0; - - l = sizeof(SWFFONT); - if (handle>=0) - if (write(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) return -1; - - if (f->name) - { U16 ln = strlen(f->name); - l+=2+ln; - if (handle>=0) - { if (write(handle,&ln,2)!=2) return -1; - if (write(handle,f->name,ln)!=ln) return -1; - } - } - - if (f->layout) - { l+=sizeof(SWFLAYOUT); - if (handle>=0) - if (write(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) return -1; -/* new kerning struct. hope commenting this out doesn't break things - if (f->layout->kerning.data) - { l+=f->layout->kerning.count*4; - if (handle>=0) - if (write(handle,f->layout->kerning.data,f->layout->kerning.count*4)!=f->layout->kerning.count*4) return -1; - }*/ - } - - for (i=0;inumchars;i++) - { if (f->glyph[i].shape) - { int ll = swf_ShapeExport(handle,f->glyph[i].shape); - if (ll<0) return -1; - l+=ll; - } - } - - return l; -} - -int swf_FontImport(int handle,SWFFONT * * font) -{ SWFFONT * f; - int layout; - int i = 0; - - if ((!font)||(handle<0)) return -1; - - f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f; - if (!f) return -1; - - memset(f,0x00,sizeof(SWFFONT)); - - if (read(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) goto fehler; - - layout = (f->layout)?1:0; // avoid illegal free() - f->layout = NULL; - - if (f->name) - { U16 ln; - f->name = NULL; - if (read(handle,&ln,2)!=2) goto fehler; - f->name = (U8*)malloc(ln+1); - if (!f->name) goto fehler; - if (read(handle,f->name,ln)!=ln) goto fehler; - f->name[ln] = 0; - } - - if (f->layout) - { f->layout = (SWFLAYOUT *)malloc(sizeof(SWFLAYOUT)); - if (!f->layout) goto fehler; - if (read(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) goto fehler; - /* new kerning struct. hope commenting this out doesn't break things - if (f->layout->kerning.data) - { int l = f->layout->kerning.count*4; - f->layout->kerning.data = (U8*)malloc(l); - if (!f->layout->kerning.data) goto fehler; - if (read(handle,f->layout->kerning.data,l)!=l) goto fehler; - } */ - } - - for (i=0;inumchars;i++) - { if (f->glyph[i].shape) - { if (swf_ShapeImport(handle,&f->glyph[i].shape)<0) goto fehler; - } - } - - f->id = 0; - - return 0; - -fehler: - if (f) for (;iglyph[i].shape = NULL; - swf_FontFree(f); - font[0] = NULL; - return -1; -} - int swf_TextPrintDefineText(TAG * t,SWFFONT * f) { int id = swf_GetTagID(t); if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT); @@ -735,11 +802,19 @@ void swf_FontFree(SWFFONT * f) free(f->glyph2ascii); f->glyph2ascii = NULL; } + if(f->glyphnames) { + int t; + for(t=0;tnumchars;t++) { + if(f->glyphnames[t]) + free(f->glyphnames[t]); + } + free(f->glyphnames); + } } free(f); } -int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S16 dy) +int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,int dx,int dy) { U8 flags; if (!t) return -1; @@ -758,58 +833,97 @@ int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S1 return 0; } -int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) +static int swf_TextCountBits2(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits, char*encoding) { U16 g,a; + char utf8=0; if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1; g = a = 0; - while(s[0]) + if(!strcmp(encoding, "UTF8")) utf8=1; + else if(!strcmp(encoding, "iso-8859-1")) utf8=0; + else fprintf(stderr, "Unknown encoding: %s", encoding); + + while(*s) { - int glyph = font->ascii2glyph[s[0]]; + int glyph = -1,c; + + if(!utf8) c = *s++; + else c = readUTF8char(&s); + + if(c < font->maxascii) + glyph = font->ascii2glyph[c]; if(glyph>=0) { - g = swf_CountBits(glyph,g); - a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a); + g = swf_CountUBits(glyph,g); + a = swf_CountBits(((((U32)font->glyph[glyph].advance)*scale)/20)/100,a); } - s++; } if (gbits) gbits[0] = (U8)g; if (abits) abits[0] = (U8)a; - return 0; } -int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) -{ int l,i; +static int swf_TextSetCharRecord2(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits, char*encoding) +{ int l=0,pos; + char utf8=0; if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1; + + if(!strcmp(encoding, "UTF8")) utf8=1; + else if(!strcmp(encoding, "iso-8859-1")) utf8=0; + else fprintf(stderr, "Unknown encoding: %s", encoding); - l = strlen(s); - if (l>0x7f) l = 0x7f; - swf_SetU8(t,l); + pos = t->len; + swf_SetU8(t, l); //placeholder - for (i=0;iascii2glyph[s[i]]; + int g = -1,c; + + if(!utf8) c = *s++; + else c = readUTF8char(&s); + + if(c < font->maxascii) + g = font->ascii2glyph[c]; if(g>=0) { swf_SetBits(t,g,gbits); - swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits); + swf_SetBits(t,((((U32)font->glyph[g].advance)*scale)/20)/100,abits); + l++; + if(l==0x7f) + break; } } + PUT8(&t->data[pos], l); + swf_ResetWriteBits(t); return 0; } +int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) { + return swf_TextCountBits2(font,s,scale,gbits,abits,"iso-8859-1"); +} +int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) { + return swf_TextSetCharRecord2(t,font,s,scale,gbits,abits,"iso-8859-1"); +} +int swf_TextCountBitsUTF8(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) { + return swf_TextCountBits2(font,s,scale,gbits,abits,"UTF8"); +} +int swf_TextSetCharRecordUTF8(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) { + return swf_TextSetCharRecord2(t,font,s,scale,gbits,abits,"UTF8"); +} + U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale) { U32 res = 0; if (font&&s) { while (s[0]) { - int g = font->ascii2glyph[*s]; + int g = -1; + if(*s < font->maxascii) + g = font->ascii2glyph[*s]; if(g>=0) - res += font->glyph[g].advance; + res += font->glyph[g].advance/20; s++; } if (scale) res = (res*scale)/100; @@ -817,6 +931,31 @@ U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale) return res; } +SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font,U8 * s,int scale) +{ + int pos=0; + SRECT r; + swf_GetRect(0, &r); + while(*s) { + int c = readUTF8char(&s); + if(c < font->maxascii) { + int g = font->ascii2glyph[c]; + if(g>=0) { + SRECT rn = font->layout->bounds[g]; + rn.xmin = (rn.xmin * scale)/20/100 + pos; + rn.xmax = (rn.xmax * scale)/20/100 + pos; + rn.ymin = (rn.ymin * scale)/20/100; + rn.ymax = (rn.ymax * scale)/20/100; + swf_ExpandRect2(&r, &rn); + pos += (font->glyph[g].advance*scale)/20/100; + } + } + c++; + } + return r; +} + + SWFFONT* swf_ReadFont(char* filename) { int f; @@ -847,6 +986,7 @@ void swf_WriteFont(SWFFONT*font, char* filename) RGBA rgb; int f; int useDefineFont2 = 0; + int storeGlyphNames = 1; if(font->layout) useDefineFont2 = 1; /* the only thing new in definefont2 @@ -868,8 +1008,8 @@ void swf_WriteFont(SWFFONT*font, char* filename) did use definefont2 -mk*/ t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR); swf.firstTag = t; - rgb.r = 0xff; - rgb.g = 0xff; + rgb.r = 0xef; + rgb.g = 0xef; rgb.b = 0xff; swf_SetRGB(t,&rgb); if(!useDefineFont2) { @@ -882,24 +1022,54 @@ void swf_WriteFont(SWFFONT*font, char* filename) swf_FontSetDefine2(t,font); } - if(1) //useDefineFont2 - { int textscale = 400; + if(storeGlyphNames && font->glyphnames) + { + int c; + t = swf_InsertTag(t,ST_GLYPHNAMES); + swf_SetU16(t, WRITEFONTID); + swf_SetU16(t, font->numchars); + for(c=0;cnumchars;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 = textscale * 2 * (font->maxascii/16+1); + int ymax = 0; + int ypos = 1; U8 gbits,abits; - char text[MAX_CHAR_PER_FONT+1]; - int x,y; - text[MAX_CHAR_PER_FONT]=0; - for(s=0;smaxascii;s++) + int x,y,c; + int range = font->maxascii; + + c=0; + if(useDefineFont2 && range > 256) { + range = 256; + } + + for(s=0;sascii2glyph[s]; - text[s] = s; if(g>=0) { - if(font->glyph[g].advance*textscale/200 > xmax) - xmax = font->glyph[g].advance*textscale/200; + 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; @@ -909,7 +1079,7 @@ void swf_WriteFont(SWFFONT*font, char* filename) r.xmin = 0; r.ymin = 0; - r.xmax = swf.movieSize.xmax*20; + r.xmax = swf.movieSize.xmax; r.ymax = swf.movieSize.ymax; swf_SetRect(t,&r); @@ -925,11 +1095,12 @@ void swf_WriteFont(SWFFONT*font, char* filename) rgb.r = 0x00; rgb.g = 0x00; rgb.b = 0x00; - for(y=0;y<=((font->maxascii-1)/16);y++) + ypos = 1; + for(y=0;y<((range+15)/16);y++) { - int c=0,lastx=-1, firstx=0; + int c=0,lastx=-1; for(x=0;x<16;x++) { - int g = (y*16+xmaxascii)?font->ascii2glyph[y*16+x]:-1; + int g = (y*16+xascii2glyph[y*16+x]:-1; if(g>=0 && font->glyph[g].shape) { c++; if(lastx<0) @@ -937,21 +1108,22 @@ void swf_WriteFont(SWFFONT*font, char* filename) } } if(c) { - swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*y*2); + swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*ypos*2); for(x=0;x<16;x++) { - int g = (y*16+xmaxascii)?font->ascii2glyph[y*16+x]:-1; + int g = (y*16+xascii2glyph[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, abits); - lastx = x*xmax+font->glyph[g].advance; + 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); @@ -962,6 +1134,7 @@ void swf_WriteFont(SWFFONT*font, char* filename) swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL); t = swf_InsertTag(t,ST_SHOWFRAME); + } t = swf_InsertTag(t,ST_END); @@ -1011,3 +1184,140 @@ void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color, swf_SetString(tag,text); } +SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale) +{ + SRECT r; + U8 gbits, abits; + U8*c = (U8*)text; + int pos = 0; + if(font->layout) { + r = swf_TextCalculateBBoxUTF8(font,text,scale*20); + } else { + fprintf(stderr, "No layout information- can't compute text bbox accurately"); + /* Hm, without layout information, we can't compute a bounding + box. We could call swf_FontCreateLayout to create a layout, + but the caller probably doesn't want us to mess up his font + structure. + */ + r.xmin = r.ymin = 0; + r.xmax = r.ymax = 1024*20; + } + + swf_SetRect(tag,&r); + + /* The text matrix is pretty boring, as it doesn't apply to + individual characters, but rather whole text objects (or + at least whole char records- haven't tested). + So it can't do anything which we can't already do with + the placeobject tag we use for placing the text on the scene. + */ + swf_SetMatrix(tag,0); + + swf_TextCountBitsUTF8(font,text,scale*20,&gbits,&abits); + swf_SetU8(tag,gbits); + swf_SetU8(tag,abits); + + /* 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) + */ + swf_TextSetInfoRecord(tag,font,(scale*1024)/100,rgb,0,0); //scale + + /* set the actual text- notice that we just pass our scale + parameter over, as TextSetCharRecord calculates with + percent, too */ + swf_TextSetCharRecordUTF8(tag,font,text,scale*20,gbits,abits); + + swf_SetU8(tag,0); + return r; +} + +void swf_FontCreateLayout(SWFFONT*f) +{ + S16 leading = 0; + int t; + if(f->layout) + return; + if(!f->numchars) + return; + + f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT)); + memset(f->layout, 0, sizeof(SWFLAYOUT)); + f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT)); + f->layout->ascent = -32767; + f->layout->descent = -32767; + + for(t=0;tnumchars;t++) { + SHAPE2*shape2; + SRECT bbox; + int width; + shape2 = swf_ShapeToShape2(f->glyph[t].shape); + if(!shape2) { + fprintf(stderr, "Shape parse error\n");exit(1); + } + bbox = swf_GetShapeBoundingBox(shape2); + swf_Shape2Free(shape2); + f->layout->bounds[t] = bbox; + + width = (bbox.xmax); + + /* The following is a heuristic- it may be that extractfont_DefineText + has already found out some widths for individual characters (from the way + they are used)- we now have to guess whether that width might be possible, + which is the case if it isn't either much too big or much too small */ + if(width > f->glyph[t].advance*3/2 || + width*2 < f->glyph[t].advance) + f->glyph[t].advance = width; + + if(-bbox.ymin > f->layout->ascent) + f->layout->ascent = bbox.ymin; + if(bbox.ymax > f->layout->descent) + f->layout->descent = bbox.ymax; + } +} + +void swf_DrawText(drawer_t*draw, SWFFONT*font, int size, char*text) +{ + U8*s = (U8*)text; + int advance = 0; + while(*s) { + SHAPE*shape; + SHAPE2*shape2; + SHAPELINE*l; + U32 c = readUTF8char(&s); + int g = font->ascii2glyph[c]; + shape = font->glyph[g].shape; + if(((int)g)<0) { + fprintf(stderr, "No char %d in font %s\n", c, font->name?(char*)font->name:"?"); + continue; + } + shape2 = swf_ShapeToShape2(shape); + l = shape2->lines; + while(l) { + if(l->type == moveTo) { + FPOINT to; + to.x = l->x*size/100.0/20.0+advance; + to.y = l->y*size/100.0/20.0; + draw->moveTo(draw, &to); + } else if(l->type == lineTo) { + FPOINT to; + to.x = l->x*size/100.0/20.0+advance; + to.y = l->y*size/100.0/20.0; + draw->lineTo(draw, &to); + } else if(l->type == splineTo) { + FPOINT mid,to; + mid.x = l->sx*size/100.0/20.0+advance; + mid.y = l->sy*size/100.0/20.0; + to.x = l->x*size/100.0/20.0+advance; + to.y = l->y*size/100.0/20.0; + draw->splineTo(draw, &mid, &to); + } + l = l->next; + } + swf_Shape2Free(shape2); + advance += font->glyph[g].advance*size/100.0/20.0; + } +} + +