X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fmodules%2Fswftext.c;h=62546db2a3ecfb9cb13062cd7cffc7b5c854bccf;hb=879d0eec420fe0fd5ddcd56c8fe62b82a6744edd;hp=a01e10b737448876545f7c2fc10a3b57c9d8e067;hpb=e29b8eb23fc41253809ea4bc090007f80ef3f708;p=swftools.git diff --git a/lib/modules/swftext.c b/lib/modules/swftext.c index a01e10b..62546db 100644 --- a/lib/modules/swftext.c +++ b/lib/modules/swftext.c @@ -1,13 +1,13 @@ /* swftext.c Text and font routines - + Extension module for the rfxswf library. Part of the swftools package. Copyright (c) 2001 Rainer Böhme - Copyright (c) 2003,2004 Matthias Kramm - + Copyright (c) 2003,2004,2005,2006,2007,2008,2009 Matthias Kramm + 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 @@ -22,7 +22,9 @@ 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) +#include "../rfxswf.h" + +U32 readUTF8char(U8 ** text) { U32 c = 0; if (!(*(*text) & 0x80)) @@ -101,7 +103,7 @@ int swf_FontIsBold(SWFFONT * f) static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont -int swf_FontEnumerate(SWF * swf, void (*FontCallback) (U16, U8 *)) +int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self) { int n; TAG *t; @@ -111,14 +113,13 @@ int swf_FontEnumerate(SWF * swf, void (*FontCallback) (U16, U8 *)) n = 0; while (t) { - if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) { + if (swf_isFontTag(t)) { n++; if (FontCallback) { U16 id; int l; U8 s[257]; s[0] = 0; - swf_SaveTagPos(t); swf_SetTagPos(t, 0); id = swf_GetU16(t); @@ -129,9 +130,7 @@ int swf_FontEnumerate(SWF * swf, void (*FontCallback) (U16, U8 *)) s[l] = 0; } - (FontCallback) (id, s); - - swf_RestoreTagPos(t); + (FontCallback) (self, id, s); } } t = swf_NextTag(t); @@ -142,7 +141,6 @@ int swf_FontEnumerate(SWF * swf, void (*FontCallback) (U16, U8 *)) int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t) { U16 fid; - swf_SaveTagPos(t); swf_SetTagPos(t, 0); fid = swf_GetU16(t); @@ -157,16 +155,13 @@ int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t) of = swf_GetU16(t); n = of / 2; f->numchars = n; - f->glyph = malloc(sizeof(SWFGLYPH) * n); - memset(f->glyph, 0, sizeof(SWFGLYPH) * n); + f->glyph = (SWFGLYPH*)rfx_calloc(sizeof(SWFGLYPH) * n); for (i = 1; i < n; i++) swf_GetU16(t); for (i = 0; i < n; i++) swf_GetSimpleShape(t, &f->glyph[i].shape); } - - swf_RestoreTagPos(t); return id; } @@ -175,7 +170,6 @@ int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t) U16 fid; U16 maxcode; U8 flags; - swf_SaveTagPos(t); swf_SetTagPos(t, 0); fid = swf_GetU16(t); @@ -191,9 +185,9 @@ int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t) } if (f->name) - free(f->name); + rfx_free(f->name); - f->name = (U8 *) malloc(l + 1); + f->name = (U8 *) rfx_alloc(l + 1); swf_GetBlock(t, f->name, l); f->name[l] = 0; @@ -213,7 +207,7 @@ int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t) f->language = swf_GetU8(t); } - f->glyph2ascii = (U16 *) malloc(sizeof(U16) * f->numchars); + f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars); maxcode = 0; for (i = 0; i < f->numchars; i++) { f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t)); @@ -224,23 +218,18 @@ int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t) if (maxcode < 256) maxcode = 256; f->maxascii = maxcode; - f->ascii2glyph = (int *) malloc(sizeof(int) * maxcode); + f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode); memset(f->ascii2glyph, -1, sizeof(int) * maxcode); for (i = 0; i < f->numchars; i++) f->ascii2glyph[f->glyph2ascii[i]] = i; } - - swf_RestoreTagPos(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); @@ -248,13 +237,11 @@ int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag) if (fid == id) { int num = swf_GetU16(tag); int t; - f->glyphnames = malloc(sizeof(char *) * num); + f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num); for (t = 0; t < num; t++) { f->glyphnames[t] = strdup(swf_GetString(tag)); } } - - swf_RestoreTagPos(tag); return id; } @@ -264,16 +251,17 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag) int t, glyphcount; int maxcode; int fid; - U8 flags1, flags2, namelen; - swf_SaveTagPos(tag); + U32 offset_start; + U32 *offset; + U8 flags1, langcode, namelen; swf_SetTagPos(tag, 0); - font->version = 2; + font->version = tag->id==ST_DEFINEFONT3?3:2; fid = swf_GetU16(tag); if (id && id != fid) return id; font->id = fid; flags1 = swf_GetU8(tag); - flags2 = swf_GetU8(tag); //reserved flags + langcode = swf_GetU8(tag); //reserved flags if (flags1 & 1) font->style |= FONT_STYLE_BOLD; @@ -287,40 +275,49 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag) font->encoding |= FONT_ENCODING_SHIFTJIS; namelen = swf_GetU8(tag); - font->name = (U8 *) malloc(namelen + 1); + font->name = (U8 *) rfx_alloc(namelen + 1); font->name[namelen] = 0; swf_GetBlock(tag, font->name, namelen); - font->version = 2; glyphcount = swf_GetU16(tag); font->numchars = glyphcount; - font->glyph = (SWFGLYPH *) malloc(sizeof(SWFGLYPH) * glyphcount); - memset(font->glyph, 0, sizeof(SWFGLYPH) * glyphcount); - font->glyph2ascii = (U16 *) malloc(sizeof(U16) * glyphcount); - memset(font->glyph2ascii, 0, sizeof(U16) * glyphcount); + font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount); + font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount); + + offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1)); + offset_start = tag->pos; if (flags1 & 8) { // wide offsets for (t = 0; t < glyphcount; t++) - swf_GetU32(tag); //offset[t] + offset[t] = swf_GetU32(tag); //offset[t] if (glyphcount) /* this _if_ is not in the specs */ - swf_GetU32(tag); // fontcodeoffset + offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset + else + offset[glyphcount] = tag->pos; } else { for (t = 0; t < glyphcount; t++) - swf_GetU16(tag); //offset[t] + offset[t] = swf_GetU16(tag); //offset[t] if (glyphcount) /* this _if_ is not in the specs */ - swf_GetU16(tag); // fontcodeoffset + offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset + else + offset[glyphcount] = tag->pos; } - /* TODO: we should use the offset positions, not just - blindly read in shapes */ - for (t = 0; t < glyphcount; t++) + for (t = 0; t < glyphcount; t++) { + swf_SetTagPos(tag, offset[t]+offset_start); swf_GetSimpleShape(tag, &(font->glyph[t].shape)); + } + + if(glyphcount) + swf_SetTagPos(tag, offset[glyphcount]+offset_start); + + free(offset); maxcode = 0; for (t = 0; t < glyphcount; t++) { int code; - if (flags1 & 4) // wide codes + if (flags1 & 4) // wide codes (always on for definefont3) code = swf_GetU16(tag); else code = swf_GetU8(tag); @@ -332,7 +329,7 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag) if (maxcode < 256) maxcode = 256; font->maxascii = maxcode; - font->ascii2glyph = (int *) malloc(sizeof(int) * maxcode); + font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode); memset(font->ascii2glyph, -1, sizeof(int) * maxcode); for (t = 0; t < glyphcount; t++) { font->ascii2glyph[font->glyph2ascii[t]] = t; @@ -340,7 +337,7 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag) if (flags1 & 128) { // has layout U16 kerningcount; - font->layout = (SWFLAYOUT *) malloc(sizeof(SWFLAYOUT)); + font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT)); font->layout->ascent = swf_GetU16(tag); font->layout->descent = swf_GetU16(tag); font->layout->leading = swf_GetU16(tag); @@ -348,18 +345,25 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag) S16 advance = swf_GetS16(tag); font->glyph[t].advance = advance; } - font->layout->bounds = malloc(glyphcount * sizeof(SRECT)); + font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT)); for (t = 0; t < glyphcount; t++) { swf_ResetReadBits(tag); swf_GetRect(tag, &font->layout->bounds[t]); + SRECT b = font->layout->bounds[t]; + if((b.xmin|b.xmax|b.ymin|b.ymax) == 0) { + // recalculate bounding box + SHAPE2 *shape2 = swf_ShapeToShape2(font->glyph[t].shape); + font->layout->bounds[t] = swf_GetShapeBoundingBox(shape2); + swf_Shape2Free(shape2);free(shape2); + } } kerningcount = swf_GetU16(tag); font->layout->kerningcount = kerningcount; - font->layout->kerning = (SWFKERNING *) malloc(sizeof(SWFKERNING) * kerningcount); + font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount); if (kerningcount) { - font->layout->kerning = malloc(sizeof(*font->layout->kerning) * kerningcount); + font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount); for (t = 0; t < kerningcount; t++) { if (flags1 & 4) { // wide codes font->layout->kerning[t].char1 = swf_GetU16(tag); @@ -372,10 +376,57 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag) } } } - swf_RestoreTagPos(t); return font->id; } +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 @@ -384,20 +435,19 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag) 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) + int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self) { U16 cid; SRECT r; MATRIX m; U8 gbits, abits; - int fid = 0; + int fid = -1; RGBA color; int x = 0, y = 0; int fontsize = 0; memset(&color, 0, sizeof(color)); - swf_SaveTagPos(t); swf_SetTagPos(t, 0); cid = swf_GetU16(t); @@ -421,6 +471,8 @@ swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs, color.b = swf_GetU8(t); if (swf_GetTagID(t) == ST_DEFINETEXT2) color.a = swf_GetU8(t); + else + color.a = 255; } if (flags & TF_HASXOFFSET) x = swf_GetS16(t); @@ -447,20 +499,14 @@ swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs, adv = swf_GetBits(t, abits); xpos += adv; - // if (id == fid) { if (jobs & FEDTJ_PRINT) { int code = f->glyph2ascii[glyph]; - printf("%c", code); + printf("%lc", code); } if (jobs & FEDTJ_MODIFY) f->glyph[glyph].advance = adv * 20; //? - } else { - if (jobs & FEDTJ_PRINT) { - printf("?"); - } } - // buf[i] = glyph; } @@ -472,12 +518,11 @@ swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs, } } - 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) + void (*callback) (void *self, int *chars, int *xpos, 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); } @@ -487,6 +532,52 @@ int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs) return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0); } +typedef struct _usagetmp { + SWFFONT*font; + int lastx,lasty; + int last; +} usagetmp_t; +static void updateusage(void *self, int *chars, int *xpos, int nr, + int fontid, int fontsize, int xstart, int ystart, RGBA * color) +{ + usagetmp_t*u = (usagetmp_t*)self; + if(!u->font->use) { + swf_FontInitUsage(u->font); + } + if(fontid!=u->font->id) + return; + + int t; + for(t=0;tu->font->numchars) + continue; + swf_FontUseGlyph(u->font, c, fontsize); + if(u->lasty == y && x>=u->lastx-200 && abs(u->lastx-x)<200 && + u->last!=c && !swf_ShapeIsEmpty(u->font->glyph[u->last].shape) && + !swf_ShapeIsEmpty(u->font->glyph[c].shape)) + { + swf_FontUsePair(u->font, u->last, c); + } + u->lasty = y; + /* FIXME: do we still need to divide advance by 20 for definefont3? */ + u->lastx = x + (u->font->glyph[c].advance*fontsize/20480); + u->last = c; + } +} + +void swf_FontUpdateUsage(SWFFONT*f, TAG* tag) +{ + usagetmp_t u; + u.font = f; + u.lastx = -0x80000000; + u.lasty = -0x80000000; + u.last = 0; + swf_ParseDefineText(tag, updateusage, &u); +} + int swf_FontExtract(SWF * swf, int id, SWFFONT * *font) { TAG *t; @@ -495,8 +586,7 @@ int swf_FontExtract(SWF * swf, int id, SWFFONT * *font) if ((!swf) || (!font)) return -1; - f = (SWFFONT *) malloc(sizeof(SWFFONT)); - memset(f, 0x00, sizeof(SWFFONT)); + f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT)); t = swf->firstTag; @@ -508,9 +598,14 @@ int swf_FontExtract(SWF * swf, int id, SWFFONT * *font) break; case ST_DEFINEFONT2: + case ST_DEFINEFONT3: 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); @@ -518,7 +613,11 @@ int swf_FontExtract(SWF * swf, int id, SWFFONT * *font) case ST_DEFINETEXT: case ST_DEFINETEXT2: - nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY); + if(!f->layout) { + nid = swf_FontExtract_DefineText(id, f, t, FEDTJ_MODIFY); + } + if(f->version>=3 && f->layout) + swf_FontUpdateUsage(f, t); break; case ST_GLYPHNAMES: @@ -530,7 +629,7 @@ int swf_FontExtract(SWF * swf, int id, SWFFONT * *font) t = swf_NextTag(t); } if (f->id != id) { - free(f); + rfx_free(f); f = 0; } font[0] = f; @@ -549,36 +648,46 @@ void swf_LayoutFree(SWFLAYOUT * l) { if (l) { if (l->kerning) - free(l->kerning); + rfx_free(l->kerning); l->kerning = NULL; if (l->bounds) - free(l->bounds); + rfx_free(l->bounds); l->bounds = NULL; } - free(l); + rfx_free(l); } static void font_freeglyphnames(SWFFONT*f) { - if (f->glyphnames) { - int t; - for (t = 0; t < f->numchars; t++) { - if (f->glyphnames[t]) - free(f->glyphnames[t]); + if (f->glyphnames) + { + int t; + for (t = 0; t < f->numchars; t++) + { + if (f->glyphnames[t]) + { + rfx_free(f->glyphnames[t]); + f->glyphnames[t] = 0; + } + } + rfx_free(f->glyphnames); + f->glyphnames = 0; } - free(f->glyphnames); - f->glyphnames = 0; - } - } static void font_freeusage(SWFFONT*f) { if (f->use) { if(f->use->chars) { - free(f->use->chars);f->use->chars = 0; + rfx_free(f->use->chars);f->use->chars = 0; } - free(f->use); f->use = 0; + if(f->use->neighbors) { + rfx_free(f->use->neighbors);f->use->neighbors = 0; + } + if(f->use->neighbors_hash) { + rfx_free(f->use->neighbors_hash);f->use->neighbors_hash = 0; + } + rfx_free(f->use); f->use = 0; } } static void font_freelayout(SWFFONT*f) @@ -591,12 +700,12 @@ static void font_freelayout(SWFFONT*f) static void font_freename(SWFFONT*f) { if (f->name) { - free(f->name); + rfx_free(f->name); f->name = 0; } } -int swf_FontReduce(SWFFONT * f) +int swf_FontReduce_old(SWFFONT * f) { int i, j; int max_unicode = 0; @@ -639,19 +748,120 @@ int swf_FontReduce(SWFFONT * f) return j; } +int swf_FontReduce_swfc(SWFFONT * f) +{ + int i, j; + int max_unicode = 0; + if ((!f) || (!f->use) || f->use->is_reduced) + return -1; + + font_freeglyphnames(f); + + j = 0; + for (i = 0; i < f->numchars; i++) { + if (f->glyph[i].shape && f->use->chars[i]) { + f->glyph2ascii[j] = f->glyph2ascii[i]; + if (f->layout) + f->layout->bounds[j] = f->layout->bounds[i]; + f->glyph[j] = f->glyph[i]; + f->use->chars[i] = j; + j++; + } else { + f->glyph2ascii[i] = 0; + if(f->glyph[i].shape) { + swf_ShapeFree(f->glyph[i].shape); + f->glyph[i].shape = 0; + f->glyph[i].advance = 0; + } + f->use->chars[i] = -1; + } + } + f->use->used_glyphs = j; + for (i = 0; i < f->maxascii; i++) { + if(f->ascii2glyph[i] > -1) { + if (f->use->chars[f->ascii2glyph[i]]<0) { + f->use->chars[f->ascii2glyph[i]] = 0; + f->ascii2glyph[i] = -1; + } else { + f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]]; + f->use->chars[f->ascii2glyph[i]] = 1; + max_unicode = i + 1; + } + } + } + f->maxascii = max_unicode; + f->use->is_reduced = 1; + f->numchars = j; + font_freename(f); + return j; +} + +int swf_FontReduce(SWFFONT * f) +{ + int i; + int max_unicode = 0; + int max_glyph = 0; + if ((!f) || (!f->use) || f->use->is_reduced) + return -1; + + font_freelayout(f); + font_freeglyphnames(f); + + f->use->used_glyphs= 0; + for (i = 0; i < f->numchars; i++) { + if(!f->use->chars[i]) { + if(f->glyph2ascii) { + f->glyph2ascii[i] = 0; + } + if(f->glyph[i].shape) { + swf_ShapeFree(f->glyph[i].shape); + f->glyph[i].shape = 0; + f->glyph[i].advance = 0; + } +// f->use->used_glyphs++; + } else { + f->use->used_glyphs++; + max_glyph = i+1; + } + } + for (i = 0; i < f->maxascii; i++) { + if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) { + if(f->ascii2glyph) { + f->ascii2glyph[i] = -1; + } + } else { + max_unicode = i+1; + } + } + f->maxascii = max_unicode; + f->numchars = max_glyph; + font_freename(f); + return 0; +} + +static SWFFONT* font_to_sort; +int cmp_chars(const void*a, const void*b) +{ + int x = *(const int*)a; + int y = *(const int*)b; + return 0; +} + void swf_FontSort(SWFFONT * font) { - int i, j, k; + int i, j; int *newplace; int *newpos; if (!font) return; - - newplace = malloc(sizeof(int) * font->numchars); + + newplace = (int*)rfx_alloc(sizeof(int) * font->numchars); for (i = 0; i < font->numchars; i++) { newplace[i] = i; } + //qsort(newplace, sizeof(newplace[0]), font->numchars, cmp_chars); + for (i = 0; i < font->numchars; i++) for (j = 0; j < i; j++) { if (font->glyph2ascii[i] < font->glyph2ascii[j]) { @@ -685,7 +895,7 @@ void swf_FontSort(SWFFONT * font) } } } - newpos = malloc(sizeof(int) * font->numchars); + newpos = (int*)rfx_alloc(sizeof(int) * font->numchars); for (i = 0; i < font->numchars; i++) { newpos[newplace[i]] = i; } @@ -694,8 +904,8 @@ void swf_FontSort(SWFFONT * font) font->ascii2glyph[i] = newpos[font->ascii2glyph[i]]; } - free(newpos); - free(newplace); + rfx_free(newplace); + font->glyph2glyph = newpos; } void swf_FontPrepareForEditText(SWFFONT * font) @@ -713,10 +923,9 @@ int swf_FontInitUsage(SWFFONT * f) fprintf(stderr, "Usage initialized twice"); return -1; } - f->use = malloc(sizeof(FONTUSAGE)); - f->use->is_reduced = 0; - f->use->chars = malloc(sizeof(f->use->chars[0]) * f->numchars); - memset(f->use->chars, 0, sizeof(f->use->chars[0]) * f->numchars); + f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE)); + f->use->smallest_size = 0xffff; + f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars); return 0; } @@ -724,37 +933,139 @@ void swf_FontClearUsage(SWFFONT * f) { if (!f || !f->use) return; - free(f->use->chars); f->use->chars = 0; - free(f->use); f->use = 0; + rfx_free(f->use->chars); f->use->chars = 0; + rfx_free(f->use); f->use = 0; } int swf_FontUse(SWFFONT * f, U8 * s) { - if (!f->use) - swf_FontInitUsage(f); if( (!s)) return -1; while (*s) { if(*s < f->maxascii && f->ascii2glyph[*s]>=0) - f->use->chars[f->ascii2glyph[*s]] = 1; + swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff); s++; } return 0; } -int swf_FontUseGlyph(SWFFONT * f, int glyph) +int swf_FontUseUTF8(SWFFONT * f, const U8 * s, U16 size) +{ + if( (!s)) + return -1; + int ascii; + while (*s) + { + ascii = readUTF8char((U8**)&s); + if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0) + swf_FontUseGlyph(f, f->ascii2glyph[ascii], size); + } + return 0; +} + +int swf_FontUseAll(SWFFONT* f) +{ + int i; + + if (!f->use) + swf_FontInitUsage(f); + for (i = 0; i < f->numchars; i++) + f->use->chars[i] = 1; + f->use->used_glyphs = f->numchars; + return 0; +} + +static unsigned hash2(int char1, int char2) { - if (!f->use) + unsigned hash = char1^(char2<<8); + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} +static void hashadd(FONTUSAGE*u, int char1, int char2, int nr) +{ + unsigned hash = hash2(char1, char2); + while(1) { + hash = hash%u->neighbors_hash_size; + if(!u->neighbors_hash[hash]) { + u->neighbors_hash[hash] = nr+1; + return; + } + hash++; + } +} +int swf_FontUseGetPair(SWFFONT * f, int char1, int char2) +{ + FONTUSAGE*u = f->use; + if(!u || !u->neighbors_hash_size) + return 0; + unsigned hash = hash2(char1, char2); + while(1) { + hash = hash%u->neighbors_hash_size; + int pos = u->neighbors_hash[hash]; + if(!pos) + return 0; + if(pos && + u->neighbors[pos-1].char1 == char1 && + u->neighbors[pos-1].char2 == char2) { + return pos; + } + hash++; + } + +} +void swf_FontUsePair(SWFFONT * f, int char1, int char2) +{ + if (!f->use) swf_FontInitUsage(f); - if(glyph < 0 || glyph > f->numchars) + FONTUSAGE*u = f->use; + + if(u->num_neighbors*3 >= u->neighbors_hash_size*2) { + if(u->neighbors_hash) { + free(u->neighbors_hash); + } + u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024; + u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int)); + int t; + for(t=0;tnum_neighbors;t++) { + hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t); + } + } + + int nr = swf_FontUseGetPair(f, char1, char2); + if(!nr) { + if(u->num_neighbors == u->neighbors_size) { + u->neighbors_size += 4096; + u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size); + } + u->neighbors[u->num_neighbors].char1 = char1; + u->neighbors[u->num_neighbors].char2 = char2; + u->neighbors[u->num_neighbors].num = 1; + hashadd(u, char1, char2, u->num_neighbors); + u->num_neighbors++; + } else { + u->neighbors[nr-1].num++; + } +} + +int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size) +{ + if (!f->use) + swf_FontInitUsage(f); + if(glyph < 0 || glyph >= f->numchars) return -1; + if(!f->use->chars[glyph]) + f->use->used_glyphs++; f->use->chars[glyph] = 1; + if(size && size < f->use->smallest_size) + f->use->smallest_size = size; return 0; } int swf_FontSetDefine(TAG * t, SWFFONT * f) { - U16 *ofs = (U16 *) malloc(f->numchars * 2); + U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2); int p, i, j; if ((!t) || (!f)) @@ -782,7 +1093,7 @@ int swf_FontSetDefine(TAG * t, SWFFONT * f) swf_SetSimpleShape(t, f->glyph[i].shape); swf_ResetWriteBits(t); - free(ofs); + rfx_free(ofs); return 0; } @@ -792,7 +1103,7 @@ static inline int fontSize(SWFFONT * font) int size = 0; for (t = 0; t < font->numchars; t++) { int l = 0; - if(font->glyph[t].shape) + if(font->glyph[t].shape) l = (font->glyph[t].shape->bitlen + 7) / 8; else l = 8; @@ -806,7 +1117,6 @@ int swf_FontSetDefine2(TAG * tag, SWFFONT * f) U8 flags = 0; int t; int pos; - int pos2; swf_SetU16(tag, f->id); if (f->layout) flags |= 128; // haslayout @@ -833,10 +1143,11 @@ int swf_FontSetDefine2(TAG * tag, SWFFONT * f) swf_SetU8(tag, 0); //reserved flags if (f->name) { /* font name */ - swf_SetU8(tag, strlen(f->name)); - swf_SetBlock(tag, f->name, strlen(f->name)); + swf_SetU8(tag, strlen((const char*)f->name)+1); + swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1); } else { /* font name (="") */ + swf_SetU8(tag, 1); swf_SetU8(tag, 0); } /* number of glyphs */ @@ -875,23 +1186,34 @@ int swf_FontSetDefine2(TAG * tag, SWFFONT * f) /* font code table */ - if (flags & 4) { /* wide codes */ - for (t = 0; t < f->numchars; t++) { - swf_SetU16(tag, f->glyph2ascii[t]); + for (t = 0; t < f->numchars; t++) { + if (flags & 4) { /* wide codes */ + if(f->glyph2ascii[t]) { + swf_SetU16(tag, f->glyph2ascii[t]); + } else { + swf_SetU16(tag, 0); + } + } else { + if(f->glyph2ascii[t]) { + swf_SetU8(tag, f->glyph2ascii[t]); + } else { + swf_SetU8(tag, 0); + } } - } else { - for (t = 0; t < f->numchars; t++) - swf_SetU8(tag, f->glyph2ascii[t]); } + if (f->layout) { swf_SetU16(tag, f->layout->ascent); swf_SetU16(tag, f->layout->descent); - swf_SetU16(tag, f->layout->leading); + swf_SetU16(tag, 0); // flash ignores leading + for (t = 0; t < f->numchars; t++) swf_SetU16(tag, f->glyph[t].advance); for (t = 0; t < f->numchars; t++) { swf_ResetWriteBits(tag); - swf_SetRect(tag, &f->layout->bounds[t]); + /* not used by flash, so leave this empty */ + SRECT b = {0,0,0,0}; + swf_SetRect(tag, &b); } swf_SetU16(tag, f->layout->kerningcount); for (t = 0; t < f->layout->kerningcount; t++) { @@ -910,14 +1232,13 @@ int swf_FontSetDefine2(TAG * tag, SWFFONT * f) void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading) { - f->layout = (SWFLAYOUT *) malloc(sizeof(SWFLAYOUT)); + f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT)); f->layout->ascent = ascent; f->layout->descent = descent; f->layout->leading = leading; f->layout->kerningcount = 0; f->layout->kerning = 0; - f->layout->bounds = (SRECT *) malloc(sizeof(SRECT) * f->numchars); - memset(f->layout->bounds, 0, sizeof(SRECT) * f->numchars); + f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars); } int swf_FontSetInfo(TAG * t, SWFFONT * f) @@ -929,7 +1250,7 @@ int swf_FontSetInfo(TAG * t, SWFFONT * f) return -1; swf_ResetWriteBits(t); swf_SetU16(t, f->id); - l = f->name ? strlen(f->name) : 0; + l = f->name ? strlen((const char *)f->name) : 0; if (l > 255) l = 255; swf_SetU8(t, l); @@ -953,7 +1274,7 @@ int swf_FontSetInfo(TAG * t, SWFFONT * f) for (i = 0; i < f->numchars; i++) { if (f->glyph[i].shape) { - int g2a = f->glyph2ascii[i]; + int g2a = f->glyph2ascii?f->glyph2ascii[i]:0; wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a); } } @@ -971,45 +1292,61 @@ int swf_TextPrintDefineText(TAG * t, SWFFONT * f) return 0; } +static void font_freealignzones(SWFFONT * f) +{ + if(f->alignzones) + free(f->alignzones); + f->alignzones = 0; +} + void swf_FontFree(SWFFONT * f) { int i; if (!f) - return; + return; - if (f->glyph) { - for (i = 0; i < f->numchars; i++) - if (f->glyph[i].shape) { - swf_ShapeFree(f->glyph[i].shape); - f->glyph[i].shape = NULL; - } - free(f->glyph); - f->glyph = NULL; + if (f->glyph) + { + for (i = 0; i < f->numchars; i++) + if (f->glyph[i].shape) + { + swf_ShapeFree(f->glyph[i].shape); + f->glyph[i].shape = NULL; + } + rfx_free(f->glyph); + f->glyph = NULL; } - if (f->ascii2glyph) { - free(f->ascii2glyph); - f->ascii2glyph = NULL; + if (f->ascii2glyph) + { + rfx_free(f->ascii2glyph); + f->ascii2glyph = NULL; } - if (f->glyph2ascii) { - free(f->glyph2ascii); - f->glyph2ascii = NULL; + if (f->glyph2ascii) + { + rfx_free(f->glyph2ascii); + f->glyph2ascii = NULL; + } + if (f->glyph2glyph) { + rfx_free(f->glyph2glyph); + f->glyph2glyph = NULL; } font_freename(f); font_freelayout(f); font_freeglyphnames(f); font_freeusage(f); + font_freealignzones(f); - free(f); + rfx_free(f); } -int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy) +int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y) { U8 flags; if (!t) return -1; - flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0) - | (dy ? TF_HASYOFFSET : 0); + flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0) + | (y ? TF_HASYOFFSET : 0); swf_SetU8(t, flags); if (font) @@ -1020,15 +1357,23 @@ int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int d else swf_SetRGB(t, color); } - if (dx) { - if(dx>32767 || dx<-32768) - fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx); - swf_SetS16(t, dx); + if (x) { + if(x != SET_TO_ZERO) { + if(x>32767 || x<-32768) + fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x); + swf_SetS16(t, x); + } else { + swf_SetS16(t, 0); + } } - if (dy) { - if(dy>32767 || dy<-32768) - fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy); - swf_SetS16(t, dy); + if (y) { + if(y != SET_TO_ZERO) { + if(y>32767 || y<-32768) + fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y); + swf_SetS16(t, y); + } else { + swf_SetS16(t, 0); + } } if (font) swf_SetU16(t, size); @@ -1106,6 +1451,11 @@ static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 swf_SetBits(t, g, gbits); swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits); l++; + /* We split into 127 characters per text field. + We could do 255, by the (formerly wrong) flash specification, + but some SWF parsing code out there still assumes that char blocks + are at max 127 characters, and it would save only a few bits. + */ if (l == 0x7f) break; } @@ -1158,36 +1508,44 @@ U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale) SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale) { - int pos = 0; + int xpos = 0; + int ypos = 0; SRECT r; swf_GetRect(0, &r); while (*s) { int c = readUTF8char(&s); + if(c==13 || c==10) { + if(s[0] == 10) { + s++; + } + xpos=0; + ypos+=font->layout->leading; + continue; + } 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; + rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos; + rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos; + rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos; + rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos; swf_ExpandRect2(&r, &rn); - pos += (font->glyph[g].advance * scale) / 20 / 100; + xpos += (font->glyph[g].advance * scale) / 20 / 100; } } - c++; } return r; } -SWFFONT *swf_ReadFont(char *filename) +SWFFONT *swf_ReadFont(const char *filename) { int f; SWF swf; if (!filename) return 0; - f = open(filename, O_RDONLY); + f = open(filename, O_RDONLY|O_BINARY); if (f < 0 || swf_ReadSWF(f, &swf) < 0) { fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename); @@ -1203,173 +1561,7 @@ SWFFONT *swf_ReadFont(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 = 4; - 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 (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, 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, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable) +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); swf_ResetWriteBits(tag); @@ -1410,14 +1602,18 @@ void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, in swf_SetString(tag, text); } -SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale) +SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale) { SRECT r; U8 gbits, abits; - U8 *c = (U8 *) text; + U8 *utext = (U8 *) strdup(text); + U8 *upos = utext; + int x = 0, y = 0; int pos = 0; + int ystep = 0; if (font->layout) { - r = swf_TextCalculateBBoxUTF8(font, text, scale * 20); + r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20); + ystep = font->layout->leading; } else { fprintf(stderr, "No layout information- can't compute text bbox accurately"); /* Hm, without layout information, we can't compute a bounding @@ -1427,6 +1623,7 @@ SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int s */ r.xmin = r.ymin = 0; r.xmax = r.ymax = 1024 * 20; + ystep = 100; } swf_SetRect(tag, &r); @@ -1439,21 +1636,48 @@ SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int s */ swf_SetMatrix(tag, 0); - swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits); + swf_TextCountBitsUTF8(font, (U8*)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 + while(*upos) { + U8*next = upos; + int count = 0; + + swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale + x = 0; + + while(*next && *next!=13 && *next!=10 && count<127) { + readUTF8char(&next); + count++; + } + if(next[0] == 13 || next[0] == 10) { + x = SET_TO_ZERO; + y += ystep; + } + + if(next[0] == 13 && next[1] == 10) + next++; + + if(next[0] == 13 || next[0] == 10) { + *next = 0; + next++; + } - /* 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); + /* now set the text params- notice that a font size of + 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 */ + swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits); + + upos= next; + } + free(utext); swf_SetU8(tag, 0); return r; @@ -1468,11 +1692,10 @@ void swf_FontCreateLayout(SWFFONT * f) 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; + f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT)); + f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT)); + f->layout->ascent = 0; + f->layout->descent = 0; for (t = 0; t < f->numchars; t++) { SHAPE2 *shape2; @@ -1497,13 +1720,13 @@ 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; } } -void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text) +void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text) { U8 *s = (U8 *) text; int advance = 0; @@ -1545,3 +1768,395 @@ void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, 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); +}