+{
+ if (l) {
+ if (l->kerning)
+ rfx_free(l->kerning);
+ l->kerning = NULL;
+ if (l->bounds)
+ rfx_free(l->bounds);
+ l->bounds = NULL;
+ }
+ 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])
+ {
+ rfx_free(f->glyphnames[t]);
+ f->glyphnames[t] = 0;
+ }
+ }
+ rfx_free(f->glyphnames);
+ f->glyphnames = 0;
+ }
+}
+static void font_freeusage(SWFFONT*f)
+{
+ if (f->use) {
+ if(f->use->chars) {
+ rfx_free(f->use->chars);f->use->chars = 0;
+ }
+ rfx_free(f->use); f->use = 0;
+ }
+}
+static void font_freelayout(SWFFONT*f)
+{
+ if (f->layout) {
+ swf_LayoutFree(f->layout);
+ f->layout = 0;
+ }
+}
+static void font_freename(SWFFONT*f)
+{
+ if (f->name) {
+ rfx_free(f->name);
+ f->name = 0;
+ }
+}
+
+int swf_FontReduce_old(SWFFONT * f)
+{
+ int i, j;
+ int max_unicode = 0;
+ if ((!f) || (!f->use) || f->use->is_reduced)
+ return -1;
+
+ j = 0;
+
+ for (i = 0; i < f->numchars; i++) {
+ if (f->glyph[i].shape && f->use->chars[i]) {
+ f->glyph2ascii[j] = f->glyph2ascii[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;
+ j++; //TODO: remove
+ }
+ }
+ for (i = 0; i < f->maxascii; i++) {
+ if(f->use->chars[f->ascii2glyph[i]]<0) {
+ f->ascii2glyph[i] = -1;
+ } else {
+ f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
+ max_unicode = i;
+ }
+ }
+ f->maxascii = max_unicode;
+ f->use->is_reduced = 1;
+ f->numchars = j;
+ font_freelayout(f);
+ font_freeglyphnames(f);
+ font_freename(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;
+}
+
+void swf_FontSort(SWFFONT * font)
+{
+ int i, j;
+ int *newplace;
+ int *newpos;
+ if (!font)
+ return;
+
+ newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
+
+ for (i = 0; i < font->numchars; i++) {
+ newplace[i] = i;
+ }
+ for (i = 0; i < font->numchars; i++)
+ for (j = 0; j < i; j++) {
+ if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
+ int n1, n2;
+ char *c1, *c2;
+ SWFGLYPH g1, g2;
+ SRECT r1, r2;
+ n1 = newplace[i];
+ n2 = newplace[j];
+ newplace[j] = n1;
+ newplace[i] = n2;
+ n1 = font->glyph2ascii[i];
+ n2 = font->glyph2ascii[j];
+ font->glyph2ascii[j] = n1;
+ font->glyph2ascii[i] = n2;
+ g1 = font->glyph[i];
+ g2 = font->glyph[j];
+ font->glyph[j] = g1;
+ font->glyph[i] = g2;
+ if (font->glyphnames) {
+ c1 = font->glyphnames[i];
+ c2 = font->glyphnames[j];
+ font->glyphnames[j] = c1;
+ font->glyphnames[i] = c2;
+ }
+ if (font->layout) {
+ r1 = font->layout->bounds[i];
+ r2 = font->layout->bounds[j];
+ font->layout->bounds[j] = r1;
+ font->layout->bounds[i] = r2;
+ }
+ }
+ }
+ newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
+ for (i = 0; i < font->numchars; i++) {
+ newpos[newplace[i]] = i;
+ }
+ for (i = 0; i < font->maxascii; i++) {
+ if (font->ascii2glyph[i] >= 0)
+ font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
+ }
+
+ rfx_free(newpos);
+ rfx_free(newplace);
+}
+
+void swf_FontPrepareForEditText(SWFFONT * font)
+{
+ if (!font->layout)
+ swf_FontCreateLayout(font);
+ swf_FontSort(font);
+}
+
+int swf_FontInitUsage(SWFFONT * f)
+{
+ if (!f)
+ return -1;
+ if(f->use) {
+ fprintf(stderr, "Usage initialized twice");
+ return -1;
+ }
+ f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
+ f->use->is_reduced = 0;
+ f->use->used_glyphs = 0;
+ f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
+ f->use->glyphs_specified = 0;
+ return 0;
+}
+
+void swf_FontClearUsage(SWFFONT * f)
+{
+ if (!f || !f->use)
+ return;
+ rfx_free(f->use->chars); f->use->chars = 0;
+ rfx_free(f->use); f->use = 0;
+}
+
+int swf_FontUse(SWFFONT * f, U8 * s)
+{
+ if( (!s))
+ return -1;
+ while (*s) {
+ if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
+ swf_FontUseGlyph(f, f->ascii2glyph[*s]);
+ s++;
+ }
+ return 0;
+}
+
+int swf_FontUseUTF8(SWFFONT * f, U8 * s)
+{
+ if( (!s))
+ return -1;
+ int ascii;
+ while (*s)
+ {
+ ascii = readUTF8char(&s);
+ if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
+ swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
+ }
+ 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;
+}
+
+int swf_FontUseGlyph(SWFFONT * f, int glyph)
+{
+ 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;
+ return 0;
+}
+
+int swf_FontSetDefine(TAG * t, SWFFONT * f)
+{
+ U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
+ int p, i, j;
+
+ if ((!t) || (!f))
+ return -1;
+ swf_ResetWriteBits(t);
+ swf_SetU16(t, f->id);
+
+ p = 0;
+ j = 0;
+ for (i = 0; i < f->numchars; i++)
+ if (f->glyph[i].shape) {
+ ofs[j++] = p;
+ p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
+ }
+
+ for (i = 0; i < j; i++)
+ swf_SetU16(t, ofs[i] + j * 2);
+ if (!j) {
+ fprintf(stderr, "rfxswf: warning: Font is empty\n");
+ swf_SetU16(t, 0);
+ }
+
+ for (i = 0; i < f->numchars; i++)
+ if (f->glyph[i].shape)
+ swf_SetSimpleShape(t, f->glyph[i].shape);
+
+ swf_ResetWriteBits(t);
+ rfx_free(ofs);
+ return 0;
+}
+
+static inline int fontSize(SWFFONT * font)
+{
+ int t;
+ int size = 0;
+ for (t = 0; t < font->numchars; t++) {
+ int l = 0;
+ if(font->glyph[t].shape)
+ l = (font->glyph[t].shape->bitlen + 7) / 8;
+ else
+ l = 8;
+ size += l + 1;
+ }
+ return size + (font->numchars + 1) * 2;
+}
+
+int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
+{
+ U8 flags = 0;
+ int t;
+ int pos;
+ swf_SetU16(tag, f->id);
+
+ if (f->layout) flags |= 128; // haslayout
+ if (f->numchars > 256)
+ flags |= 4; // widecodes
+ if (f->style & FONT_STYLE_BOLD)
+ flags |= 1; // bold
+ if (f->style & FONT_STYLE_ITALIC)
+ flags |= 2; // italic
+ 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)
+ flags |= 32; // unicode
+ if (f->encoding & FONT_ENCODING_SHIFTJIS)
+ flags |= 64; // shiftjis
+
+ swf_SetU8(tag, flags);
+ swf_SetU8(tag, 0); //reserved flags
+ if (f->name) {
+ /* font 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 */
+ swf_SetU16(tag, f->numchars);
+ /* font offset table */
+ pos = tag->len;
+ for (t = 0; t <= f->numchars; t++) {
+ if (flags & 8)
+ swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
+ else
+ swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
+ }
+
+ 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 (t < f->numchars) {
+ if(f->glyph[t].shape) {
+ swf_SetSimpleShape(tag, f->glyph[t].shape);
+ } else {
+ swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
+ }
+ }
+ }
+
+
+ /* font code table */
+ 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);
+ }
+ }
+ }
+
+ if (f->layout) {
+ swf_SetU16(tag, f->layout->ascent);
+ swf_SetU16(tag, f->layout->descent);
+ swf_SetU16(tag, f->layout->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]);
+ }
+ swf_SetU16(tag, f->layout->kerningcount);
+ for (t = 0; t < f->layout->kerningcount; t++) {
+ if (flags & 4) { /* wide codes */
+ 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);
+ }
+ }
+ return 0;
+}
+
+void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
+{
+ 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 *) rfx_calloc(sizeof(SRECT) * f->numchars);
+}
+
+int swf_FontSetInfo(TAG * t, SWFFONT * f)
+{
+ int l, i;
+ U8 wide = 0;
+ U8 flags = 0;
+ if ((!t) || (!f))
+ return -1;
+ swf_ResetWriteBits(t);
+ swf_SetU16(t, f->id);
+ l = f->name ? strlen((const char *)f->name) : 0;
+ if (l > 255)
+ l = 255;
+ swf_SetU8(t, l);
+ if (l)
+ swf_SetBlock(t, f->name, l);
+ if (f->numchars >= 256)
+ wide = 1;
+
+ if (f->style & FONT_STYLE_BOLD)
+ flags |= 2;
+ if (f->style & FONT_STYLE_ITALIC)
+ flags |= 4;
+ if (f->style & FONT_ENCODING_ANSI)
+ flags |= 8;
+ if (f->style & FONT_ENCODING_SHIFTJIS)
+ flags |= 16;
+ if (f->style & FONT_ENCODING_UNICODE)
+ flags |= 32;
+
+ swf_SetU8(t, (flags & 0xfe) | wide);
+
+ for (i = 0; i < f->numchars; i++) {
+ if (f->glyph[i].shape) {
+ int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
+ wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
+ }
+ }
+
+ return 0;
+}
+
+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);
+ else
+ return -1;
+ return 0;