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 static float F16toFloat(U16 x)
383 return swf_GetF16(&t);
386 static float floatToF16(float f)
398 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
401 swf_SetTagPos(tag, 0);
402 fid = swf_GetU16(tag);
405 font->alignzone_flags = swf_GetU8(tag);
406 font->alignzones = rfx_calloc(sizeof(ALIGNZONE)*font->numchars);
408 while(tag->pos < tag->len) {
409 if(i>=font->numchars)
411 int nr = swf_GetU8(tag); // should be 2
413 fprintf(stderr, "rfxswf: Can't parse alignzone tags with %d zones", nr);
416 U16 x = swf_GetU16(tag);
417 U16 y = swf_GetU16(tag);
418 U16 dx = (nr==2)?swf_GetU16(tag):0xffff;
419 U16 dy = (nr==2)?swf_GetU16(tag):0xffff;
420 U8 xy = swf_GetU8(tag);
423 if((!(xy&1) && (x!=0 || (dx!=0 && dx!=0xffff))) ||
424 (!(xy&2) && (y!=0 || (dy!=0 && dy!=0xffff)))) {
425 fprintf(stderr, "Warning: weird combination of alignzone bits and values (%d x:%04x-%04x y:%04x-%04x)\n", xy,
436 font->alignzones[i].x = x;
437 font->alignzones[i].y = y;
438 font->alignzones[i].dx = dx;
439 font->alignzones[i].dy = dy;
447 #define FEDTJ_PRINT 0x01
448 #define FEDTJ_MODIFY 0x02
449 #define FEDTJ_CALLBACK 0x04
452 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
453 void (*callback) (void *self,
454 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
465 memset(&color, 0, sizeof(color));
471 swf_GetMatrix(t, &m);
472 gbits = swf_GetU8(t);
473 abits = swf_GetU8(t);
477 flags = swf_GetU8(t);
481 if (flags & TF_TEXTCONTROL) {
482 if (flags & TF_HASFONT)
484 if (flags & TF_HASCOLOR) {
485 color.r = swf_GetU8(t); // rgb
486 color.g = swf_GetU8(t);
487 color.b = swf_GetU8(t);
488 if (swf_GetTagID(t) == ST_DEFINETEXT2)
489 color.a = swf_GetU8(t);
493 if (flags & TF_HASXOFFSET)
495 if (flags & TF_HASYOFFSET)
497 if (flags & TF_HASFONT)
498 fontsize = swf_GetU16(t);
510 for (i = 0; i < num; i++) {
514 glyph = swf_GetBits(t, gbits);
515 adv = swf_GetBits(t, abits);
519 if (jobs & FEDTJ_PRINT) {
520 int code = f->glyph2ascii[glyph];
523 if (jobs & FEDTJ_MODIFY)
524 f->glyph[glyph].advance = adv * 20; //?
529 if ((id == fid) && (jobs & FEDTJ_PRINT))
531 if (jobs & FEDTJ_CALLBACK)
532 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
540 int swf_ParseDefineText(TAG * tag,
541 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
543 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
546 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
548 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
551 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
556 if ((!swf) || (!font))
559 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
565 switch (swf_GetTagID(t)) {
567 nid = swf_FontExtract_DefineFont(id, f, t);
572 nid = swf_FontExtract_DefineFont2(id, f, t);
575 case ST_DEFINEFONTALIGNZONES:
576 nid = swf_FontExtract_DefineFontAlignZones(id, f, t);
579 case ST_DEFINEFONTINFO:
580 case ST_DEFINEFONTINFO2:
581 nid = swf_FontExtract_DefineFontInfo(id, f, t);
586 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
590 nid = swf_FontExtract_GlyphNames(id, f, t);
605 int swf_FontSetID(SWFFONT * f, U16 id)
613 void swf_LayoutFree(SWFLAYOUT * l)
617 rfx_free(l->kerning);
627 static void font_freeglyphnames(SWFFONT*f)
632 for (t = 0; t < f->numchars; t++)
634 if (f->glyphnames[t])
636 rfx_free(f->glyphnames[t]);
637 f->glyphnames[t] = 0;
640 rfx_free(f->glyphnames);
644 static void font_freeusage(SWFFONT*f)
648 rfx_free(f->use->chars);f->use->chars = 0;
650 rfx_free(f->use); f->use = 0;
653 static void font_freelayout(SWFFONT*f)
656 swf_LayoutFree(f->layout);
660 static void font_freename(SWFFONT*f)
668 int swf_FontReduce_old(SWFFONT * f)
672 if ((!f) || (!f->use) || f->use->is_reduced)
677 for (i = 0; i < f->numchars; i++) {
678 if (f->glyph[i].shape && f->use->chars[i]) {
679 f->glyph2ascii[j] = f->glyph2ascii[i];
680 f->glyph[j] = f->glyph[i];
681 f->use->chars[i] = j;
684 f->glyph2ascii[i] = 0;
685 if(f->glyph[i].shape) {
686 swf_ShapeFree(f->glyph[i].shape);
687 f->glyph[i].shape = 0;
688 f->glyph[i].advance = 0;
690 f->use->chars[i] = -1;
694 for (i = 0; i < f->maxascii; i++) {
695 if(f->use->chars[f->ascii2glyph[i]]<0) {
696 f->ascii2glyph[i] = -1;
698 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
702 f->maxascii = max_unicode;
703 f->use->is_reduced = 1;
706 font_freeglyphnames(f);
711 int swf_FontReduce_swfc(SWFFONT * f)
715 if ((!f) || (!f->use) || f->use->is_reduced)
718 font_freeglyphnames(f);
721 for (i = 0; i < f->numchars; i++) {
722 if (f->glyph[i].shape && f->use->chars[i]) {
723 f->glyph2ascii[j] = f->glyph2ascii[i];
725 f->layout->bounds[j] = f->layout->bounds[i];
726 f->glyph[j] = f->glyph[i];
727 f->use->chars[i] = j;
730 f->glyph2ascii[i] = 0;
731 if(f->glyph[i].shape) {
732 swf_ShapeFree(f->glyph[i].shape);
733 f->glyph[i].shape = 0;
734 f->glyph[i].advance = 0;
736 f->use->chars[i] = -1;
739 f->use->used_glyphs = j;
740 for (i = 0; i < f->maxascii; i++) {
741 if(f->ascii2glyph[i] > -1) {
742 if (f->use->chars[f->ascii2glyph[i]]<0) {
743 f->use->chars[f->ascii2glyph[i]] = 0;
744 f->ascii2glyph[i] = -1;
746 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
747 f->use->chars[f->ascii2glyph[i]] = 1;
752 f->maxascii = max_unicode;
753 f->use->is_reduced = 1;
759 int swf_FontReduce(SWFFONT * f)
764 if ((!f) || (!f->use) || f->use->is_reduced)
768 font_freeglyphnames(f);
770 f->use->used_glyphs= 0;
771 for (i = 0; i < f->numchars; i++) {
772 if(!f->use->chars[i]) {
774 f->glyph2ascii[i] = 0;
776 if(f->glyph[i].shape) {
777 swf_ShapeFree(f->glyph[i].shape);
778 f->glyph[i].shape = 0;
779 f->glyph[i].advance = 0;
781 // f->use->used_glyphs++;
783 f->use->used_glyphs++;
787 for (i = 0; i < f->maxascii; i++) {
788 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
790 f->ascii2glyph[i] = -1;
796 f->maxascii = max_unicode;
797 f->numchars = max_glyph;
802 void swf_FontSort(SWFFONT * font)
810 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
812 for (i = 0; i < font->numchars; i++) {
815 for (i = 0; i < font->numchars; i++)
816 for (j = 0; j < i; j++) {
817 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
826 n1 = font->glyph2ascii[i];
827 n2 = font->glyph2ascii[j];
828 font->glyph2ascii[j] = n1;
829 font->glyph2ascii[i] = n2;
834 if (font->glyphnames) {
835 c1 = font->glyphnames[i];
836 c2 = font->glyphnames[j];
837 font->glyphnames[j] = c1;
838 font->glyphnames[i] = c2;
841 r1 = font->layout->bounds[i];
842 r2 = font->layout->bounds[j];
843 font->layout->bounds[j] = r1;
844 font->layout->bounds[i] = r2;
848 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
849 for (i = 0; i < font->numchars; i++) {
850 newpos[newplace[i]] = i;
852 for (i = 0; i < font->maxascii; i++) {
853 if (font->ascii2glyph[i] >= 0)
854 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
861 void swf_FontPrepareForEditText(SWFFONT * font)
864 swf_FontCreateLayout(font);
868 int swf_FontInitUsage(SWFFONT * f)
873 fprintf(stderr, "Usage initialized twice");
876 f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
877 f->use->is_reduced = 0;
878 f->use->used_glyphs = 0;
879 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
880 f->use->glyphs_specified = 0;
884 void swf_FontClearUsage(SWFFONT * f)
888 rfx_free(f->use->chars); f->use->chars = 0;
889 rfx_free(f->use); f->use = 0;
892 int swf_FontUse(SWFFONT * f, U8 * s)
897 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
898 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
904 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
911 ascii = readUTF8char(&s);
912 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
913 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
918 int swf_FontUseAll(SWFFONT* f)
923 swf_FontInitUsage(f);
924 for (i = 0; i < f->numchars; i++)
925 f->use->chars[i] = 1;
926 f->use->used_glyphs = f->numchars;
930 int swf_FontUseGlyph(SWFFONT * f, int glyph)
933 swf_FontInitUsage(f);
934 if(glyph < 0 || glyph >= f->numchars)
936 if(!f->use->chars[glyph])
937 f->use->used_glyphs++;
938 f->use->chars[glyph] = 1;
942 int swf_FontSetDefine(TAG * t, SWFFONT * f)
944 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
949 swf_ResetWriteBits(t);
950 swf_SetU16(t, f->id);
954 for (i = 0; i < f->numchars; i++)
955 if (f->glyph[i].shape) {
957 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
960 for (i = 0; i < j; i++)
961 swf_SetU16(t, ofs[i] + j * 2);
963 fprintf(stderr, "rfxswf: warning: Font is empty\n");
967 for (i = 0; i < f->numchars; i++)
968 if (f->glyph[i].shape)
969 swf_SetSimpleShape(t, f->glyph[i].shape);
971 swf_ResetWriteBits(t);
976 static inline int fontSize(SWFFONT * font)
980 for (t = 0; t < font->numchars; t++) {
982 if(font->glyph[t].shape)
983 l = (font->glyph[t].shape->bitlen + 7) / 8;
988 return size + (font->numchars + 1) * 2;
991 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
996 swf_SetU16(tag, f->id);
998 if (f->layout) flags |= 128; // haslayout
999 if (f->numchars > 256)
1000 flags |= 4; // widecodes
1001 if (f->style & FONT_STYLE_BOLD)
1003 if (f->style & FONT_STYLE_ITALIC)
1004 flags |= 2; // italic
1005 if (f->maxascii >= 256)
1006 flags |= 4; //wide codecs
1007 if (fontSize(f) > 65535)
1008 flags |= 8; //wide offsets
1009 flags |= 8 | 4; //FIXME: the above check doesn't work
1011 if (f->encoding & FONT_ENCODING_ANSI)
1012 flags |= 16; // ansi
1013 if (f->encoding & FONT_ENCODING_UNICODE)
1014 flags |= 32; // unicode
1015 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1016 flags |= 64; // shiftjis
1018 swf_SetU8(tag, flags);
1019 swf_SetU8(tag, 0); //reserved flags
1022 swf_SetU8(tag, strlen((const char*)f->name)+1);
1023 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1025 /* font name (="") */
1029 /* number of glyphs */
1030 swf_SetU16(tag, f->numchars);
1031 /* font offset table */
1033 for (t = 0; t <= f->numchars; t++) {
1035 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1037 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1040 for (t = 0; t <= f->numchars; t++) {
1042 tag->data[pos + t * 4] = (tag->len - pos);
1043 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1044 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1045 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1047 if (tag->len - pos > 65535) {
1048 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1051 tag->data[pos + t * 2] = (tag->len - pos);
1052 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1054 if (t < f->numchars) {
1055 if(f->glyph[t].shape) {
1056 swf_SetSimpleShape(tag, f->glyph[t].shape);
1058 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1064 /* font code table */
1065 for (t = 0; t < f->numchars; t++) {
1066 if (flags & 4) { /* wide codes */
1067 if(f->glyph2ascii[t]) {
1068 swf_SetU16(tag, f->glyph2ascii[t]);
1073 if(f->glyph2ascii[t]) {
1074 swf_SetU8(tag, f->glyph2ascii[t]);
1082 swf_SetU16(tag, f->layout->ascent);
1083 swf_SetU16(tag, f->layout->descent);
1084 swf_SetU16(tag, f->layout->leading);
1085 for (t = 0; t < f->numchars; t++)
1086 swf_SetU16(tag, f->glyph[t].advance);
1087 for (t = 0; t < f->numchars; t++) {
1088 swf_ResetWriteBits(tag);
1089 swf_SetRect(tag, &f->layout->bounds[t]);
1091 swf_SetU16(tag, f->layout->kerningcount);
1092 for (t = 0; t < f->layout->kerningcount; t++) {
1093 if (flags & 4) { /* wide codes */
1094 swf_SetU16(tag, f->layout->kerning[t].char1);
1095 swf_SetU16(tag, f->layout->kerning[t].char2);
1097 swf_SetU8(tag, f->layout->kerning[t].char1);
1098 swf_SetU8(tag, f->layout->kerning[t].char2);
1100 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1106 void swf_FontSetAlignZones(TAG*t, SWFFONT *f)
1108 swf_SetU16(t, f->id);
1109 swf_SetU8(t, f->alignzone_flags);
1111 for(i=0;i<f->numchars;i++) {
1112 ALIGNZONE*a = &f->alignzones[i];
1114 if((a->x & a->dx)!=0xffff)
1116 if((a->y & a->dy)!=0xffff)
1119 if(flags&1) swf_SetU16(t, a->x); else swf_SetU16(t, 0);
1120 if(flags&2) swf_SetU16(t, a->y); else swf_SetU16(t, 0);
1121 if((flags&1) && a->dx!=0xffff) swf_SetU16(t, a->dx); else swf_SetU16(t, 0);
1122 if((flags&2) && a->dy!=0xffff) swf_SetU16(t, a->dy); else swf_SetU16(t, 0);
1123 swf_SetU8(t, flags);
1127 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1129 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1130 f->layout->ascent = ascent;
1131 f->layout->descent = descent;
1132 f->layout->leading = leading;
1133 f->layout->kerningcount = 0;
1134 f->layout->kerning = 0;
1135 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1138 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1145 swf_ResetWriteBits(t);
1146 swf_SetU16(t, f->id);
1147 l = f->name ? strlen((const char *)f->name) : 0;
1152 swf_SetBlock(t, f->name, l);
1153 if (f->numchars >= 256)
1156 if (f->style & FONT_STYLE_BOLD)
1158 if (f->style & FONT_STYLE_ITALIC)
1160 if (f->style & FONT_ENCODING_ANSI)
1162 if (f->style & FONT_ENCODING_SHIFTJIS)
1164 if (f->style & FONT_ENCODING_UNICODE)
1167 swf_SetU8(t, (flags & 0xfe) | wide);
1169 for (i = 0; i < f->numchars; i++) {
1170 if (f->glyph[i].shape) {
1171 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1172 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1179 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1181 int id = swf_GetTagID(t);
1182 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1183 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1189 void swf_FontFree(SWFFONT * f)
1197 for (i = 0; i < f->numchars; i++)
1198 if (f->glyph[i].shape)
1200 swf_ShapeFree(f->glyph[i].shape);
1201 f->glyph[i].shape = NULL;
1208 rfx_free(f->ascii2glyph);
1209 f->ascii2glyph = NULL;
1213 rfx_free(f->glyph2ascii);
1214 f->glyph2ascii = NULL;
1218 font_freeglyphnames(f);
1224 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1230 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1231 | (y ? TF_HASYOFFSET : 0);
1233 swf_SetU8(t, flags);
1235 swf_SetU16(t, font->id);
1237 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1238 swf_SetRGBA(t, color);
1240 swf_SetRGB(t, color);
1243 if(x != SET_TO_ZERO) {
1244 if(x>32767 || x<-32768)
1245 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1252 if(y != SET_TO_ZERO) {
1253 if(y>32767 || y<-32768)
1254 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1261 swf_SetU16(t, size);
1266 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1270 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1274 if (!strcmp(encoding, "UTF8"))
1276 else if (!strcmp(encoding, "iso-8859-1"))
1279 fprintf(stderr, "Unknown encoding: %s", encoding);
1287 c = readUTF8char(&s);
1289 if (c < font->maxascii)
1290 glyph = font->ascii2glyph[c];
1292 g = swf_CountUBits(glyph, g);
1293 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1304 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1309 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1312 if (!strcmp(encoding, "UTF8"))
1314 else if (!strcmp(encoding, "iso-8859-1"))
1317 fprintf(stderr, "Unknown encoding: %s", encoding);
1320 swf_SetU8(t, l); //placeholder
1328 c = readUTF8char(&s);
1330 if (c < font->maxascii)
1331 g = font->ascii2glyph[c];
1333 swf_SetBits(t, g, gbits);
1334 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1336 /* We split into 127 characters per text field.
1337 We could do 255, by the (formerly wrong) flash specification,
1338 but some SWF parsing code out there still assumes that char blocks
1339 are at max 127 characters, and it would save only a few bits.
1346 PUT8(&t->data[pos], l);
1348 swf_ResetWriteBits(t);
1352 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1354 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1357 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1359 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1362 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1364 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1367 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1369 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1372 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1379 if (*s < font->maxascii)
1380 g = font->ascii2glyph[*s];
1382 res += font->glyph[g].advance / 20;
1386 res = (res * scale) / 100;
1391 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1398 int c = readUTF8char(&s);
1399 if(c==13 || c==10) {
1404 ypos+=font->layout->leading;
1407 if (c < font->maxascii) {
1408 int g = font->ascii2glyph[c];
1410 SRECT rn = font->layout->bounds[g];
1411 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1412 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1413 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1414 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1415 swf_ExpandRect2(&r, &rn);
1416 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1424 SWFFONT *swf_ReadFont(const char *filename)
1430 f = open(filename, O_RDONLY|O_BINARY);
1432 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1433 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1439 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1446 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)
1448 swf_SetRect(tag, &r);
1449 swf_ResetWriteBits(tag);
1451 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1453 flags |= ET_HASTEXT;
1455 flags |= ET_HASTEXTCOLOR;
1457 flags |= ET_HASMAXLENGTH;
1459 flags |= ET_HASFONT;
1461 flags |= ET_HASLAYOUT;
1463 swf_SetBits(tag, flags, 16);
1465 if (flags & ET_HASFONT) {
1466 swf_SetU16(tag, font); //font
1467 swf_SetU16(tag, height); //fontheight
1469 if (flags & ET_HASTEXTCOLOR) {
1470 swf_SetRGBA(tag, color);
1472 if (flags & ET_HASMAXLENGTH) {
1473 swf_SetU16(tag, maxlength); //maxlength
1475 if (flags & ET_HASLAYOUT) {
1476 swf_SetU8(tag, layout->align); //align
1477 swf_SetU16(tag, layout->leftmargin); //left margin
1478 swf_SetU16(tag, layout->rightmargin); //right margin
1479 swf_SetU16(tag, layout->indent); //indent
1480 swf_SetU16(tag, layout->leading); //leading
1482 swf_SetString(tag, variable);
1483 if (flags & ET_HASTEXT)
1484 swf_SetString(tag, text);
1487 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1491 U8 *utext = (U8 *) strdup(text);
1497 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1498 ystep = font->layout->leading;
1500 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1501 /* Hm, without layout information, we can't compute a bounding
1502 box. We could call swf_FontCreateLayout to create a layout,
1503 but the caller probably doesn't want us to mess up his font
1506 r.xmin = r.ymin = 0;
1507 r.xmax = r.ymax = 1024 * 20;
1511 swf_SetRect(tag, &r);
1513 /* The text matrix is pretty boring, as it doesn't apply to
1514 individual characters, but rather whole text objects (or
1515 at least whole char records- haven't tested).
1516 So it can't do anything which we can't already do with
1517 the placeobject tag we use for placing the text on the scene.
1519 swf_SetMatrix(tag, 0);
1521 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1522 swf_SetU8(tag, gbits);
1523 swf_SetU8(tag, abits);
1529 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1532 while(*next && *next!=13 && *next!=10 && count<127) {
1533 readUTF8char(&next);
1536 if(next[0] == 13 || next[0] == 10) {
1541 if(next[0] == 13 && next[1] == 10)
1544 if(next[0] == 13 || next[0] == 10) {
1549 /* now set the text params- notice that a font size of
1550 1024 (or 1024*20 for definefont3) means that the glyphs will
1551 be displayed exactly as they would be in/with a defineshape.
1552 This is not documented in the specs.
1555 /* set the actual text- notice that we just pass our scale
1556 parameter over, as TextSetCharRecord calculates with
1558 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1568 void swf_FontCreateLayout(SWFFONT * f)
1577 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1578 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1579 f->layout->ascent = 0;
1580 f->layout->descent = 0;
1582 for (t = 0; t < f->numchars; t++) {
1586 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1588 fprintf(stderr, "Shape parse error\n");
1591 bbox = swf_GetShapeBoundingBox(shape2);
1592 swf_Shape2Free(shape2);
1593 f->layout->bounds[t] = bbox;
1595 width = (bbox.xmax);
1597 /* The following is a heuristic- it may be that extractfont_DefineText
1598 has already found out some widths for individual characters (from the way
1599 they are used)- we now have to guess whether that width might be possible,
1600 which is the case if it isn't either much too big or much too small */
1601 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1602 f->glyph[t].advance = width;
1604 if (-bbox.ymin > f->layout->ascent)
1605 f->layout->ascent = -bbox.ymin;
1606 if (bbox.ymax > f->layout->descent)
1607 f->layout->descent = bbox.ymax;
1611 #define FONTALIGN_THIN
1612 #define FONTALIGN_MEDIUM
1613 #define FONTALIGN_THICK
1615 void swf_FontCreateAlignZones(SWFFONT * f)
1620 f->alignzones = (ALIGNZONE*)rfx_calloc(sizeof(ALIGNZONE)*f->numchars);
1621 f->alignzone_flags = 0; // thin
1625 for(t=0;t<f->numchars;t++) {
1626 // just align the baseline
1627 f->alignzones[t].x = 0xffff;
1628 f->alignzones[t].y = 0;
1629 f->alignzones[t].dx = 0xffff;
1630 f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
1634 for(t=0;t<f->numchars;t++) {
1635 // just align the baseline
1636 f->alignzones[t].x = 0xffff;
1637 f->alignzones[t].y = 0;
1638 f->alignzones[t].dx = 0xffff;
1639 f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
1644 "-^_~\xad\xaf+`\xac\xb7\xf7" //chars for which to detect one y value
1645 "#=:;\xb1" //chars for which to detect two y values
1646 "\"\xa8" //chars for which to detect two x values
1651 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1653 U8 *s = (U8 *) text;
1659 U32 c = readUTF8char(&s);
1660 int g = font->ascii2glyph[c];
1661 shape = font->glyph[g].shape;
1662 if (((int) g) < 0) {
1663 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1666 shape2 = swf_ShapeToShape2(shape);
1669 if (l->type == moveTo) {
1671 to.x = l->x * size / 100.0 / 20.0 + advance;
1672 to.y = l->y * size / 100.0 / 20.0;
1673 draw->moveTo(draw, &to);
1674 } else if (l->type == lineTo) {
1676 to.x = l->x * size / 100.0 / 20.0 + advance;
1677 to.y = l->y * size / 100.0 / 20.0;
1678 draw->lineTo(draw, &to);
1679 } else if (l->type == splineTo) {
1681 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1682 mid.y = l->sy * size / 100.0 / 20.0;
1683 to.x = l->x * size / 100.0 / 20.0 + advance;
1684 to.y = l->y * size / 100.0 / 20.0;
1685 draw->splineTo(draw, &mid, &to);
1689 swf_Shape2Free(shape2);
1690 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1694 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1697 swf_FontCreateLayout(font);
1700 memset(&swf, 0, sizeof(SWF));
1701 swf.fileVersion = 9;
1702 swf.frameRate = 0x4000;
1703 swf.movieSize.xmax = 200;
1704 swf.movieSize.ymax = 200;
1706 if(!font->id) font->id=1;
1709 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1710 swf_FontSetDefine2(tag, font);
1712 char*name = font->name?(char*)font->name:"font";
1714 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1715 swf_SetU16(tag, font->id);
1716 swf_SetString(tag, name);
1717 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1719 swf_SetU16(tag, font->id);
1720 swf_SetString(tag, name);
1721 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1723 tag = swf_InsertTag(tag, ST_END);
1724 swf_SaveSWF(&swf, filename);
1728 void swf_WriteFont(SWFFONT * font, char *filename)
1731 swf_FontCreateLayout(font);
1740 memset(&swf, 0, sizeof(SWF));
1741 swf.fileVersion = 8;
1742 swf.frameRate = 0x4000;
1743 swf.movieSize.xmax = 1024*20;
1744 swf.movieSize.ymax = 768*20;
1747 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1748 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1750 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1751 swf_FontSetDefine2(tag, font);
1753 if(font->glyphnames) {
1755 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1756 swf_SetU16(tag, font->id);
1757 swf_SetU16(tag, font->numchars);
1758 for (c = 0; c < font->numchars; c++) {
1759 if (font->glyphnames[c])
1760 swf_SetString(tag, font->glyphnames[c]);
1762 swf_SetString(tag, "");
1768 RGBA white = {255,255,255,255};
1769 RGBA black = {255,0,0,0};
1770 RGBA gray50 = {255,128,128,128};
1771 RGBA green = {255,0,255,0};
1773 SCOORD miny = SCOORD_MAX;
1774 SCOORD maxy = SCOORD_MIN;
1776 U16 max_advance = 0;
1777 char*flags = rfx_calloc(font->numchars);
1778 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1779 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1780 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1781 for(t=0;t<font->numchars;t++) {
1782 SHAPE*s = font->glyph[t].shape;
1783 SHAPE2*s2 = swf_ShapeToShape2(s);
1784 SRECT r = swf_GetShapeBoundingBox(s2);
1786 // inside a definefont3, everything is 20x the resolution:
1787 double rx1 = r.xmin / 20.0;
1788 double ry1 = r.ymin / 20.0;
1789 double rx2 = r.xmax / 20.0;
1790 double ry2 = r.ymax / 20.0;
1795 if(ry1<miny) {miny=ry1;}
1796 if(ry2>maxy) {maxy=ry2;}
1797 swf_Shape2Free(s2);free(s2);
1798 width += font->glyph[t].advance;
1799 if(font->glyph[t].advance>max_advance)
1800 max_advance = font->glyph[t].advance;
1803 if(miny==SCOORD_MAX) miny=maxy=0;
1804 if(miny==maxy) maxy=miny+1;
1806 /* scale the font so that it's 256 pixels high */
1807 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1808 double overlarge_factor;
1812 overlarge_factor = scale / 32767.0;
1815 overlarge_factor = 1.0;
1819 int spriteid = id++;
1822 r.ymin = miny*fontsize/1024;
1823 r.xmax = width*fontsize/20480;
1824 r.ymax = maxy*fontsize/1024;
1825 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1826 swf_SetU16(tag, textid);
1827 swf_SetRect(tag, &r);
1828 swf_SetMatrix(tag, NULL);
1831 U8 gbits = swf_CountBits(font->numchars, 0);
1832 swf_SetU8(tag, gbits);
1833 swf_SetU8(tag, abits);
1835 RGBA rgb = {255,0,0,0};
1837 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1838 ActionTAG*array = 0;
1840 array = action_PushString(array, "xpos");
1841 for(t=0;t<font->numchars;t++) {
1843 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1844 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1845 x += width * overlarge_factor;
1846 swf_SetBits(tag, t, gbits);
1847 swf_SetBits(tag, width, abits);
1848 swf_SetU8(tag, 128);
1850 array = action_PushInt(array, x/20);
1851 array = action_PushInt(array, font->numchars+1);
1852 array = action_InitArray(array);
1853 array = action_SetVariable(array);
1857 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1860 int ls = swf_ShapeAddLineStyle(s,20,&white);
1862 swf_SetU16(tag,shapeid);
1868 swf_SetRect(tag,&r);
1869 swf_SetShapeHeader(tag,s);
1870 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1872 /* Ç and  are good chars to test ascent/descent extend */
1873 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1874 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1876 swf_ShapeSetMove(tag,s,0,y1);
1877 swf_ShapeSetLine(tag,s,width,0);
1878 swf_ShapeSetMove(tag,s,0,y2);
1879 swf_ShapeSetLine(tag,s,width,0);
1881 swf_ShapeSetEnd(tag);
1883 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1884 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1889 for(t=0;t<font->numchars;t++) {
1890 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1893 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1894 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1895 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1897 swf_SetU16(tag,shapeid);
1903 swf_SetRect(tag,&r);
1904 swf_SetShapeHeader(tag,s);
1905 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1906 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1907 SHAPELINE*l = s2->lines;
1908 int lastx=0,lasty=0;
1910 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1911 double y1 = -miny*20*scale*2/20480.0;
1912 double scalex = scale*2/20480.0;
1913 double scaley = scale*2/20480.0;
1916 int lx = (l->x)*scalex+x1;
1917 int ly = (l->y)*scaley+y1;
1918 int sx = (l->sx)*scalex+x1;
1919 int sy = (l->sy)*scaley+y1;
1920 if(l->type == moveTo) {
1921 swf_ShapeSetMove(tag,s,lx,ly);
1922 } else if(l->type == lineTo) {
1923 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1924 } else if(l->type == splineTo) {
1925 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1932 if(font->alignzones) {
1933 ALIGNZONE*zone = &font->alignzones[t];
1934 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1935 if((zone->x&zone->dx)!=0xffff) {
1936 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1937 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1938 swf_ShapeSetMove(tag,s,x,0);
1939 swf_ShapeSetLine(tag,s,0,1024*20);
1940 swf_ShapeSetMove(tag,s,dx,0);
1941 swf_ShapeSetLine(tag,s,0,1024*20);
1943 if((zone->y&zone->dy)!=0xffff) {
1944 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
1945 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
1946 swf_ShapeSetMove(tag,s,0,y);
1947 swf_ShapeSetLine(tag,s,1024*20,0);
1948 swf_ShapeSetMove(tag,s,0,dy);
1949 swf_ShapeSetLine(tag,s,1024*20,0);
1953 swf_ShapeSetEnd(tag);
1956 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1958 swf_SetU16(tag, spriteid);
1960 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1961 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1962 tag = swf_InsertTag(tag, ST_END);
1963 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1965 swf_GetMatrix(0, &m);
1968 sprintf(txt, "char%d", font->numchars-t);
1969 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
1973 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1975 RGBA blue = {0xff,0xc0,0xc0,0xff};
1976 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
1977 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1979 swf_SetU16(tag, spriteid2);
1981 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1982 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1983 tag = swf_InsertTag(tag, ST_END);
1984 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1985 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
1988 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1989 swf_SetU16(tag, spriteid);
1991 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1993 swf_GetMatrix(0, &m);
1994 m.sx = 65536 * overlarge_factor;
1995 m.sy = 65536 * overlarge_factor;
1997 m.ty = -miny*256*20/(maxy-miny);
1998 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
1999 tag = swf_InsertTag(tag, ST_END);
2000 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2001 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
2004 RGBA blue2 = {0x80,0x80,0xff,0x80};
2005 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2007 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2008 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2010 swf_SetU16(tag, spriteid3);
2012 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2013 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2014 tag = swf_InsertTag(tag, ST_END);
2015 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2016 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2020 " var mouseListener = new Object();"
2023 " var currentMouseOver, currentChar;"
2024 " mouseListener.onMouseDown = function() { "
2025 " eval(\"_root.char\"+currentChar)._y = 20000;"
2026 " currentChar = currentMouseOver;"
2027 " var i = currentMouseOver;"
2028 " eval(\"_root.char\"+i)._y = 256;"
2029 " _root.marker2._yscale=256*100;"
2030 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2031 " _root.marker2._x=xpos[i]+myx;"
2033 " mouseListener.onMouseMove = function() { "
2034 " if(_ymouse<256) {"
2035 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2040 " setInterval( function(){ "
2041 " if(_ymouse<256) {"
2042 " var i, x=_xmouse-_root.textbar._x;"
2043 " for(i=xpos.length-1;i>0;i--) {"
2044 " if(x<xpos[i-1]) break;"
2046 " currentMouseOver = i;"
2047 " _root.marker._yscale=256*100;"
2048 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2049 " _root.marker._x=xpos[i]+myx;"
2050 " _root.textbar._x += 0.05;"
2052 " if(myx+speed>0) {"
2054 " } else if(myx+speed<-xpos[0]+1024) {"
2058 " _root.textbar._x = myx;"
2059 " _root.marker._x += speed;"
2060 " _root.marker2._x += speed;"
2062 " Mouse.addListener(mouseListener);"
2064 ActionTAG* atag = swf_ActionCompile(data, 6);
2066 tag = swf_InsertTag(tag, ST_DOACTION);
2067 swf_ActionSet(tag, array);
2068 swf_ActionSet(tag, atag);
2070 swf_ActionFree(atag);
2072 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2079 tag = swf_InsertTag(tag, ST_END);
2081 swf.compressed = -1;
2082 swf_SaveSWF(&swf, filename);