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,2005,2006,2007,2008,2009 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)
549 if(c<0 || c>u->font->numchars)
551 swf_FontUseGlyph(u->font, c, fontsize);
552 if(u->lasty == y && x>=u->lastx-200 && abs(u->lastx-x)<200 &&
553 u->last!=c && !swf_ShapeIsEmpty(u->font->glyph[u->last].shape) &&
554 !swf_ShapeIsEmpty(u->font->glyph[c].shape))
556 /* ignore the first pair of every word (caps subset hack). */
558 swf_FontUsePair(u->font, u->last, c);
564 /* FIXME: do we still need to divide advance by 20 for definefont3? */
565 u->lastx = x + (u->font->glyph[c].advance*fontsize/20480);
570 void swf_FontUpdateUsage(SWFFONT*f, TAG* tag)
574 u.lastx = -0x80000000;
575 u.lasty = -0x80000000;
577 swf_ParseDefineText(tag, updateusage, &u);
580 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
585 if ((!swf) || (!font))
588 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
594 switch (swf_GetTagID(t)) {
596 nid = swf_FontExtract_DefineFont(id, f, t);
601 nid = swf_FontExtract_DefineFont2(id, f, t);
604 case ST_DEFINEFONTALIGNZONES:
605 nid = swf_FontExtract_DefineFontAlignZones(id, f, t);
608 case ST_DEFINEFONTINFO:
609 case ST_DEFINEFONTINFO2:
610 nid = swf_FontExtract_DefineFontInfo(id, f, t);
616 nid = swf_FontExtract_DefineText(id, f, t, FEDTJ_MODIFY);
618 if(f->version>=3 && f->layout)
619 swf_FontUpdateUsage(f, t);
623 nid = swf_FontExtract_GlyphNames(id, f, t);
638 int swf_FontSetID(SWFFONT * f, U16 id)
646 void swf_LayoutFree(SWFLAYOUT * l)
650 rfx_free(l->kerning);
660 static void font_freeglyphnames(SWFFONT*f)
665 for (t = 0; t < f->numchars; t++)
667 if (f->glyphnames[t])
669 rfx_free(f->glyphnames[t]);
670 f->glyphnames[t] = 0;
673 rfx_free(f->glyphnames);
677 static void font_freeusage(SWFFONT*f)
681 rfx_free(f->use->chars);f->use->chars = 0;
683 if(f->use->neighbors) {
684 rfx_free(f->use->neighbors);f->use->neighbors = 0;
686 if(f->use->neighbors_hash) {
687 rfx_free(f->use->neighbors_hash);f->use->neighbors_hash = 0;
689 rfx_free(f->use); f->use = 0;
692 static void font_freelayout(SWFFONT*f)
695 swf_LayoutFree(f->layout);
699 static void font_freename(SWFFONT*f)
707 int swf_FontReduce_old(SWFFONT * f)
711 if ((!f) || (!f->use) || f->use->is_reduced)
716 for (i = 0; i < f->numchars; i++) {
717 if (f->glyph[i].shape && f->use->chars[i]) {
718 f->glyph2ascii[j] = f->glyph2ascii[i];
719 f->glyph[j] = f->glyph[i];
720 f->use->chars[i] = j;
723 f->glyph2ascii[i] = 0;
724 if(f->glyph[i].shape) {
725 swf_ShapeFree(f->glyph[i].shape);
726 f->glyph[i].shape = 0;
727 f->glyph[i].advance = 0;
729 f->use->chars[i] = -1;
733 for (i = 0; i < f->maxascii; i++) {
734 if(f->use->chars[f->ascii2glyph[i]]<0) {
735 f->ascii2glyph[i] = -1;
737 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
741 f->maxascii = max_unicode;
742 f->use->is_reduced = 1;
745 font_freeglyphnames(f);
750 int swf_FontReduce_swfc(SWFFONT * f)
754 if ((!f) || (!f->use) || f->use->is_reduced)
757 font_freeglyphnames(f);
760 for (i = 0; i < f->numchars; i++) {
761 if (f->glyph[i].shape && f->use->chars[i]) {
762 f->glyph2ascii[j] = f->glyph2ascii[i];
764 f->layout->bounds[j] = f->layout->bounds[i];
765 f->glyph[j] = f->glyph[i];
766 f->use->chars[i] = j;
769 f->glyph2ascii[i] = 0;
770 if(f->glyph[i].shape) {
771 swf_ShapeFree(f->glyph[i].shape);
772 f->glyph[i].shape = 0;
773 f->glyph[i].advance = 0;
775 f->use->chars[i] = -1;
778 f->use->used_glyphs = j;
779 for (i = 0; i < f->maxascii; i++) {
780 if(f->ascii2glyph[i] > -1) {
781 if (f->use->chars[f->ascii2glyph[i]]<0) {
782 f->use->chars[f->ascii2glyph[i]] = 0;
783 f->ascii2glyph[i] = -1;
785 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
786 f->use->chars[f->ascii2glyph[i]] = 1;
791 f->maxascii = max_unicode;
792 f->use->is_reduced = 1;
798 int swf_FontReduce(SWFFONT * f)
803 if ((!f) || (!f->use) || f->use->is_reduced)
807 font_freeglyphnames(f);
809 f->use->used_glyphs= 0;
810 for (i = 0; i < f->numchars; i++) {
811 if(!f->use->chars[i]) {
813 f->glyph2ascii[i] = 0;
815 if(f->glyph[i].shape) {
816 swf_ShapeFree(f->glyph[i].shape);
817 f->glyph[i].shape = 0;
818 f->glyph[i].advance = 0;
820 // f->use->used_glyphs++;
822 f->use->used_glyphs++;
826 for (i = 0; i < f->maxascii; i++) {
827 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
829 f->ascii2glyph[i] = -1;
835 f->maxascii = max_unicode;
836 f->numchars = max_glyph;
841 void swf_FontSort(SWFFONT * font)
849 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
851 for (i = 0; i < font->numchars; i++) {
854 for (i = 0; i < font->numchars; i++)
855 for (j = 0; j < i; j++) {
856 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
865 n1 = font->glyph2ascii[i];
866 n2 = font->glyph2ascii[j];
867 font->glyph2ascii[j] = n1;
868 font->glyph2ascii[i] = n2;
873 if (font->glyphnames) {
874 c1 = font->glyphnames[i];
875 c2 = font->glyphnames[j];
876 font->glyphnames[j] = c1;
877 font->glyphnames[i] = c2;
880 r1 = font->layout->bounds[i];
881 r2 = font->layout->bounds[j];
882 font->layout->bounds[j] = r1;
883 font->layout->bounds[i] = r2;
887 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
888 for (i = 0; i < font->numchars; i++) {
889 newpos[newplace[i]] = i;
891 for (i = 0; i < font->maxascii; i++) {
892 if (font->ascii2glyph[i] >= 0)
893 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
900 void swf_FontPrepareForEditText(SWFFONT * font)
903 swf_FontCreateLayout(font);
907 int swf_FontInitUsage(SWFFONT * f)
912 fprintf(stderr, "Usage initialized twice");
915 f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE));
916 f->use->smallest_size = 0xffff;
917 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
921 void swf_FontClearUsage(SWFFONT * f)
925 rfx_free(f->use->chars); f->use->chars = 0;
926 rfx_free(f->use); f->use = 0;
929 int swf_FontUse(SWFFONT * f, U8 * s)
934 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
935 swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
941 int swf_FontUseUTF8(SWFFONT * f, U8 * s, U16 size)
948 ascii = readUTF8char(&s);
949 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
950 swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
955 int swf_FontUseAll(SWFFONT* f)
960 swf_FontInitUsage(f);
961 for (i = 0; i < f->numchars; i++)
962 f->use->chars[i] = 1;
963 f->use->used_glyphs = f->numchars;
967 static unsigned hash2(int char1, int char2)
969 unsigned hash = char1^(char2<<8);
971 hash ^= (hash >> 11);
972 hash += (hash << 15);
975 static void hashadd(FONTUSAGE*u, int char1, int char2, int nr)
977 unsigned hash = hash2(char1, char2);
979 hash = hash%u->neighbors_hash_size;
980 if(!u->neighbors_hash[hash]) {
981 u->neighbors_hash[hash] = nr+1;
987 int swf_FontUseGetPair(SWFFONT * f, int char1, int char2)
989 FONTUSAGE*u = f->use;
990 if(!u || !u->neighbors_hash_size)
992 unsigned hash = hash2(char1, char2);
994 hash = hash%u->neighbors_hash_size;
995 int pos = u->neighbors_hash[hash];
999 u->neighbors[pos-1].char1 == char1 &&
1000 u->neighbors[pos-1].char2 == char2) {
1007 void swf_FontUsePair(SWFFONT * f, int char1, int char2)
1010 swf_FontInitUsage(f);
1011 FONTUSAGE*u = f->use;
1013 if(u->num_neighbors*3 >= u->neighbors_hash_size*2) {
1014 if(u->neighbors_hash) {
1015 free(u->neighbors_hash);
1017 u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024;
1018 u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int));
1020 for(t=0;t<u->num_neighbors;t++) {
1021 hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t);
1025 int nr = swf_FontUseGetPair(f, char1, char2);
1027 if(u->num_neighbors == u->neighbors_size) {
1028 u->neighbors_size += 4096;
1029 u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
1031 u->neighbors[u->num_neighbors].char1 = char1;
1032 u->neighbors[u->num_neighbors].char2 = char2;
1033 u->neighbors[u->num_neighbors].num = 1;
1034 hashadd(u, char1, char2, u->num_neighbors);
1037 u->neighbors[nr-1].num++;
1041 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
1044 swf_FontInitUsage(f);
1045 if(glyph < 0 || glyph >= f->numchars)
1047 if(!f->use->chars[glyph])
1048 f->use->used_glyphs++;
1049 f->use->chars[glyph] = 1;
1050 if(size && size < f->use->smallest_size)
1051 f->use->smallest_size = size;
1055 int swf_FontSetDefine(TAG * t, SWFFONT * f)
1057 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
1062 swf_ResetWriteBits(t);
1063 swf_SetU16(t, f->id);
1067 for (i = 0; i < f->numchars; i++)
1068 if (f->glyph[i].shape) {
1070 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
1073 for (i = 0; i < j; i++)
1074 swf_SetU16(t, ofs[i] + j * 2);
1076 fprintf(stderr, "rfxswf: warning: Font is empty\n");
1080 for (i = 0; i < f->numchars; i++)
1081 if (f->glyph[i].shape)
1082 swf_SetSimpleShape(t, f->glyph[i].shape);
1084 swf_ResetWriteBits(t);
1089 static inline int fontSize(SWFFONT * font)
1093 for (t = 0; t < font->numchars; t++) {
1095 if(font->glyph[t].shape)
1096 l = (font->glyph[t].shape->bitlen + 7) / 8;
1101 return size + (font->numchars + 1) * 2;
1104 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
1109 swf_SetU16(tag, f->id);
1111 if (f->layout) flags |= 128; // haslayout
1112 if (f->numchars > 256)
1113 flags |= 4; // widecodes
1114 if (f->style & FONT_STYLE_BOLD)
1116 if (f->style & FONT_STYLE_ITALIC)
1117 flags |= 2; // italic
1118 if (f->maxascii >= 256)
1119 flags |= 4; //wide codecs
1120 if (fontSize(f) > 65535)
1121 flags |= 8; //wide offsets
1122 flags |= 8 | 4; //FIXME: the above check doesn't work
1124 if (f->encoding & FONT_ENCODING_ANSI)
1125 flags |= 16; // ansi
1126 if (f->encoding & FONT_ENCODING_UNICODE)
1127 flags |= 32; // unicode
1128 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1129 flags |= 64; // shiftjis
1131 swf_SetU8(tag, flags);
1132 swf_SetU8(tag, 0); //reserved flags
1135 swf_SetU8(tag, strlen((const char*)f->name)+1);
1136 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1138 /* font name (="") */
1142 /* number of glyphs */
1143 swf_SetU16(tag, f->numchars);
1144 /* font offset table */
1146 for (t = 0; t <= f->numchars; t++) {
1148 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1150 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1153 for (t = 0; t <= f->numchars; t++) {
1155 tag->data[pos + t * 4] = (tag->len - pos);
1156 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1157 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1158 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1160 if (tag->len - pos > 65535) {
1161 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1164 tag->data[pos + t * 2] = (tag->len - pos);
1165 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1167 if (t < f->numchars) {
1168 if(f->glyph[t].shape) {
1169 swf_SetSimpleShape(tag, f->glyph[t].shape);
1171 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1177 /* font code table */
1178 for (t = 0; t < f->numchars; t++) {
1179 if (flags & 4) { /* wide codes */
1180 if(f->glyph2ascii[t]) {
1181 swf_SetU16(tag, f->glyph2ascii[t]);
1186 if(f->glyph2ascii[t]) {
1187 swf_SetU8(tag, f->glyph2ascii[t]);
1195 swf_SetU16(tag, f->layout->ascent);
1196 swf_SetU16(tag, f->layout->descent);
1197 swf_SetU16(tag, f->layout->leading);
1198 for (t = 0; t < f->numchars; t++)
1199 swf_SetU16(tag, f->glyph[t].advance);
1200 for (t = 0; t < f->numchars; t++) {
1201 swf_ResetWriteBits(tag);
1202 swf_SetRect(tag, &f->layout->bounds[t]);
1204 swf_SetU16(tag, f->layout->kerningcount);
1205 for (t = 0; t < f->layout->kerningcount; t++) {
1206 if (flags & 4) { /* wide codes */
1207 swf_SetU16(tag, f->layout->kerning[t].char1);
1208 swf_SetU16(tag, f->layout->kerning[t].char2);
1210 swf_SetU8(tag, f->layout->kerning[t].char1);
1211 swf_SetU8(tag, f->layout->kerning[t].char2);
1213 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1219 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1221 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1222 f->layout->ascent = ascent;
1223 f->layout->descent = descent;
1224 f->layout->leading = leading;
1225 f->layout->kerningcount = 0;
1226 f->layout->kerning = 0;
1227 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1230 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1237 swf_ResetWriteBits(t);
1238 swf_SetU16(t, f->id);
1239 l = f->name ? strlen((const char *)f->name) : 0;
1244 swf_SetBlock(t, f->name, l);
1245 if (f->numchars >= 256)
1248 if (f->style & FONT_STYLE_BOLD)
1250 if (f->style & FONT_STYLE_ITALIC)
1252 if (f->style & FONT_ENCODING_ANSI)
1254 if (f->style & FONT_ENCODING_SHIFTJIS)
1256 if (f->style & FONT_ENCODING_UNICODE)
1259 swf_SetU8(t, (flags & 0xfe) | wide);
1261 for (i = 0; i < f->numchars; i++) {
1262 if (f->glyph[i].shape) {
1263 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1264 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1271 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1273 int id = swf_GetTagID(t);
1274 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1275 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1281 void swf_FontFree(SWFFONT * f)
1289 for (i = 0; i < f->numchars; i++)
1290 if (f->glyph[i].shape)
1292 swf_ShapeFree(f->glyph[i].shape);
1293 f->glyph[i].shape = NULL;
1300 rfx_free(f->ascii2glyph);
1301 f->ascii2glyph = NULL;
1305 rfx_free(f->glyph2ascii);
1306 f->glyph2ascii = NULL;
1310 font_freeglyphnames(f);
1316 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1322 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1323 | (y ? TF_HASYOFFSET : 0);
1325 swf_SetU8(t, flags);
1327 swf_SetU16(t, font->id);
1329 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1330 swf_SetRGBA(t, color);
1332 swf_SetRGB(t, color);
1335 if(x != SET_TO_ZERO) {
1336 if(x>32767 || x<-32768)
1337 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1344 if(y != SET_TO_ZERO) {
1345 if(y>32767 || y<-32768)
1346 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1353 swf_SetU16(t, size);
1358 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1362 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1366 if (!strcmp(encoding, "UTF8"))
1368 else if (!strcmp(encoding, "iso-8859-1"))
1371 fprintf(stderr, "Unknown encoding: %s", encoding);
1379 c = readUTF8char(&s);
1381 if (c < font->maxascii)
1382 glyph = font->ascii2glyph[c];
1384 g = swf_CountUBits(glyph, g);
1385 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1396 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1401 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1404 if (!strcmp(encoding, "UTF8"))
1406 else if (!strcmp(encoding, "iso-8859-1"))
1409 fprintf(stderr, "Unknown encoding: %s", encoding);
1412 swf_SetU8(t, l); //placeholder
1420 c = readUTF8char(&s);
1422 if (c < font->maxascii)
1423 g = font->ascii2glyph[c];
1425 swf_SetBits(t, g, gbits);
1426 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1428 /* We split into 127 characters per text field.
1429 We could do 255, by the (formerly wrong) flash specification,
1430 but some SWF parsing code out there still assumes that char blocks
1431 are at max 127 characters, and it would save only a few bits.
1438 PUT8(&t->data[pos], l);
1440 swf_ResetWriteBits(t);
1444 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1446 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1449 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1451 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1454 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1456 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1459 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1461 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1464 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1471 if (*s < font->maxascii)
1472 g = font->ascii2glyph[*s];
1474 res += font->glyph[g].advance / 20;
1478 res = (res * scale) / 100;
1483 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1490 int c = readUTF8char(&s);
1491 if(c==13 || c==10) {
1496 ypos+=font->layout->leading;
1499 if (c < font->maxascii) {
1500 int g = font->ascii2glyph[c];
1502 SRECT rn = font->layout->bounds[g];
1503 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1504 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1505 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1506 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1507 swf_ExpandRect2(&r, &rn);
1508 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1516 SWFFONT *swf_ReadFont(const char *filename)
1522 f = open(filename, O_RDONLY|O_BINARY);
1524 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1525 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1531 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1538 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)
1540 swf_SetRect(tag, &r);
1541 swf_ResetWriteBits(tag);
1543 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1545 flags |= ET_HASTEXT;
1547 flags |= ET_HASTEXTCOLOR;
1549 flags |= ET_HASMAXLENGTH;
1551 flags |= ET_HASFONT;
1553 flags |= ET_HASLAYOUT;
1555 swf_SetBits(tag, flags, 16);
1557 if (flags & ET_HASFONT) {
1558 swf_SetU16(tag, font); //font
1559 swf_SetU16(tag, height); //fontheight
1561 if (flags & ET_HASTEXTCOLOR) {
1562 swf_SetRGBA(tag, color);
1564 if (flags & ET_HASMAXLENGTH) {
1565 swf_SetU16(tag, maxlength); //maxlength
1567 if (flags & ET_HASLAYOUT) {
1568 swf_SetU8(tag, layout->align); //align
1569 swf_SetU16(tag, layout->leftmargin); //left margin
1570 swf_SetU16(tag, layout->rightmargin); //right margin
1571 swf_SetU16(tag, layout->indent); //indent
1572 swf_SetU16(tag, layout->leading); //leading
1574 swf_SetString(tag, variable);
1575 if (flags & ET_HASTEXT)
1576 swf_SetString(tag, text);
1579 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1583 U8 *utext = (U8 *) strdup(text);
1589 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1590 ystep = font->layout->leading;
1592 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1593 /* Hm, without layout information, we can't compute a bounding
1594 box. We could call swf_FontCreateLayout to create a layout,
1595 but the caller probably doesn't want us to mess up his font
1598 r.xmin = r.ymin = 0;
1599 r.xmax = r.ymax = 1024 * 20;
1603 swf_SetRect(tag, &r);
1605 /* The text matrix is pretty boring, as it doesn't apply to
1606 individual characters, but rather whole text objects (or
1607 at least whole char records- haven't tested).
1608 So it can't do anything which we can't already do with
1609 the placeobject tag we use for placing the text on the scene.
1611 swf_SetMatrix(tag, 0);
1613 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1614 swf_SetU8(tag, gbits);
1615 swf_SetU8(tag, abits);
1621 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1624 while(*next && *next!=13 && *next!=10 && count<127) {
1625 readUTF8char(&next);
1628 if(next[0] == 13 || next[0] == 10) {
1633 if(next[0] == 13 && next[1] == 10)
1636 if(next[0] == 13 || next[0] == 10) {
1641 /* now set the text params- notice that a font size of
1642 1024 (or 1024*20 for definefont3) means that the glyphs will
1643 be displayed exactly as they would be in/with a defineshape.
1644 This is not documented in the specs.
1647 /* set the actual text- notice that we just pass our scale
1648 parameter over, as TextSetCharRecord calculates with
1650 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1660 void swf_FontCreateLayout(SWFFONT * f)
1669 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1670 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1671 f->layout->ascent = 0;
1672 f->layout->descent = 0;
1674 for (t = 0; t < f->numchars; t++) {
1678 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1680 fprintf(stderr, "Shape parse error\n");
1683 bbox = swf_GetShapeBoundingBox(shape2);
1684 swf_Shape2Free(shape2);
1685 f->layout->bounds[t] = bbox;
1687 width = (bbox.xmax);
1689 /* The following is a heuristic- it may be that extractfont_DefineText
1690 has already found out some widths for individual characters (from the way
1691 they are used)- we now have to guess whether that width might be possible,
1692 which is the case if it isn't either much too big or much too small */
1693 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1694 f->glyph[t].advance = width;
1696 if (-bbox.ymin > f->layout->ascent)
1697 f->layout->ascent = -bbox.ymin;
1698 if (bbox.ymax > f->layout->descent)
1699 f->layout->descent = bbox.ymax;
1703 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1705 U8 *s = (U8 *) text;
1711 U32 c = readUTF8char(&s);
1712 int g = font->ascii2glyph[c];
1713 shape = font->glyph[g].shape;
1714 if (((int) g) < 0) {
1715 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1718 shape2 = swf_ShapeToShape2(shape);
1721 if (l->type == moveTo) {
1723 to.x = l->x * size / 100.0 / 20.0 + advance;
1724 to.y = l->y * size / 100.0 / 20.0;
1725 draw->moveTo(draw, &to);
1726 } else if (l->type == lineTo) {
1728 to.x = l->x * size / 100.0 / 20.0 + advance;
1729 to.y = l->y * size / 100.0 / 20.0;
1730 draw->lineTo(draw, &to);
1731 } else if (l->type == splineTo) {
1733 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1734 mid.y = l->sy * size / 100.0 / 20.0;
1735 to.x = l->x * size / 100.0 / 20.0 + advance;
1736 to.y = l->y * size / 100.0 / 20.0;
1737 draw->splineTo(draw, &mid, &to);
1741 swf_Shape2Free(shape2);
1742 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1746 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1749 swf_FontCreateLayout(font);
1752 memset(&swf, 0, sizeof(SWF));
1753 swf.fileVersion = 9;
1754 swf.frameRate = 0x4000;
1755 swf.movieSize.xmax = 200;
1756 swf.movieSize.ymax = 200;
1758 if(!font->id) font->id=1;
1761 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1762 swf_FontSetDefine2(tag, font);
1764 char*name = font->name?(char*)font->name:"font";
1766 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1767 swf_SetU16(tag, font->id);
1768 swf_SetString(tag, name);
1769 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1771 swf_SetU16(tag, font->id);
1772 swf_SetString(tag, name);
1773 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1775 tag = swf_InsertTag(tag, ST_END);
1776 swf_SaveSWF(&swf, filename);
1780 void swf_WriteFont(SWFFONT * font, char *filename)
1783 swf_FontCreateLayout(font);
1792 memset(&swf, 0, sizeof(SWF));
1793 swf.fileVersion = 8;
1794 swf.frameRate = 0x4000;
1795 swf.movieSize.xmax = 1024*20;
1796 swf.movieSize.ymax = 768*20;
1799 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1800 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1802 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1803 swf_FontSetDefine2(tag, font);
1805 if(font->glyphnames) {
1807 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1808 swf_SetU16(tag, font->id);
1809 swf_SetU16(tag, font->numchars);
1810 for (c = 0; c < font->numchars; c++) {
1811 if (font->glyphnames[c])
1812 swf_SetString(tag, font->glyphnames[c]);
1814 swf_SetString(tag, "");
1820 RGBA white = {255,255,255,255};
1821 RGBA black = {255,0,0,0};
1822 RGBA gray50 = {255,128,128,128};
1823 RGBA green = {255,0,255,0};
1825 SCOORD miny = SCOORD_MAX;
1826 SCOORD maxy = SCOORD_MIN;
1828 U16 max_advance = 0;
1829 char*flags = rfx_calloc(font->numchars);
1830 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1831 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1832 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1833 for(t=0;t<font->numchars;t++) {
1834 SHAPE*s = font->glyph[t].shape;
1835 SHAPE2*s2 = swf_ShapeToShape2(s);
1836 SRECT r = swf_GetShapeBoundingBox(s2);
1838 // inside a definefont3, everything is 20x the resolution:
1839 double rx1 = r.xmin / 20.0;
1840 double ry1 = r.ymin / 20.0;
1841 double rx2 = r.xmax / 20.0;
1842 double ry2 = r.ymax / 20.0;
1847 if(ry1<miny) {miny=ry1;}
1848 if(ry2>maxy) {maxy=ry2;}
1849 swf_Shape2Free(s2);free(s2);
1850 width += font->glyph[t].advance;
1851 if(font->glyph[t].advance>max_advance)
1852 max_advance = font->glyph[t].advance;
1855 if(miny==SCOORD_MAX) miny=maxy=0;
1856 if(miny==maxy) maxy=miny+1;
1858 /* scale the font so that it's 256 pixels high */
1859 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1860 double overlarge_factor;
1864 overlarge_factor = scale / 32767.0;
1867 overlarge_factor = 1.0;
1871 int spriteid = id++;
1874 r.ymin = miny*fontsize/1024;
1875 r.xmax = width*fontsize/20480;
1876 r.ymax = maxy*fontsize/1024;
1877 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1878 swf_SetU16(tag, textid);
1879 swf_SetRect(tag, &r);
1880 swf_SetMatrix(tag, NULL);
1883 U8 gbits = swf_CountBits(font->numchars, 0);
1884 swf_SetU8(tag, gbits);
1885 swf_SetU8(tag, abits);
1887 RGBA rgb = {255,0,0,0};
1889 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1890 ActionTAG*array = 0;
1892 array = action_PushString(array, "xpos");
1893 for(t=0;t<font->numchars;t++) {
1895 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1896 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1897 x += width * overlarge_factor;
1898 swf_SetBits(tag, t, gbits);
1899 swf_SetBits(tag, width, abits);
1900 swf_SetU8(tag, 128);
1902 array = action_PushInt(array, x/20);
1903 array = action_PushInt(array, font->numchars+1);
1904 array = action_InitArray(array);
1905 array = action_SetVariable(array);
1909 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1912 int ls = swf_ShapeAddLineStyle(s,20,&white);
1914 swf_SetU16(tag,shapeid);
1920 swf_SetRect(tag,&r);
1921 swf_SetShapeHeader(tag,s);
1922 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1924 /* Ç and  are good chars to test ascent/descent extend */
1925 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1926 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1928 swf_ShapeSetMove(tag,s,0,y1);
1929 swf_ShapeSetLine(tag,s,width,0);
1930 swf_ShapeSetMove(tag,s,0,y2);
1931 swf_ShapeSetLine(tag,s,width,0);
1933 swf_ShapeSetEnd(tag);
1935 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1936 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1941 for(t=0;t<font->numchars;t++) {
1942 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1945 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1946 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1947 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1949 swf_SetU16(tag,shapeid);
1955 swf_SetRect(tag,&r);
1956 swf_SetShapeHeader(tag,s);
1957 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1958 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1959 SHAPELINE*l = s2->lines;
1960 int lastx=0,lasty=0;
1962 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1963 double y1 = -miny*20*scale*2/20480.0;
1964 double scalex = scale*2/20480.0;
1965 double scaley = scale*2/20480.0;
1968 int lx = (l->x)*scalex+x1;
1969 int ly = (l->y)*scaley+y1;
1970 int sx = (l->sx)*scalex+x1;
1971 int sy = (l->sy)*scaley+y1;
1972 if(l->type == moveTo) {
1973 swf_ShapeSetMove(tag,s,lx,ly);
1974 } else if(l->type == lineTo) {
1975 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1976 } else if(l->type == splineTo) {
1977 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1984 if(font->alignzones) {
1985 ALIGNZONE*zone = &font->alignzones[t];
1986 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1987 if((zone->x&zone->dx)!=0xffff) {
1988 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1989 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1990 swf_ShapeSetMove(tag,s,x,0);
1991 swf_ShapeSetLine(tag,s,0,1024*20);
1992 swf_ShapeSetMove(tag,s,dx,0);
1993 swf_ShapeSetLine(tag,s,0,1024*20);
1995 if((zone->y&zone->dy)!=0xffff) {
1996 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
1997 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
1998 swf_ShapeSetMove(tag,s,0,y);
1999 swf_ShapeSetLine(tag,s,1024*20,0);
2000 swf_ShapeSetMove(tag,s,0,dy);
2001 swf_ShapeSetLine(tag,s,1024*20,0);
2005 swf_ShapeSetEnd(tag);
2008 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2010 swf_SetU16(tag, spriteid);
2012 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2013 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2014 tag = swf_InsertTag(tag, ST_END);
2015 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2017 swf_GetMatrix(0, &m);
2020 sprintf(txt, "char%d", font->numchars-t);
2021 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
2025 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
2027 RGBA blue = {0xff,0xc0,0xc0,0xff};
2028 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
2029 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2031 swf_SetU16(tag, spriteid2);
2033 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2034 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2035 tag = swf_InsertTag(tag, ST_END);
2036 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2037 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
2040 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2041 swf_SetU16(tag, spriteid);
2043 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2045 swf_GetMatrix(0, &m);
2046 m.sx = 65536 * overlarge_factor;
2047 m.sy = 65536 * overlarge_factor;
2049 m.ty = -miny*256*20/(maxy-miny);
2050 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
2051 tag = swf_InsertTag(tag, ST_END);
2052 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2053 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
2056 RGBA blue2 = {0x80,0x80,0xff,0x80};
2057 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2059 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2060 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2062 swf_SetU16(tag, spriteid3);
2064 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2065 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2066 tag = swf_InsertTag(tag, ST_END);
2067 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2068 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2072 " var mouseListener = new Object();"
2075 " var currentMouseOver, currentChar;"
2076 " mouseListener.onMouseDown = function() { "
2077 " eval(\"_root.char\"+currentChar)._y = 20000;"
2078 " currentChar = currentMouseOver;"
2079 " var i = currentMouseOver;"
2080 " eval(\"_root.char\"+i)._y = 256;"
2081 " _root.marker2._yscale=256*100;"
2082 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2083 " _root.marker2._x=xpos[i]+myx;"
2085 " mouseListener.onMouseMove = function() { "
2086 " if(_ymouse<256) {"
2087 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2092 " setInterval( function(){ "
2093 " if(_ymouse<256) {"
2094 " var i, x=_xmouse-_root.textbar._x;"
2095 " for(i=xpos.length-1;i>0;i--) {"
2096 " if(x<xpos[i-1]) break;"
2098 " currentMouseOver = i;"
2099 " _root.marker._yscale=256*100;"
2100 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2101 " _root.marker._x=xpos[i]+myx;"
2102 " _root.textbar._x += 0.05;"
2104 " if(myx+speed>0) {"
2106 " } else if(myx+speed<-xpos[0]+1024) {"
2110 " _root.textbar._x = myx;"
2111 " _root.marker._x += speed;"
2112 " _root.marker2._x += speed;"
2114 " Mouse.addListener(mouseListener);"
2116 ActionTAG* atag = swf_ActionCompile(data, 6);
2118 tag = swf_InsertTag(tag, ST_DOACTION);
2119 swf_ActionSet(tag, array);
2120 swf_ActionSet(tag, atag);
2122 swf_ActionFree(atag);
2124 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2131 tag = swf_InsertTag(tag, ST_END);
2133 swf.compressed = -1;
2134 swf_SaveSWF(&swf, filename);