5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9 Copyright (c) 2003,2004 Matthias Kramm
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../rfxswf.h"
27 U32 readUTF8char(U8 ** text)
30 if (!(*(*text) & 0x80))
33 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
34 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
35 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
39 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
40 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
41 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
45 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
46 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
48 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
52 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
53 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
56 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
60 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
61 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
63 && (*text)[4] && (*text)[5]) {
64 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
65 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
72 #define TF_TEXTCONTROL 0x80
73 #define TF_HASFONT 0x08
74 #define TF_HASCOLOR 0x04
75 #define TF_HASYOFFSET 0x02
76 #define TF_HASXOFFSET 0x01
78 #define FF_WIDECODES 0x01
80 #define FF_ITALIC 0x04
82 #define FF_SHIFTJIS 0x10
83 #define FF_UNICODE 0x20
86 #define FF2_ITALIC 0x02
87 #define FF2_WIDECODES 0x04
88 #define FF2_WIDEOFFSETS 0x08
90 #define FF2_UNICODE 0x20
91 #define FF2_SHIFTJIS 0x40
92 #define FF2_LAYOUT 0x80
94 int swf_FontIsItalic(SWFFONT * f)
96 return f->style & FONT_STYLE_ITALIC;
99 int swf_FontIsBold(SWFFONT * f)
101 return f->style & FONT_STYLE_BOLD;
104 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
106 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
116 if (swf_isFontTag(t)) {
126 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
129 swf_GetBlock(t, s, l);
133 (FontCallback) (self, id, s);
141 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
147 if ((!id) || (id == fid)) {
158 f->glyph = (SWFGLYPH*)rfx_calloc(sizeof(SWFGLYPH) * n);
160 for (i = 1; i < n; i++)
162 for (i = 0; i < n; i++)
163 swf_GetSimpleShape(t, &f->glyph[i].shape);
168 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
180 if (f->version > 1) {
181 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
182 too. However, they only add little information to what's already
183 inside the DefineFont2 tag */
190 f->name = (U8 *) rfx_alloc(l + 1);
191 swf_GetBlock(t, f->name, l);
194 flags = swf_GetU8(t);
196 f->style |= FONT_STYLE_BOLD;
198 f->style |= FONT_STYLE_ITALIC;
200 f->encoding |= FONT_ENCODING_ANSI;
202 f->encoding |= FONT_ENCODING_SHIFTJIS;
204 f->encoding |= FONT_ENCODING_UNICODE;
206 if (t->id == ST_DEFINEFONTINFO2) {
207 f->language = swf_GetU8(t);
210 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
212 for (i = 0; i < f->numchars; i++) {
213 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
214 if (f->glyph2ascii[i] > maxcode)
215 maxcode = f->glyph2ascii[i];
220 f->maxascii = maxcode;
221 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
222 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
224 for (i = 0; i < f->numchars; i++)
225 f->ascii2glyph[f->glyph2ascii[i]] = i;
230 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
233 swf_SetTagPos(tag, 0);
235 fid = swf_GetU16(tag);
238 int num = swf_GetU16(tag);
240 f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num);
241 for (t = 0; t < num; t++) {
242 f->glyphnames[t] = strdup(swf_GetString(tag));
249 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
256 U8 flags1, langcode, namelen;
257 swf_SetTagPos(tag, 0);
258 font->version = tag->id==ST_DEFINEFONT3?3:2;
259 fid = swf_GetU16(tag);
263 flags1 = swf_GetU8(tag);
264 langcode = swf_GetU8(tag); //reserved flags
267 font->style |= FONT_STYLE_BOLD;
269 font->style |= FONT_STYLE_ITALIC;
271 font->encoding |= FONT_ENCODING_ANSI;
273 font->encoding |= FONT_ENCODING_UNICODE;
275 font->encoding |= FONT_ENCODING_SHIFTJIS;
277 namelen = swf_GetU8(tag);
278 font->name = (U8 *) rfx_alloc(namelen + 1);
279 font->name[namelen] = 0;
280 swf_GetBlock(tag, font->name, namelen);
281 glyphcount = swf_GetU16(tag);
282 font->numchars = glyphcount;
284 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
285 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
287 offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
288 offset_start = tag->pos;
290 if (flags1 & 8) { // wide offsets
291 for (t = 0; t < glyphcount; t++)
292 offset[t] = swf_GetU32(tag); //offset[t]
294 if (glyphcount) /* this _if_ is not in the specs */
295 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
297 offset[glyphcount] = tag->pos;
299 for (t = 0; t < glyphcount; t++)
300 offset[t] = swf_GetU16(tag); //offset[t]
302 if (glyphcount) /* this _if_ is not in the specs */
303 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
305 offset[glyphcount] = tag->pos;
307 for (t = 0; t < glyphcount; t++) {
308 swf_SetTagPos(tag, offset[t]+offset_start);
309 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
313 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
318 for (t = 0; t < glyphcount; t++) {
320 if (flags1 & 4) // wide codes (always on for definefont3)
321 code = swf_GetU16(tag);
323 code = swf_GetU8(tag);
324 font->glyph2ascii[t] = code;
331 font->maxascii = maxcode;
332 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
333 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
334 for (t = 0; t < glyphcount; t++) {
335 font->ascii2glyph[font->glyph2ascii[t]] = t;
338 if (flags1 & 128) { // has layout
340 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
341 font->layout->ascent = swf_GetU16(tag);
342 font->layout->descent = swf_GetU16(tag);
343 font->layout->leading = swf_GetU16(tag);
344 for (t = 0; t < glyphcount; t++) {
345 S16 advance = swf_GetS16(tag);
346 font->glyph[t].advance = advance;
348 font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
349 for (t = 0; t < glyphcount; t++) {
350 swf_ResetReadBits(tag);
351 swf_GetRect(tag, &font->layout->bounds[t]);
354 kerningcount = swf_GetU16(tag);
355 font->layout->kerningcount = kerningcount;
357 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
359 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
360 for (t = 0; t < kerningcount; t++) {
361 if (flags1 & 4) { // wide codes
362 font->layout->kerning[t].char1 = swf_GetU16(tag);
363 font->layout->kerning[t].char2 = swf_GetU16(tag);
365 font->layout->kerning[t].char1 = swf_GetU8(tag);
366 font->layout->kerning[t].char2 = swf_GetU8(tag);
368 font->layout->kerning[t].adjustment = swf_GetS16(tag);
375 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
378 swf_SetTagPos(tag, 0);
379 fid = swf_GetU16(tag);
382 font->alignzone_flags = swf_GetU8(tag);
383 font->alignzones = rfx_calloc(sizeof(ALIGNZONE)*font->numchars);
385 while(tag->pos < tag->len) {
386 if(i>=font->numchars)
388 int nr = swf_GetU8(tag); // should be 2
390 fprintf(stderr, "rfxswf: Can't parse alignzone tags with %d zones", nr);
393 U16 x = swf_GetU16(tag);
394 U16 y = swf_GetU16(tag);
395 U16 dx = (nr==2)?swf_GetU16(tag):0xffff;
396 U16 dy = (nr==2)?swf_GetU16(tag):0xffff;
397 U8 xy = swf_GetU8(tag);
400 if((!(xy&1) && (x!=0 || (dx!=0 && dx!=0xffff))) ||
401 (!(xy&2) && (y!=0 || (dy!=0 && dy!=0xffff)))) {
402 fprintf(stderr, "Warning: weird combination of alignzone bits and values (%d x:%04x-%04x y:%04x-%04x)\n", xy,
413 font->alignzones[i].x = x;
414 font->alignzones[i].y = y;
415 font->alignzones[i].dx = dx;
416 font->alignzones[i].dy = dy;
424 #define FEDTJ_PRINT 0x01
425 #define FEDTJ_MODIFY 0x02
426 #define FEDTJ_CALLBACK 0x04
429 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
430 void (*callback) (void *self,
431 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
442 memset(&color, 0, sizeof(color));
448 swf_GetMatrix(t, &m);
449 gbits = swf_GetU8(t);
450 abits = swf_GetU8(t);
454 flags = swf_GetU8(t);
458 if (flags & TF_TEXTCONTROL) {
459 if (flags & TF_HASFONT)
461 if (flags & TF_HASCOLOR) {
462 color.r = swf_GetU8(t); // rgb
463 color.g = swf_GetU8(t);
464 color.b = swf_GetU8(t);
465 if (swf_GetTagID(t) == ST_DEFINETEXT2)
466 color.a = swf_GetU8(t);
470 if (flags & TF_HASXOFFSET)
472 if (flags & TF_HASYOFFSET)
474 if (flags & TF_HASFONT)
475 fontsize = swf_GetU16(t);
487 for (i = 0; i < num; i++) {
491 glyph = swf_GetBits(t, gbits);
492 adv = swf_GetBits(t, abits);
496 if (jobs & FEDTJ_PRINT) {
497 int code = f->glyph2ascii[glyph];
500 if (jobs & FEDTJ_MODIFY)
501 f->glyph[glyph].advance = adv * 20; //?
506 if ((id == fid) && (jobs & FEDTJ_PRINT))
508 if (jobs & FEDTJ_CALLBACK)
509 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
517 int swf_ParseDefineText(TAG * tag,
518 void (*callback) (void *self, int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
520 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
523 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
525 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
528 typedef struct _usagetmp {
533 static void updateusage(void *self, int *chars, int *xpos, int nr,
534 int fontid, int fontsize, int xstart, int ystart, RGBA * color)
536 usagetmp_t*u = (usagetmp_t*)self;
538 swf_FontInitUsage(u->font);
540 if(fontid!=u->font->id)
548 if(c<0 || c>u->font->numchars)
550 swf_FontUseGlyph(u->font, c, fontsize);
551 if(u->lasty == y && x>=u->lastx-200 && abs(u->lastx-x)<200 &&
552 u->last!=c && !swf_ShapeIsEmpty(u->font->glyph[u->last].shape) &&
553 !swf_ShapeIsEmpty(u->font->glyph[c].shape))
555 swf_FontUsePair(u->font, u->last, c);
558 /* FIXME: do we still need to divide advance by 20 for definefont3? */
559 u->lastx = x + (u->font->glyph[c].advance*fontsize/20480);
564 void swf_FontUpdateUsage(SWFFONT*f, TAG* tag)
568 u.lastx = -0x80000000;
569 u.lasty = -0x80000000;
571 swf_ParseDefineText(tag, updateusage, &u);
574 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
579 if ((!swf) || (!font))
582 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
588 switch (swf_GetTagID(t)) {
590 nid = swf_FontExtract_DefineFont(id, f, t);
595 nid = swf_FontExtract_DefineFont2(id, f, t);
598 case ST_DEFINEFONTALIGNZONES:
599 nid = swf_FontExtract_DefineFontAlignZones(id, f, t);
602 case ST_DEFINEFONTINFO:
603 case ST_DEFINEFONTINFO2:
604 nid = swf_FontExtract_DefineFontInfo(id, f, t);
610 nid = swf_FontExtract_DefineText(id, f, t, FEDTJ_MODIFY);
612 if(f->version>=3 && f->layout)
613 swf_FontUpdateUsage(f, t);
617 nid = swf_FontExtract_GlyphNames(id, f, t);
632 int swf_FontSetID(SWFFONT * f, U16 id)
640 void swf_LayoutFree(SWFLAYOUT * l)
644 rfx_free(l->kerning);
654 static void font_freeglyphnames(SWFFONT*f)
659 for (t = 0; t < f->numchars; t++)
661 if (f->glyphnames[t])
663 rfx_free(f->glyphnames[t]);
664 f->glyphnames[t] = 0;
667 rfx_free(f->glyphnames);
671 static void font_freeusage(SWFFONT*f)
675 rfx_free(f->use->chars);f->use->chars = 0;
677 if(f->use->neighbors) {
678 rfx_free(f->use->neighbors);f->use->neighbors = 0;
680 if(f->use->neighbors_hash) {
681 rfx_free(f->use->neighbors_hash);f->use->neighbors_hash = 0;
683 rfx_free(f->use); f->use = 0;
686 static void font_freelayout(SWFFONT*f)
689 swf_LayoutFree(f->layout);
693 static void font_freename(SWFFONT*f)
701 int swf_FontReduce_old(SWFFONT * f)
705 if ((!f) || (!f->use) || f->use->is_reduced)
710 for (i = 0; i < f->numchars; i++) {
711 if (f->glyph[i].shape && f->use->chars[i]) {
712 f->glyph2ascii[j] = f->glyph2ascii[i];
713 f->glyph[j] = f->glyph[i];
714 f->use->chars[i] = j;
717 f->glyph2ascii[i] = 0;
718 if(f->glyph[i].shape) {
719 swf_ShapeFree(f->glyph[i].shape);
720 f->glyph[i].shape = 0;
721 f->glyph[i].advance = 0;
723 f->use->chars[i] = -1;
727 for (i = 0; i < f->maxascii; i++) {
728 if(f->use->chars[f->ascii2glyph[i]]<0) {
729 f->ascii2glyph[i] = -1;
731 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
735 f->maxascii = max_unicode;
736 f->use->is_reduced = 1;
739 font_freeglyphnames(f);
744 int swf_FontReduce_swfc(SWFFONT * f)
748 if ((!f) || (!f->use) || f->use->is_reduced)
751 font_freeglyphnames(f);
754 for (i = 0; i < f->numchars; i++) {
755 if (f->glyph[i].shape && f->use->chars[i]) {
756 f->glyph2ascii[j] = f->glyph2ascii[i];
758 f->layout->bounds[j] = f->layout->bounds[i];
759 f->glyph[j] = f->glyph[i];
760 f->use->chars[i] = j;
763 f->glyph2ascii[i] = 0;
764 if(f->glyph[i].shape) {
765 swf_ShapeFree(f->glyph[i].shape);
766 f->glyph[i].shape = 0;
767 f->glyph[i].advance = 0;
769 f->use->chars[i] = -1;
772 f->use->used_glyphs = j;
773 for (i = 0; i < f->maxascii; i++) {
774 if(f->ascii2glyph[i] > -1) {
775 if (f->use->chars[f->ascii2glyph[i]]<0) {
776 f->use->chars[f->ascii2glyph[i]] = 0;
777 f->ascii2glyph[i] = -1;
779 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
780 f->use->chars[f->ascii2glyph[i]] = 1;
785 f->maxascii = max_unicode;
786 f->use->is_reduced = 1;
792 int swf_FontReduce(SWFFONT * f)
797 if ((!f) || (!f->use) || f->use->is_reduced)
801 font_freeglyphnames(f);
803 f->use->used_glyphs= 0;
804 for (i = 0; i < f->numchars; i++) {
805 if(!f->use->chars[i]) {
807 f->glyph2ascii[i] = 0;
809 if(f->glyph[i].shape) {
810 swf_ShapeFree(f->glyph[i].shape);
811 f->glyph[i].shape = 0;
812 f->glyph[i].advance = 0;
814 // f->use->used_glyphs++;
816 f->use->used_glyphs++;
820 for (i = 0; i < f->maxascii; i++) {
821 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
823 f->ascii2glyph[i] = -1;
829 f->maxascii = max_unicode;
830 f->numchars = max_glyph;
835 void swf_FontSort(SWFFONT * font)
843 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
845 for (i = 0; i < font->numchars; i++) {
848 for (i = 0; i < font->numchars; i++)
849 for (j = 0; j < i; j++) {
850 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
859 n1 = font->glyph2ascii[i];
860 n2 = font->glyph2ascii[j];
861 font->glyph2ascii[j] = n1;
862 font->glyph2ascii[i] = n2;
867 if (font->glyphnames) {
868 c1 = font->glyphnames[i];
869 c2 = font->glyphnames[j];
870 font->glyphnames[j] = c1;
871 font->glyphnames[i] = c2;
874 r1 = font->layout->bounds[i];
875 r2 = font->layout->bounds[j];
876 font->layout->bounds[j] = r1;
877 font->layout->bounds[i] = r2;
881 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
882 for (i = 0; i < font->numchars; i++) {
883 newpos[newplace[i]] = i;
885 for (i = 0; i < font->maxascii; i++) {
886 if (font->ascii2glyph[i] >= 0)
887 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
894 void swf_FontPrepareForEditText(SWFFONT * font)
897 swf_FontCreateLayout(font);
901 int swf_FontInitUsage(SWFFONT * f)
906 fprintf(stderr, "Usage initialized twice");
909 f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE));
910 f->use->smallest_size = 0xffff;
911 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
915 void swf_FontClearUsage(SWFFONT * f)
919 rfx_free(f->use->chars); f->use->chars = 0;
920 rfx_free(f->use); f->use = 0;
923 int swf_FontUse(SWFFONT * f, U8 * s)
928 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
929 swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
935 int swf_FontUseUTF8(SWFFONT * f, U8 * s, U16 size)
942 ascii = readUTF8char(&s);
943 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
944 swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
949 int swf_FontUseAll(SWFFONT* f)
954 swf_FontInitUsage(f);
955 for (i = 0; i < f->numchars; i++)
956 f->use->chars[i] = 1;
957 f->use->used_glyphs = f->numchars;
961 static unsigned hash2(int char1, int char2)
963 unsigned hash = char1^(char2<<8);
965 hash ^= (hash >> 11);
966 hash += (hash << 15);
969 static void hashadd(FONTUSAGE*u, int char1, int char2, int nr)
971 unsigned hash = hash2(char1, char2);
973 hash = hash%u->neighbors_hash_size;
974 if(!u->neighbors_hash[hash]) {
975 u->neighbors_hash[hash] = nr+1;
981 int swf_FontUseGetPair(SWFFONT * f, int char1, int char2)
983 FONTUSAGE*u = f->use;
984 if(!u || !u->neighbors_hash_size)
986 unsigned hash = hash2(char1, char2);
988 hash = hash%u->neighbors_hash_size;
989 int pos = u->neighbors_hash[hash];
993 u->neighbors[pos-1].char1 == char1 &&
994 u->neighbors[pos-1].char2 == char2) {
1001 void swf_FontUsePair(SWFFONT * f, int char1, int char2)
1004 swf_FontInitUsage(f);
1005 FONTUSAGE*u = f->use;
1007 if(u->num_neighbors*3 >= u->neighbors_hash_size*2) {
1008 if(u->neighbors_hash) {
1009 free(u->neighbors_hash);
1011 u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024;
1012 u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int));
1014 for(t=0;t<u->num_neighbors;t++) {
1015 hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t);
1019 int nr = swf_FontUseGetPair(f, char1, char2);
1021 if(u->num_neighbors == u->neighbors_size) {
1022 u->neighbors_size += 4096;
1023 u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
1025 u->neighbors[u->num_neighbors].char1 = char1;
1026 u->neighbors[u->num_neighbors].char2 = char2;
1027 u->neighbors[u->num_neighbors].num = 1;
1028 hashadd(u, char1, char2, u->num_neighbors);
1031 u->neighbors[nr-1].num++;
1035 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
1038 swf_FontInitUsage(f);
1039 if(glyph < 0 || glyph >= f->numchars)
1041 if(!f->use->chars[glyph])
1042 f->use->used_glyphs++;
1043 f->use->chars[glyph] = 1;
1044 if(size && size < f->use->smallest_size)
1045 f->use->smallest_size = size;
1049 int swf_FontSetDefine(TAG * t, SWFFONT * f)
1051 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
1056 swf_ResetWriteBits(t);
1057 swf_SetU16(t, f->id);
1061 for (i = 0; i < f->numchars; i++)
1062 if (f->glyph[i].shape) {
1064 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
1067 for (i = 0; i < j; i++)
1068 swf_SetU16(t, ofs[i] + j * 2);
1070 fprintf(stderr, "rfxswf: warning: Font is empty\n");
1074 for (i = 0; i < f->numchars; i++)
1075 if (f->glyph[i].shape)
1076 swf_SetSimpleShape(t, f->glyph[i].shape);
1078 swf_ResetWriteBits(t);
1083 static inline int fontSize(SWFFONT * font)
1087 for (t = 0; t < font->numchars; t++) {
1089 if(font->glyph[t].shape)
1090 l = (font->glyph[t].shape->bitlen + 7) / 8;
1095 return size + (font->numchars + 1) * 2;
1098 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
1103 swf_SetU16(tag, f->id);
1105 if (f->layout) flags |= 128; // haslayout
1106 if (f->numchars > 256)
1107 flags |= 4; // widecodes
1108 if (f->style & FONT_STYLE_BOLD)
1110 if (f->style & FONT_STYLE_ITALIC)
1111 flags |= 2; // italic
1112 if (f->maxascii >= 256)
1113 flags |= 4; //wide codecs
1114 if (fontSize(f) > 65535)
1115 flags |= 8; //wide offsets
1116 flags |= 8 | 4; //FIXME: the above check doesn't work
1118 if (f->encoding & FONT_ENCODING_ANSI)
1119 flags |= 16; // ansi
1120 if (f->encoding & FONT_ENCODING_UNICODE)
1121 flags |= 32; // unicode
1122 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1123 flags |= 64; // shiftjis
1125 swf_SetU8(tag, flags);
1126 swf_SetU8(tag, 0); //reserved flags
1129 swf_SetU8(tag, strlen((const char*)f->name)+1);
1130 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1132 /* font name (="") */
1136 /* number of glyphs */
1137 swf_SetU16(tag, f->numchars);
1138 /* font offset table */
1140 for (t = 0; t <= f->numchars; t++) {
1142 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1144 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1147 for (t = 0; t <= f->numchars; t++) {
1149 tag->data[pos + t * 4] = (tag->len - pos);
1150 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1151 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1152 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1154 if (tag->len - pos > 65535) {
1155 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1158 tag->data[pos + t * 2] = (tag->len - pos);
1159 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1161 if (t < f->numchars) {
1162 if(f->glyph[t].shape) {
1163 swf_SetSimpleShape(tag, f->glyph[t].shape);
1165 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1171 /* font code table */
1172 for (t = 0; t < f->numchars; t++) {
1173 if (flags & 4) { /* wide codes */
1174 if(f->glyph2ascii[t]) {
1175 swf_SetU16(tag, f->glyph2ascii[t]);
1180 if(f->glyph2ascii[t]) {
1181 swf_SetU8(tag, f->glyph2ascii[t]);
1189 swf_SetU16(tag, f->layout->ascent);
1190 swf_SetU16(tag, f->layout->descent);
1191 swf_SetU16(tag, f->layout->leading);
1192 for (t = 0; t < f->numchars; t++)
1193 swf_SetU16(tag, f->glyph[t].advance);
1194 for (t = 0; t < f->numchars; t++) {
1195 swf_ResetWriteBits(tag);
1196 swf_SetRect(tag, &f->layout->bounds[t]);
1198 swf_SetU16(tag, f->layout->kerningcount);
1199 for (t = 0; t < f->layout->kerningcount; t++) {
1200 if (flags & 4) { /* wide codes */
1201 swf_SetU16(tag, f->layout->kerning[t].char1);
1202 swf_SetU16(tag, f->layout->kerning[t].char2);
1204 swf_SetU8(tag, f->layout->kerning[t].char1);
1205 swf_SetU8(tag, f->layout->kerning[t].char2);
1207 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1213 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1215 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1216 f->layout->ascent = ascent;
1217 f->layout->descent = descent;
1218 f->layout->leading = leading;
1219 f->layout->kerningcount = 0;
1220 f->layout->kerning = 0;
1221 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1224 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1231 swf_ResetWriteBits(t);
1232 swf_SetU16(t, f->id);
1233 l = f->name ? strlen((const char *)f->name) : 0;
1238 swf_SetBlock(t, f->name, l);
1239 if (f->numchars >= 256)
1242 if (f->style & FONT_STYLE_BOLD)
1244 if (f->style & FONT_STYLE_ITALIC)
1246 if (f->style & FONT_ENCODING_ANSI)
1248 if (f->style & FONT_ENCODING_SHIFTJIS)
1250 if (f->style & FONT_ENCODING_UNICODE)
1253 swf_SetU8(t, (flags & 0xfe) | wide);
1255 for (i = 0; i < f->numchars; i++) {
1256 if (f->glyph[i].shape) {
1257 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1258 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1265 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1267 int id = swf_GetTagID(t);
1268 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1269 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1275 void swf_FontFree(SWFFONT * f)
1283 for (i = 0; i < f->numchars; i++)
1284 if (f->glyph[i].shape)
1286 swf_ShapeFree(f->glyph[i].shape);
1287 f->glyph[i].shape = NULL;
1294 rfx_free(f->ascii2glyph);
1295 f->ascii2glyph = NULL;
1299 rfx_free(f->glyph2ascii);
1300 f->glyph2ascii = NULL;
1304 font_freeglyphnames(f);
1310 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1316 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1317 | (y ? TF_HASYOFFSET : 0);
1319 swf_SetU8(t, flags);
1321 swf_SetU16(t, font->id);
1323 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1324 swf_SetRGBA(t, color);
1326 swf_SetRGB(t, color);
1329 if(x != SET_TO_ZERO) {
1330 if(x>32767 || x<-32768)
1331 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1338 if(y != SET_TO_ZERO) {
1339 if(y>32767 || y<-32768)
1340 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1347 swf_SetU16(t, size);
1352 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1356 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1360 if (!strcmp(encoding, "UTF8"))
1362 else if (!strcmp(encoding, "iso-8859-1"))
1365 fprintf(stderr, "Unknown encoding: %s", encoding);
1373 c = readUTF8char(&s);
1375 if (c < font->maxascii)
1376 glyph = font->ascii2glyph[c];
1378 g = swf_CountUBits(glyph, g);
1379 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1390 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1395 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1398 if (!strcmp(encoding, "UTF8"))
1400 else if (!strcmp(encoding, "iso-8859-1"))
1403 fprintf(stderr, "Unknown encoding: %s", encoding);
1406 swf_SetU8(t, l); //placeholder
1414 c = readUTF8char(&s);
1416 if (c < font->maxascii)
1417 g = font->ascii2glyph[c];
1419 swf_SetBits(t, g, gbits);
1420 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1422 /* We split into 127 characters per text field.
1423 We could do 255, by the (formerly wrong) flash specification,
1424 but some SWF parsing code out there still assumes that char blocks
1425 are at max 127 characters, and it would save only a few bits.
1432 PUT8(&t->data[pos], l);
1434 swf_ResetWriteBits(t);
1438 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1440 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1443 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1445 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1448 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1450 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1453 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1455 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1458 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1465 if (*s < font->maxascii)
1466 g = font->ascii2glyph[*s];
1468 res += font->glyph[g].advance / 20;
1472 res = (res * scale) / 100;
1477 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1484 int c = readUTF8char(&s);
1485 if(c==13 || c==10) {
1490 ypos+=font->layout->leading;
1493 if (c < font->maxascii) {
1494 int g = font->ascii2glyph[c];
1496 SRECT rn = font->layout->bounds[g];
1497 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1498 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1499 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1500 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1501 swf_ExpandRect2(&r, &rn);
1502 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1510 SWFFONT *swf_ReadFont(const char *filename)
1516 f = open(filename, O_RDONLY|O_BINARY);
1518 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1519 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1525 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1532 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)
1534 swf_SetRect(tag, &r);
1535 swf_ResetWriteBits(tag);
1537 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1539 flags |= ET_HASTEXT;
1541 flags |= ET_HASTEXTCOLOR;
1543 flags |= ET_HASMAXLENGTH;
1545 flags |= ET_HASFONT;
1547 flags |= ET_HASLAYOUT;
1549 swf_SetBits(tag, flags, 16);
1551 if (flags & ET_HASFONT) {
1552 swf_SetU16(tag, font); //font
1553 swf_SetU16(tag, height); //fontheight
1555 if (flags & ET_HASTEXTCOLOR) {
1556 swf_SetRGBA(tag, color);
1558 if (flags & ET_HASMAXLENGTH) {
1559 swf_SetU16(tag, maxlength); //maxlength
1561 if (flags & ET_HASLAYOUT) {
1562 swf_SetU8(tag, layout->align); //align
1563 swf_SetU16(tag, layout->leftmargin); //left margin
1564 swf_SetU16(tag, layout->rightmargin); //right margin
1565 swf_SetU16(tag, layout->indent); //indent
1566 swf_SetU16(tag, layout->leading); //leading
1568 swf_SetString(tag, variable);
1569 if (flags & ET_HASTEXT)
1570 swf_SetString(tag, text);
1573 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1577 U8 *utext = (U8 *) strdup(text);
1583 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1584 ystep = font->layout->leading;
1586 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1587 /* Hm, without layout information, we can't compute a bounding
1588 box. We could call swf_FontCreateLayout to create a layout,
1589 but the caller probably doesn't want us to mess up his font
1592 r.xmin = r.ymin = 0;
1593 r.xmax = r.ymax = 1024 * 20;
1597 swf_SetRect(tag, &r);
1599 /* The text matrix is pretty boring, as it doesn't apply to
1600 individual characters, but rather whole text objects (or
1601 at least whole char records- haven't tested).
1602 So it can't do anything which we can't already do with
1603 the placeobject tag we use for placing the text on the scene.
1605 swf_SetMatrix(tag, 0);
1607 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1608 swf_SetU8(tag, gbits);
1609 swf_SetU8(tag, abits);
1615 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1618 while(*next && *next!=13 && *next!=10 && count<127) {
1619 readUTF8char(&next);
1622 if(next[0] == 13 || next[0] == 10) {
1627 if(next[0] == 13 && next[1] == 10)
1630 if(next[0] == 13 || next[0] == 10) {
1635 /* now set the text params- notice that a font size of
1636 1024 (or 1024*20 for definefont3) means that the glyphs will
1637 be displayed exactly as they would be in/with a defineshape.
1638 This is not documented in the specs.
1641 /* set the actual text- notice that we just pass our scale
1642 parameter over, as TextSetCharRecord calculates with
1644 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1654 void swf_FontCreateLayout(SWFFONT * f)
1663 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1664 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1665 f->layout->ascent = 0;
1666 f->layout->descent = 0;
1668 for (t = 0; t < f->numchars; t++) {
1672 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1674 fprintf(stderr, "Shape parse error\n");
1677 bbox = swf_GetShapeBoundingBox(shape2);
1678 swf_Shape2Free(shape2);
1679 f->layout->bounds[t] = bbox;
1681 width = (bbox.xmax);
1683 /* The following is a heuristic- it may be that extractfont_DefineText
1684 has already found out some widths for individual characters (from the way
1685 they are used)- we now have to guess whether that width might be possible,
1686 which is the case if it isn't either much too big or much too small */
1687 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1688 f->glyph[t].advance = width;
1690 if (-bbox.ymin > f->layout->ascent)
1691 f->layout->ascent = -bbox.ymin;
1692 if (bbox.ymax > f->layout->descent)
1693 f->layout->descent = bbox.ymax;
1697 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1699 U8 *s = (U8 *) text;
1705 U32 c = readUTF8char(&s);
1706 int g = font->ascii2glyph[c];
1707 shape = font->glyph[g].shape;
1708 if (((int) g) < 0) {
1709 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1712 shape2 = swf_ShapeToShape2(shape);
1715 if (l->type == moveTo) {
1717 to.x = l->x * size / 100.0 / 20.0 + advance;
1718 to.y = l->y * size / 100.0 / 20.0;
1719 draw->moveTo(draw, &to);
1720 } else if (l->type == lineTo) {
1722 to.x = l->x * size / 100.0 / 20.0 + advance;
1723 to.y = l->y * size / 100.0 / 20.0;
1724 draw->lineTo(draw, &to);
1725 } else if (l->type == splineTo) {
1727 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1728 mid.y = l->sy * size / 100.0 / 20.0;
1729 to.x = l->x * size / 100.0 / 20.0 + advance;
1730 to.y = l->y * size / 100.0 / 20.0;
1731 draw->splineTo(draw, &mid, &to);
1735 swf_Shape2Free(shape2);
1736 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1740 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1743 swf_FontCreateLayout(font);
1746 memset(&swf, 0, sizeof(SWF));
1747 swf.fileVersion = 9;
1748 swf.frameRate = 0x4000;
1749 swf.movieSize.xmax = 200;
1750 swf.movieSize.ymax = 200;
1752 if(!font->id) font->id=1;
1755 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1756 swf_FontSetDefine2(tag, font);
1758 char*name = font->name?(char*)font->name:"font";
1760 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1761 swf_SetU16(tag, font->id);
1762 swf_SetString(tag, name);
1763 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1765 swf_SetU16(tag, font->id);
1766 swf_SetString(tag, name);
1767 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1769 tag = swf_InsertTag(tag, ST_END);
1770 swf_SaveSWF(&swf, filename);
1774 void swf_WriteFont(SWFFONT * font, char *filename)
1777 swf_FontCreateLayout(font);
1786 memset(&swf, 0, sizeof(SWF));
1787 swf.fileVersion = 8;
1788 swf.frameRate = 0x4000;
1789 swf.movieSize.xmax = 1024*20;
1790 swf.movieSize.ymax = 768*20;
1793 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1794 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1796 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1797 swf_FontSetDefine2(tag, font);
1799 if(font->glyphnames) {
1801 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1802 swf_SetU16(tag, font->id);
1803 swf_SetU16(tag, font->numchars);
1804 for (c = 0; c < font->numchars; c++) {
1805 if (font->glyphnames[c])
1806 swf_SetString(tag, font->glyphnames[c]);
1808 swf_SetString(tag, "");
1814 RGBA white = {255,255,255,255};
1815 RGBA black = {255,0,0,0};
1816 RGBA gray50 = {255,128,128,128};
1817 RGBA green = {255,0,255,0};
1819 SCOORD miny = SCOORD_MAX;
1820 SCOORD maxy = SCOORD_MIN;
1822 U16 max_advance = 0;
1823 char*flags = rfx_calloc(font->numchars);
1824 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1825 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1826 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1827 for(t=0;t<font->numchars;t++) {
1828 SHAPE*s = font->glyph[t].shape;
1829 SHAPE2*s2 = swf_ShapeToShape2(s);
1830 SRECT r = swf_GetShapeBoundingBox(s2);
1832 // inside a definefont3, everything is 20x the resolution:
1833 double rx1 = r.xmin / 20.0;
1834 double ry1 = r.ymin / 20.0;
1835 double rx2 = r.xmax / 20.0;
1836 double ry2 = r.ymax / 20.0;
1841 if(ry1<miny) {miny=ry1;}
1842 if(ry2>maxy) {maxy=ry2;}
1843 swf_Shape2Free(s2);free(s2);
1844 width += font->glyph[t].advance;
1845 if(font->glyph[t].advance>max_advance)
1846 max_advance = font->glyph[t].advance;
1849 if(miny==SCOORD_MAX) miny=maxy=0;
1850 if(miny==maxy) maxy=miny+1;
1852 /* scale the font so that it's 256 pixels high */
1853 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1854 double overlarge_factor;
1858 overlarge_factor = scale / 32767.0;
1861 overlarge_factor = 1.0;
1865 int spriteid = id++;
1868 r.ymin = miny*fontsize/1024;
1869 r.xmax = width*fontsize/20480;
1870 r.ymax = maxy*fontsize/1024;
1871 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1872 swf_SetU16(tag, textid);
1873 swf_SetRect(tag, &r);
1874 swf_SetMatrix(tag, NULL);
1877 U8 gbits = swf_CountBits(font->numchars, 0);
1878 swf_SetU8(tag, gbits);
1879 swf_SetU8(tag, abits);
1881 RGBA rgb = {255,0,0,0};
1883 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1884 ActionTAG*array = 0;
1886 array = action_PushString(array, "xpos");
1887 for(t=0;t<font->numchars;t++) {
1889 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1890 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1891 x += width * overlarge_factor;
1892 swf_SetBits(tag, t, gbits);
1893 swf_SetBits(tag, width, abits);
1894 swf_SetU8(tag, 128);
1896 array = action_PushInt(array, x/20);
1897 array = action_PushInt(array, font->numchars+1);
1898 array = action_InitArray(array);
1899 array = action_SetVariable(array);
1903 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1906 int ls = swf_ShapeAddLineStyle(s,20,&white);
1908 swf_SetU16(tag,shapeid);
1914 swf_SetRect(tag,&r);
1915 swf_SetShapeHeader(tag,s);
1916 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1918 /* Ç and  are good chars to test ascent/descent extend */
1919 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1920 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1922 swf_ShapeSetMove(tag,s,0,y1);
1923 swf_ShapeSetLine(tag,s,width,0);
1924 swf_ShapeSetMove(tag,s,0,y2);
1925 swf_ShapeSetLine(tag,s,width,0);
1927 swf_ShapeSetEnd(tag);
1929 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1930 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1935 for(t=0;t<font->numchars;t++) {
1936 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1939 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1940 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1941 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1943 swf_SetU16(tag,shapeid);
1949 swf_SetRect(tag,&r);
1950 swf_SetShapeHeader(tag,s);
1951 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1952 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1953 SHAPELINE*l = s2->lines;
1954 int lastx=0,lasty=0;
1956 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1957 double y1 = -miny*20*scale*2/20480.0;
1958 double scalex = scale*2/20480.0;
1959 double scaley = scale*2/20480.0;
1962 int lx = (l->x)*scalex+x1;
1963 int ly = (l->y)*scaley+y1;
1964 int sx = (l->sx)*scalex+x1;
1965 int sy = (l->sy)*scaley+y1;
1966 if(l->type == moveTo) {
1967 swf_ShapeSetMove(tag,s,lx,ly);
1968 } else if(l->type == lineTo) {
1969 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1970 } else if(l->type == splineTo) {
1971 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1978 if(font->alignzones) {
1979 ALIGNZONE*zone = &font->alignzones[t];
1980 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1981 if((zone->x&zone->dx)!=0xffff) {
1982 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1983 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1984 swf_ShapeSetMove(tag,s,x,0);
1985 swf_ShapeSetLine(tag,s,0,1024*20);
1986 swf_ShapeSetMove(tag,s,dx,0);
1987 swf_ShapeSetLine(tag,s,0,1024*20);
1989 if((zone->y&zone->dy)!=0xffff) {
1990 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
1991 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
1992 swf_ShapeSetMove(tag,s,0,y);
1993 swf_ShapeSetLine(tag,s,1024*20,0);
1994 swf_ShapeSetMove(tag,s,0,dy);
1995 swf_ShapeSetLine(tag,s,1024*20,0);
1999 swf_ShapeSetEnd(tag);
2002 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2004 swf_SetU16(tag, spriteid);
2006 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2007 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2008 tag = swf_InsertTag(tag, ST_END);
2009 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2011 swf_GetMatrix(0, &m);
2014 sprintf(txt, "char%d", font->numchars-t);
2015 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
2019 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
2021 RGBA blue = {0xff,0xc0,0xc0,0xff};
2022 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
2023 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2025 swf_SetU16(tag, spriteid2);
2027 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2028 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2029 tag = swf_InsertTag(tag, ST_END);
2030 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2031 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
2034 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2035 swf_SetU16(tag, spriteid);
2037 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2039 swf_GetMatrix(0, &m);
2040 m.sx = 65536 * overlarge_factor;
2041 m.sy = 65536 * overlarge_factor;
2043 m.ty = -miny*256*20/(maxy-miny);
2044 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
2045 tag = swf_InsertTag(tag, ST_END);
2046 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2047 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
2050 RGBA blue2 = {0x80,0x80,0xff,0x80};
2051 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2053 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2054 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2056 swf_SetU16(tag, spriteid3);
2058 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2059 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2060 tag = swf_InsertTag(tag, ST_END);
2061 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2062 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2066 " var mouseListener = new Object();"
2069 " var currentMouseOver, currentChar;"
2070 " mouseListener.onMouseDown = function() { "
2071 " eval(\"_root.char\"+currentChar)._y = 20000;"
2072 " currentChar = currentMouseOver;"
2073 " var i = currentMouseOver;"
2074 " eval(\"_root.char\"+i)._y = 256;"
2075 " _root.marker2._yscale=256*100;"
2076 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2077 " _root.marker2._x=xpos[i]+myx;"
2079 " mouseListener.onMouseMove = function() { "
2080 " if(_ymouse<256) {"
2081 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2086 " setInterval( function(){ "
2087 " if(_ymouse<256) {"
2088 " var i, x=_xmouse-_root.textbar._x;"
2089 " for(i=xpos.length-1;i>0;i--) {"
2090 " if(x<xpos[i-1]) break;"
2092 " currentMouseOver = i;"
2093 " _root.marker._yscale=256*100;"
2094 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2095 " _root.marker._x=xpos[i]+myx;"
2096 " _root.textbar._x += 0.05;"
2098 " if(myx+speed>0) {"
2100 " } else if(myx+speed<-xpos[0]+1024) {"
2104 " _root.textbar._x = myx;"
2105 " _root.marker._x += speed;"
2106 " _root.marker2._x += speed;"
2108 " Mouse.addListener(mouseListener);"
2110 ActionTAG* atag = swf_ActionCompile(data, 6);
2112 tag = swf_InsertTag(tag, ST_DOACTION);
2113 swf_ActionSet(tag, array);
2114 swf_ActionSet(tag, atag);
2116 swf_ActionFree(atag);
2118 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2125 tag = swf_InsertTag(tag, ST_END);
2127 swf.compressed = -1;
2128 swf_SaveSWF(&swf, filename);