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);
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);
282 glyphcount = swf_GetU16(tag);
283 font->numchars = glyphcount;
285 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
286 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
288 offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
289 offset_start = tag->pos;
291 if (flags1 & 8) { // wide offsets
292 for (t = 0; t < glyphcount; t++)
293 offset[t] = swf_GetU32(tag); //offset[t]
295 if (glyphcount) /* this _if_ is not in the specs */
296 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
298 offset[glyphcount] = tag->pos;
300 for (t = 0; t < glyphcount; t++)
301 offset[t] = swf_GetU16(tag); //offset[t]
303 if (glyphcount) /* this _if_ is not in the specs */
304 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
306 offset[glyphcount] = tag->pos;
308 for (t = 0; t < glyphcount; t++) {
309 swf_SetTagPos(tag, offset[t]+offset_start);
310 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
314 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
319 for (t = 0; t < glyphcount; t++) {
321 if (flags1 & 4) // wide codes (always on for definefont3)
322 code = swf_GetU16(tag);
324 code = swf_GetU8(tag);
325 font->glyph2ascii[t] = code;
332 font->maxascii = maxcode;
333 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
334 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
335 for (t = 0; t < glyphcount; t++) {
336 font->ascii2glyph[font->glyph2ascii[t]] = t;
339 if (flags1 & 128) { // has layout
341 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
342 font->layout->ascent = swf_GetU16(tag);
343 font->layout->descent = swf_GetU16(tag);
344 font->layout->leading = swf_GetU16(tag);
345 for (t = 0; t < glyphcount; t++) {
346 S16 advance = swf_GetS16(tag);
347 font->glyph[t].advance = advance;
349 font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
350 for (t = 0; t < glyphcount; t++) {
351 swf_ResetReadBits(tag);
352 swf_GetRect(tag, &font->layout->bounds[t]);
355 kerningcount = swf_GetU16(tag);
356 font->layout->kerningcount = kerningcount;
358 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
360 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
361 for (t = 0; t < kerningcount; t++) {
362 if (flags1 & 4) { // wide codes
363 font->layout->kerning[t].char1 = swf_GetU16(tag);
364 font->layout->kerning[t].char2 = swf_GetU16(tag);
366 font->layout->kerning[t].char1 = swf_GetU8(tag);
367 font->layout->kerning[t].char2 = swf_GetU8(tag);
369 font->layout->kerning[t].adjustment = swf_GetS16(tag);
376 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
379 swf_SetTagPos(tag, 0);
380 fid = swf_GetU16(tag);
383 font->alignzone_flags = swf_GetU8(tag);
384 font->alignzones = rfx_calloc(sizeof(ALIGNZONE)*font->numchars);
386 while(tag->pos < tag->len) {
387 if(i>=font->numchars)
389 int nr = swf_GetU8(tag); // should be 2
391 fprintf(stderr, "rfxswf: Can't parse alignzone tags with %d zones", nr);
394 U16 x = swf_GetU16(tag);
395 U16 y = swf_GetU16(tag);
396 U16 dx = (nr==2)?swf_GetU16(tag):0xffff;
397 U16 dy = (nr==2)?swf_GetU16(tag):0xffff;
398 U8 xy = swf_GetU8(tag);
401 if((!(xy&1) && (x!=0 || (dx!=0 && dx!=0xffff))) ||
402 (!(xy&2) && (y!=0 || (dy!=0 && dy!=0xffff)))) {
403 fprintf(stderr, "Warning: weird combination of alignzone bits and values (%d x:%04x-%04x y:%04x-%04x)\n", xy,
414 font->alignzones[i].x = x;
415 font->alignzones[i].y = y;
416 font->alignzones[i].dx = dx;
417 font->alignzones[i].dy = dy;
425 #define FEDTJ_PRINT 0x01
426 #define FEDTJ_MODIFY 0x02
427 #define FEDTJ_CALLBACK 0x04
430 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
431 void (*callback) (void *self,
432 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
443 memset(&color, 0, sizeof(color));
449 swf_GetMatrix(t, &m);
450 gbits = swf_GetU8(t);
451 abits = swf_GetU8(t);
455 flags = swf_GetU8(t);
459 if (flags & TF_TEXTCONTROL) {
460 if (flags & TF_HASFONT)
462 if (flags & TF_HASCOLOR) {
463 color.r = swf_GetU8(t); // rgb
464 color.g = swf_GetU8(t);
465 color.b = swf_GetU8(t);
466 if (swf_GetTagID(t) == ST_DEFINETEXT2)
467 color.a = swf_GetU8(t);
471 if (flags & TF_HASXOFFSET)
473 if (flags & TF_HASYOFFSET)
475 if (flags & TF_HASFONT)
476 fontsize = swf_GetU16(t);
488 for (i = 0; i < num; i++) {
492 glyph = swf_GetBits(t, gbits);
493 adv = swf_GetBits(t, abits);
497 if (jobs & FEDTJ_PRINT) {
498 int code = f->glyph2ascii[glyph];
501 if (jobs & FEDTJ_MODIFY)
502 f->glyph[glyph].advance = adv * 20; //?
507 if ((id == fid) && (jobs & FEDTJ_PRINT))
509 if (jobs & FEDTJ_CALLBACK)
510 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
518 int swf_ParseDefineText(TAG * tag,
519 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
521 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
524 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
526 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
529 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
534 if ((!swf) || (!font))
537 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
543 switch (swf_GetTagID(t)) {
545 nid = swf_FontExtract_DefineFont(id, f, t);
550 nid = swf_FontExtract_DefineFont2(id, f, t);
553 case ST_DEFINEFONTALIGNZONES:
554 nid = swf_FontExtract_DefineFontAlignZones(id, f, t);
557 case ST_DEFINEFONTINFO:
558 case ST_DEFINEFONTINFO2:
559 nid = swf_FontExtract_DefineFontInfo(id, f, t);
564 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
568 nid = swf_FontExtract_GlyphNames(id, f, t);
583 int swf_FontSetID(SWFFONT * f, U16 id)
591 void swf_LayoutFree(SWFLAYOUT * l)
595 rfx_free(l->kerning);
605 static void font_freeglyphnames(SWFFONT*f)
610 for (t = 0; t < f->numchars; t++)
612 if (f->glyphnames[t])
614 rfx_free(f->glyphnames[t]);
615 f->glyphnames[t] = 0;
618 rfx_free(f->glyphnames);
622 static void font_freeusage(SWFFONT*f)
626 rfx_free(f->use->chars);f->use->chars = 0;
628 rfx_free(f->use); f->use = 0;
631 static void font_freelayout(SWFFONT*f)
634 swf_LayoutFree(f->layout);
638 static void font_freename(SWFFONT*f)
646 int swf_FontReduce_old(SWFFONT * f)
650 if ((!f) || (!f->use) || f->use->is_reduced)
655 for (i = 0; i < f->numchars; i++) {
656 if (f->glyph[i].shape && f->use->chars[i]) {
657 f->glyph2ascii[j] = f->glyph2ascii[i];
658 f->glyph[j] = f->glyph[i];
659 f->use->chars[i] = j;
662 f->glyph2ascii[i] = 0;
663 if(f->glyph[i].shape) {
664 swf_ShapeFree(f->glyph[i].shape);
665 f->glyph[i].shape = 0;
666 f->glyph[i].advance = 0;
668 f->use->chars[i] = -1;
672 for (i = 0; i < f->maxascii; i++) {
673 if(f->use->chars[f->ascii2glyph[i]]<0) {
674 f->ascii2glyph[i] = -1;
676 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
680 f->maxascii = max_unicode;
681 f->use->is_reduced = 1;
684 font_freeglyphnames(f);
689 int swf_FontReduce_swfc(SWFFONT * f)
693 if ((!f) || (!f->use) || f->use->is_reduced)
696 font_freeglyphnames(f);
699 for (i = 0; i < f->numchars; i++) {
700 if (f->glyph[i].shape && f->use->chars[i]) {
701 f->glyph2ascii[j] = f->glyph2ascii[i];
703 f->layout->bounds[j] = f->layout->bounds[i];
704 f->glyph[j] = f->glyph[i];
705 f->use->chars[i] = j;
708 f->glyph2ascii[i] = 0;
709 if(f->glyph[i].shape) {
710 swf_ShapeFree(f->glyph[i].shape);
711 f->glyph[i].shape = 0;
712 f->glyph[i].advance = 0;
714 f->use->chars[i] = -1;
717 f->use->used_glyphs = j;
718 for (i = 0; i < f->maxascii; i++) {
719 if(f->ascii2glyph[i] > -1) {
720 if (f->use->chars[f->ascii2glyph[i]]<0) {
721 f->use->chars[f->ascii2glyph[i]] = 0;
722 f->ascii2glyph[i] = -1;
724 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
725 f->use->chars[f->ascii2glyph[i]] = 1;
730 f->maxascii = max_unicode;
731 f->use->is_reduced = 1;
737 int swf_FontReduce(SWFFONT * f)
742 if ((!f) || (!f->use) || f->use->is_reduced)
746 font_freeglyphnames(f);
748 f->use->used_glyphs= 0;
749 for (i = 0; i < f->numchars; i++) {
750 if(!f->use->chars[i]) {
752 f->glyph2ascii[i] = 0;
754 if(f->glyph[i].shape) {
755 swf_ShapeFree(f->glyph[i].shape);
756 f->glyph[i].shape = 0;
757 f->glyph[i].advance = 0;
759 // f->use->used_glyphs++;
761 f->use->used_glyphs++;
765 for (i = 0; i < f->maxascii; i++) {
766 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
768 f->ascii2glyph[i] = -1;
774 f->maxascii = max_unicode;
775 f->numchars = max_glyph;
780 void swf_FontSort(SWFFONT * font)
788 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
790 for (i = 0; i < font->numchars; i++) {
793 for (i = 0; i < font->numchars; i++)
794 for (j = 0; j < i; j++) {
795 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
804 n1 = font->glyph2ascii[i];
805 n2 = font->glyph2ascii[j];
806 font->glyph2ascii[j] = n1;
807 font->glyph2ascii[i] = n2;
812 if (font->glyphnames) {
813 c1 = font->glyphnames[i];
814 c2 = font->glyphnames[j];
815 font->glyphnames[j] = c1;
816 font->glyphnames[i] = c2;
819 r1 = font->layout->bounds[i];
820 r2 = font->layout->bounds[j];
821 font->layout->bounds[j] = r1;
822 font->layout->bounds[i] = r2;
826 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
827 for (i = 0; i < font->numchars; i++) {
828 newpos[newplace[i]] = i;
830 for (i = 0; i < font->maxascii; i++) {
831 if (font->ascii2glyph[i] >= 0)
832 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
839 void swf_FontPrepareForEditText(SWFFONT * font)
842 swf_FontCreateLayout(font);
846 int swf_FontInitUsage(SWFFONT * f)
851 fprintf(stderr, "Usage initialized twice");
854 f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
855 f->use->is_reduced = 0;
856 f->use->smallest_size = 0xffff;
857 f->use->used_glyphs = 0;
858 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
859 f->use->glyphs_specified = 0;
863 void swf_FontClearUsage(SWFFONT * f)
867 rfx_free(f->use->chars); f->use->chars = 0;
868 rfx_free(f->use); f->use = 0;
871 int swf_FontUse(SWFFONT * f, U8 * s)
876 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
877 swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
883 int swf_FontUseUTF8(SWFFONT * f, U8 * s, U16 size)
890 ascii = readUTF8char(&s);
891 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
892 swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
897 int swf_FontUseAll(SWFFONT* f)
902 swf_FontInitUsage(f);
903 for (i = 0; i < f->numchars; i++)
904 f->use->chars[i] = 1;
905 f->use->used_glyphs = f->numchars;
909 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
912 swf_FontInitUsage(f);
913 if(glyph < 0 || glyph >= f->numchars)
915 if(!f->use->chars[glyph])
916 f->use->used_glyphs++;
917 f->use->chars[glyph] = 1;
918 if(size && size < f->use->smallest_size)
919 f->use->smallest_size = size;
923 int swf_FontSetDefine(TAG * t, SWFFONT * f)
925 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
930 swf_ResetWriteBits(t);
931 swf_SetU16(t, f->id);
935 for (i = 0; i < f->numchars; i++)
936 if (f->glyph[i].shape) {
938 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
941 for (i = 0; i < j; i++)
942 swf_SetU16(t, ofs[i] + j * 2);
944 fprintf(stderr, "rfxswf: warning: Font is empty\n");
948 for (i = 0; i < f->numchars; i++)
949 if (f->glyph[i].shape)
950 swf_SetSimpleShape(t, f->glyph[i].shape);
952 swf_ResetWriteBits(t);
957 static inline int fontSize(SWFFONT * font)
961 for (t = 0; t < font->numchars; t++) {
963 if(font->glyph[t].shape)
964 l = (font->glyph[t].shape->bitlen + 7) / 8;
969 return size + (font->numchars + 1) * 2;
972 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
977 swf_SetU16(tag, f->id);
979 if (f->layout) flags |= 128; // haslayout
980 if (f->numchars > 256)
981 flags |= 4; // widecodes
982 if (f->style & FONT_STYLE_BOLD)
984 if (f->style & FONT_STYLE_ITALIC)
985 flags |= 2; // italic
986 if (f->maxascii >= 256)
987 flags |= 4; //wide codecs
988 if (fontSize(f) > 65535)
989 flags |= 8; //wide offsets
990 flags |= 8 | 4; //FIXME: the above check doesn't work
992 if (f->encoding & FONT_ENCODING_ANSI)
994 if (f->encoding & FONT_ENCODING_UNICODE)
995 flags |= 32; // unicode
996 if (f->encoding & FONT_ENCODING_SHIFTJIS)
997 flags |= 64; // shiftjis
999 swf_SetU8(tag, flags);
1000 swf_SetU8(tag, 0); //reserved flags
1003 swf_SetU8(tag, strlen((const char*)f->name)+1);
1004 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1006 /* font name (="") */
1010 /* number of glyphs */
1011 swf_SetU16(tag, f->numchars);
1012 /* font offset table */
1014 for (t = 0; t <= f->numchars; t++) {
1016 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1018 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1021 for (t = 0; t <= f->numchars; t++) {
1023 tag->data[pos + t * 4] = (tag->len - pos);
1024 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1025 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1026 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1028 if (tag->len - pos > 65535) {
1029 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1032 tag->data[pos + t * 2] = (tag->len - pos);
1033 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1035 if (t < f->numchars) {
1036 if(f->glyph[t].shape) {
1037 swf_SetSimpleShape(tag, f->glyph[t].shape);
1039 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1045 /* font code table */
1046 for (t = 0; t < f->numchars; t++) {
1047 if (flags & 4) { /* wide codes */
1048 if(f->glyph2ascii[t]) {
1049 swf_SetU16(tag, f->glyph2ascii[t]);
1054 if(f->glyph2ascii[t]) {
1055 swf_SetU8(tag, f->glyph2ascii[t]);
1063 swf_SetU16(tag, f->layout->ascent);
1064 swf_SetU16(tag, f->layout->descent);
1065 swf_SetU16(tag, f->layout->leading);
1066 for (t = 0; t < f->numchars; t++)
1067 swf_SetU16(tag, f->glyph[t].advance);
1068 for (t = 0; t < f->numchars; t++) {
1069 swf_ResetWriteBits(tag);
1070 swf_SetRect(tag, &f->layout->bounds[t]);
1072 swf_SetU16(tag, f->layout->kerningcount);
1073 for (t = 0; t < f->layout->kerningcount; t++) {
1074 if (flags & 4) { /* wide codes */
1075 swf_SetU16(tag, f->layout->kerning[t].char1);
1076 swf_SetU16(tag, f->layout->kerning[t].char2);
1078 swf_SetU8(tag, f->layout->kerning[t].char1);
1079 swf_SetU8(tag, f->layout->kerning[t].char2);
1081 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1087 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1089 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1090 f->layout->ascent = ascent;
1091 f->layout->descent = descent;
1092 f->layout->leading = leading;
1093 f->layout->kerningcount = 0;
1094 f->layout->kerning = 0;
1095 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1098 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1105 swf_ResetWriteBits(t);
1106 swf_SetU16(t, f->id);
1107 l = f->name ? strlen((const char *)f->name) : 0;
1112 swf_SetBlock(t, f->name, l);
1113 if (f->numchars >= 256)
1116 if (f->style & FONT_STYLE_BOLD)
1118 if (f->style & FONT_STYLE_ITALIC)
1120 if (f->style & FONT_ENCODING_ANSI)
1122 if (f->style & FONT_ENCODING_SHIFTJIS)
1124 if (f->style & FONT_ENCODING_UNICODE)
1127 swf_SetU8(t, (flags & 0xfe) | wide);
1129 for (i = 0; i < f->numchars; i++) {
1130 if (f->glyph[i].shape) {
1131 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1132 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1139 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1141 int id = swf_GetTagID(t);
1142 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1143 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1149 void swf_FontFree(SWFFONT * f)
1157 for (i = 0; i < f->numchars; i++)
1158 if (f->glyph[i].shape)
1160 swf_ShapeFree(f->glyph[i].shape);
1161 f->glyph[i].shape = NULL;
1168 rfx_free(f->ascii2glyph);
1169 f->ascii2glyph = NULL;
1173 rfx_free(f->glyph2ascii);
1174 f->glyph2ascii = NULL;
1178 font_freeglyphnames(f);
1184 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1190 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1191 | (y ? TF_HASYOFFSET : 0);
1193 swf_SetU8(t, flags);
1195 swf_SetU16(t, font->id);
1197 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1198 swf_SetRGBA(t, color);
1200 swf_SetRGB(t, color);
1203 if(x != SET_TO_ZERO) {
1204 if(x>32767 || x<-32768)
1205 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1212 if(y != SET_TO_ZERO) {
1213 if(y>32767 || y<-32768)
1214 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1221 swf_SetU16(t, size);
1226 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1230 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1234 if (!strcmp(encoding, "UTF8"))
1236 else if (!strcmp(encoding, "iso-8859-1"))
1239 fprintf(stderr, "Unknown encoding: %s", encoding);
1247 c = readUTF8char(&s);
1249 if (c < font->maxascii)
1250 glyph = font->ascii2glyph[c];
1252 g = swf_CountUBits(glyph, g);
1253 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1264 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1269 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1272 if (!strcmp(encoding, "UTF8"))
1274 else if (!strcmp(encoding, "iso-8859-1"))
1277 fprintf(stderr, "Unknown encoding: %s", encoding);
1280 swf_SetU8(t, l); //placeholder
1288 c = readUTF8char(&s);
1290 if (c < font->maxascii)
1291 g = font->ascii2glyph[c];
1293 swf_SetBits(t, g, gbits);
1294 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1296 /* We split into 127 characters per text field.
1297 We could do 255, by the (formerly wrong) flash specification,
1298 but some SWF parsing code out there still assumes that char blocks
1299 are at max 127 characters, and it would save only a few bits.
1306 PUT8(&t->data[pos], l);
1308 swf_ResetWriteBits(t);
1312 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1314 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1317 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1319 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1322 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1324 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1327 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1329 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1332 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1339 if (*s < font->maxascii)
1340 g = font->ascii2glyph[*s];
1342 res += font->glyph[g].advance / 20;
1346 res = (res * scale) / 100;
1351 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1358 int c = readUTF8char(&s);
1359 if(c==13 || c==10) {
1364 ypos+=font->layout->leading;
1367 if (c < font->maxascii) {
1368 int g = font->ascii2glyph[c];
1370 SRECT rn = font->layout->bounds[g];
1371 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1372 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1373 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1374 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1375 swf_ExpandRect2(&r, &rn);
1376 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1384 SWFFONT *swf_ReadFont(const char *filename)
1390 f = open(filename, O_RDONLY|O_BINARY);
1392 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1393 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1399 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1406 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)
1408 swf_SetRect(tag, &r);
1409 swf_ResetWriteBits(tag);
1411 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1413 flags |= ET_HASTEXT;
1415 flags |= ET_HASTEXTCOLOR;
1417 flags |= ET_HASMAXLENGTH;
1419 flags |= ET_HASFONT;
1421 flags |= ET_HASLAYOUT;
1423 swf_SetBits(tag, flags, 16);
1425 if (flags & ET_HASFONT) {
1426 swf_SetU16(tag, font); //font
1427 swf_SetU16(tag, height); //fontheight
1429 if (flags & ET_HASTEXTCOLOR) {
1430 swf_SetRGBA(tag, color);
1432 if (flags & ET_HASMAXLENGTH) {
1433 swf_SetU16(tag, maxlength); //maxlength
1435 if (flags & ET_HASLAYOUT) {
1436 swf_SetU8(tag, layout->align); //align
1437 swf_SetU16(tag, layout->leftmargin); //left margin
1438 swf_SetU16(tag, layout->rightmargin); //right margin
1439 swf_SetU16(tag, layout->indent); //indent
1440 swf_SetU16(tag, layout->leading); //leading
1442 swf_SetString(tag, variable);
1443 if (flags & ET_HASTEXT)
1444 swf_SetString(tag, text);
1447 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1451 U8 *utext = (U8 *) strdup(text);
1457 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1458 ystep = font->layout->leading;
1460 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1461 /* Hm, without layout information, we can't compute a bounding
1462 box. We could call swf_FontCreateLayout to create a layout,
1463 but the caller probably doesn't want us to mess up his font
1466 r.xmin = r.ymin = 0;
1467 r.xmax = r.ymax = 1024 * 20;
1471 swf_SetRect(tag, &r);
1473 /* The text matrix is pretty boring, as it doesn't apply to
1474 individual characters, but rather whole text objects (or
1475 at least whole char records- haven't tested).
1476 So it can't do anything which we can't already do with
1477 the placeobject tag we use for placing the text on the scene.
1479 swf_SetMatrix(tag, 0);
1481 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1482 swf_SetU8(tag, gbits);
1483 swf_SetU8(tag, abits);
1489 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1492 while(*next && *next!=13 && *next!=10 && count<127) {
1493 readUTF8char(&next);
1496 if(next[0] == 13 || next[0] == 10) {
1501 if(next[0] == 13 && next[1] == 10)
1504 if(next[0] == 13 || next[0] == 10) {
1509 /* now set the text params- notice that a font size of
1510 1024 (or 1024*20 for definefont3) means that the glyphs will
1511 be displayed exactly as they would be in/with a defineshape.
1512 This is not documented in the specs.
1515 /* set the actual text- notice that we just pass our scale
1516 parameter over, as TextSetCharRecord calculates with
1518 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1528 void swf_FontCreateLayout(SWFFONT * f)
1537 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1538 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1539 f->layout->ascent = 0;
1540 f->layout->descent = 0;
1542 for (t = 0; t < f->numchars; t++) {
1546 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1548 fprintf(stderr, "Shape parse error\n");
1551 bbox = swf_GetShapeBoundingBox(shape2);
1552 swf_Shape2Free(shape2);
1553 f->layout->bounds[t] = bbox;
1555 width = (bbox.xmax);
1557 /* The following is a heuristic- it may be that extractfont_DefineText
1558 has already found out some widths for individual characters (from the way
1559 they are used)- we now have to guess whether that width might be possible,
1560 which is the case if it isn't either much too big or much too small */
1561 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1562 f->glyph[t].advance = width;
1564 if (-bbox.ymin > f->layout->ascent)
1565 f->layout->ascent = -bbox.ymin;
1566 if (bbox.ymax > f->layout->descent)
1567 f->layout->descent = bbox.ymax;
1571 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1573 U8 *s = (U8 *) text;
1579 U32 c = readUTF8char(&s);
1580 int g = font->ascii2glyph[c];
1581 shape = font->glyph[g].shape;
1582 if (((int) g) < 0) {
1583 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1586 shape2 = swf_ShapeToShape2(shape);
1589 if (l->type == moveTo) {
1591 to.x = l->x * size / 100.0 / 20.0 + advance;
1592 to.y = l->y * size / 100.0 / 20.0;
1593 draw->moveTo(draw, &to);
1594 } else if (l->type == lineTo) {
1596 to.x = l->x * size / 100.0 / 20.0 + advance;
1597 to.y = l->y * size / 100.0 / 20.0;
1598 draw->lineTo(draw, &to);
1599 } else if (l->type == splineTo) {
1601 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1602 mid.y = l->sy * size / 100.0 / 20.0;
1603 to.x = l->x * size / 100.0 / 20.0 + advance;
1604 to.y = l->y * size / 100.0 / 20.0;
1605 draw->splineTo(draw, &mid, &to);
1609 swf_Shape2Free(shape2);
1610 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1614 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1617 swf_FontCreateLayout(font);
1620 memset(&swf, 0, sizeof(SWF));
1621 swf.fileVersion = 9;
1622 swf.frameRate = 0x4000;
1623 swf.movieSize.xmax = 200;
1624 swf.movieSize.ymax = 200;
1626 if(!font->id) font->id=1;
1629 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1630 swf_FontSetDefine2(tag, font);
1632 char*name = font->name?(char*)font->name:"font";
1634 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1635 swf_SetU16(tag, font->id);
1636 swf_SetString(tag, name);
1637 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1639 swf_SetU16(tag, font->id);
1640 swf_SetString(tag, name);
1641 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1643 tag = swf_InsertTag(tag, ST_END);
1644 swf_SaveSWF(&swf, filename);
1648 void swf_WriteFont(SWFFONT * font, char *filename)
1651 swf_FontCreateLayout(font);
1660 memset(&swf, 0, sizeof(SWF));
1661 swf.fileVersion = 8;
1662 swf.frameRate = 0x4000;
1663 swf.movieSize.xmax = 1024*20;
1664 swf.movieSize.ymax = 768*20;
1667 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1668 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1670 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1671 swf_FontSetDefine2(tag, font);
1673 if(font->glyphnames) {
1675 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1676 swf_SetU16(tag, font->id);
1677 swf_SetU16(tag, font->numchars);
1678 for (c = 0; c < font->numchars; c++) {
1679 if (font->glyphnames[c])
1680 swf_SetString(tag, font->glyphnames[c]);
1682 swf_SetString(tag, "");
1688 RGBA white = {255,255,255,255};
1689 RGBA black = {255,0,0,0};
1690 RGBA gray50 = {255,128,128,128};
1691 RGBA green = {255,0,255,0};
1693 SCOORD miny = SCOORD_MAX;
1694 SCOORD maxy = SCOORD_MIN;
1696 U16 max_advance = 0;
1697 char*flags = rfx_calloc(font->numchars);
1698 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1699 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1700 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1701 for(t=0;t<font->numchars;t++) {
1702 SHAPE*s = font->glyph[t].shape;
1703 SHAPE2*s2 = swf_ShapeToShape2(s);
1704 SRECT r = swf_GetShapeBoundingBox(s2);
1706 // inside a definefont3, everything is 20x the resolution:
1707 double rx1 = r.xmin / 20.0;
1708 double ry1 = r.ymin / 20.0;
1709 double rx2 = r.xmax / 20.0;
1710 double ry2 = r.ymax / 20.0;
1715 if(ry1<miny) {miny=ry1;}
1716 if(ry2>maxy) {maxy=ry2;}
1717 swf_Shape2Free(s2);free(s2);
1718 width += font->glyph[t].advance;
1719 if(font->glyph[t].advance>max_advance)
1720 max_advance = font->glyph[t].advance;
1723 if(miny==SCOORD_MAX) miny=maxy=0;
1724 if(miny==maxy) maxy=miny+1;
1726 /* scale the font so that it's 256 pixels high */
1727 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1728 double overlarge_factor;
1732 overlarge_factor = scale / 32767.0;
1735 overlarge_factor = 1.0;
1739 int spriteid = id++;
1742 r.ymin = miny*fontsize/1024;
1743 r.xmax = width*fontsize/20480;
1744 r.ymax = maxy*fontsize/1024;
1745 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1746 swf_SetU16(tag, textid);
1747 swf_SetRect(tag, &r);
1748 swf_SetMatrix(tag, NULL);
1751 U8 gbits = swf_CountBits(font->numchars, 0);
1752 swf_SetU8(tag, gbits);
1753 swf_SetU8(tag, abits);
1755 RGBA rgb = {255,0,0,0};
1757 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1758 ActionTAG*array = 0;
1760 array = action_PushString(array, "xpos");
1761 for(t=0;t<font->numchars;t++) {
1763 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1764 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1765 x += width * overlarge_factor;
1766 swf_SetBits(tag, t, gbits);
1767 swf_SetBits(tag, width, abits);
1768 swf_SetU8(tag, 128);
1770 array = action_PushInt(array, x/20);
1771 array = action_PushInt(array, font->numchars+1);
1772 array = action_InitArray(array);
1773 array = action_SetVariable(array);
1777 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1780 int ls = swf_ShapeAddLineStyle(s,20,&white);
1782 swf_SetU16(tag,shapeid);
1788 swf_SetRect(tag,&r);
1789 swf_SetShapeHeader(tag,s);
1790 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1792 /* Ç and  are good chars to test ascent/descent extend */
1793 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1794 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1796 swf_ShapeSetMove(tag,s,0,y1);
1797 swf_ShapeSetLine(tag,s,width,0);
1798 swf_ShapeSetMove(tag,s,0,y2);
1799 swf_ShapeSetLine(tag,s,width,0);
1801 swf_ShapeSetEnd(tag);
1803 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1804 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1809 for(t=0;t<font->numchars;t++) {
1810 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1813 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1814 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1815 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1817 swf_SetU16(tag,shapeid);
1823 swf_SetRect(tag,&r);
1824 swf_SetShapeHeader(tag,s);
1825 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1826 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1827 SHAPELINE*l = s2->lines;
1828 int lastx=0,lasty=0;
1830 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1831 double y1 = -miny*20*scale*2/20480.0;
1832 double scalex = scale*2/20480.0;
1833 double scaley = scale*2/20480.0;
1836 int lx = (l->x)*scalex+x1;
1837 int ly = (l->y)*scaley+y1;
1838 int sx = (l->sx)*scalex+x1;
1839 int sy = (l->sy)*scaley+y1;
1840 if(l->type == moveTo) {
1841 swf_ShapeSetMove(tag,s,lx,ly);
1842 } else if(l->type == lineTo) {
1843 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1844 } else if(l->type == splineTo) {
1845 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1852 if(font->alignzones) {
1853 ALIGNZONE*zone = &font->alignzones[t];
1854 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1855 if((zone->x&zone->dx)!=0xffff) {
1856 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1857 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1858 swf_ShapeSetMove(tag,s,x,0);
1859 swf_ShapeSetLine(tag,s,0,1024*20);
1860 swf_ShapeSetMove(tag,s,dx,0);
1861 swf_ShapeSetLine(tag,s,0,1024*20);
1863 if((zone->y&zone->dy)!=0xffff) {
1864 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
1865 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
1866 swf_ShapeSetMove(tag,s,0,y);
1867 swf_ShapeSetLine(tag,s,1024*20,0);
1868 swf_ShapeSetMove(tag,s,0,dy);
1869 swf_ShapeSetLine(tag,s,1024*20,0);
1873 swf_ShapeSetEnd(tag);
1876 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1878 swf_SetU16(tag, spriteid);
1880 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1881 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1882 tag = swf_InsertTag(tag, ST_END);
1883 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1885 swf_GetMatrix(0, &m);
1888 sprintf(txt, "char%d", font->numchars-t);
1889 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
1893 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1895 RGBA blue = {0xff,0xc0,0xc0,0xff};
1896 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
1897 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1899 swf_SetU16(tag, spriteid2);
1901 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1902 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1903 tag = swf_InsertTag(tag, ST_END);
1904 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1905 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
1908 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1909 swf_SetU16(tag, spriteid);
1911 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1913 swf_GetMatrix(0, &m);
1914 m.sx = 65536 * overlarge_factor;
1915 m.sy = 65536 * overlarge_factor;
1917 m.ty = -miny*256*20/(maxy-miny);
1918 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
1919 tag = swf_InsertTag(tag, ST_END);
1920 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1921 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
1924 RGBA blue2 = {0x80,0x80,0xff,0x80};
1925 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1927 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
1928 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1930 swf_SetU16(tag, spriteid3);
1932 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1933 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
1934 tag = swf_InsertTag(tag, ST_END);
1935 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1936 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
1940 " var mouseListener = new Object();"
1943 " var currentMouseOver, currentChar;"
1944 " mouseListener.onMouseDown = function() { "
1945 " eval(\"_root.char\"+currentChar)._y = 20000;"
1946 " currentChar = currentMouseOver;"
1947 " var i = currentMouseOver;"
1948 " eval(\"_root.char\"+i)._y = 256;"
1949 " _root.marker2._yscale=256*100;"
1950 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
1951 " _root.marker2._x=xpos[i]+myx;"
1953 " mouseListener.onMouseMove = function() { "
1954 " if(_ymouse<256) {"
1955 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
1960 " setInterval( function(){ "
1961 " if(_ymouse<256) {"
1962 " var i, x=_xmouse-_root.textbar._x;"
1963 " for(i=xpos.length-1;i>0;i--) {"
1964 " if(x<xpos[i-1]) break;"
1966 " currentMouseOver = i;"
1967 " _root.marker._yscale=256*100;"
1968 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
1969 " _root.marker._x=xpos[i]+myx;"
1970 " _root.textbar._x += 0.05;"
1972 " if(myx+speed>0) {"
1974 " } else if(myx+speed<-xpos[0]+1024) {"
1978 " _root.textbar._x = myx;"
1979 " _root.marker._x += speed;"
1980 " _root.marker2._x += speed;"
1982 " Mouse.addListener(mouseListener);"
1984 ActionTAG* atag = swf_ActionCompile(data, 6);
1986 tag = swf_InsertTag(tag, ST_DOACTION);
1987 swf_ActionSet(tag, array);
1988 swf_ActionSet(tag, atag);
1990 swf_ActionFree(atag);
1992 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1999 tag = swf_InsertTag(tag, ST_END);
2001 swf.compressed = -1;
2002 swf_SaveSWF(&swf, filename);