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 if(f->use->neighbors) {
629 rfx_free(f->use->neighbors);f->use->neighbors = 0;
631 if(f->use->neighbors_hash) {
632 rfx_free(f->use->neighbors_hash);f->use->neighbors_hash = 0;
634 rfx_free(f->use); f->use = 0;
637 static void font_freelayout(SWFFONT*f)
640 swf_LayoutFree(f->layout);
644 static void font_freename(SWFFONT*f)
652 int swf_FontReduce_old(SWFFONT * f)
656 if ((!f) || (!f->use) || f->use->is_reduced)
661 for (i = 0; i < f->numchars; i++) {
662 if (f->glyph[i].shape && f->use->chars[i]) {
663 f->glyph2ascii[j] = f->glyph2ascii[i];
664 f->glyph[j] = f->glyph[i];
665 f->use->chars[i] = j;
668 f->glyph2ascii[i] = 0;
669 if(f->glyph[i].shape) {
670 swf_ShapeFree(f->glyph[i].shape);
671 f->glyph[i].shape = 0;
672 f->glyph[i].advance = 0;
674 f->use->chars[i] = -1;
678 for (i = 0; i < f->maxascii; i++) {
679 if(f->use->chars[f->ascii2glyph[i]]<0) {
680 f->ascii2glyph[i] = -1;
682 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
686 f->maxascii = max_unicode;
687 f->use->is_reduced = 1;
690 font_freeglyphnames(f);
695 int swf_FontReduce_swfc(SWFFONT * f)
699 if ((!f) || (!f->use) || f->use->is_reduced)
702 font_freeglyphnames(f);
705 for (i = 0; i < f->numchars; i++) {
706 if (f->glyph[i].shape && f->use->chars[i]) {
707 f->glyph2ascii[j] = f->glyph2ascii[i];
709 f->layout->bounds[j] = f->layout->bounds[i];
710 f->glyph[j] = f->glyph[i];
711 f->use->chars[i] = j;
714 f->glyph2ascii[i] = 0;
715 if(f->glyph[i].shape) {
716 swf_ShapeFree(f->glyph[i].shape);
717 f->glyph[i].shape = 0;
718 f->glyph[i].advance = 0;
720 f->use->chars[i] = -1;
723 f->use->used_glyphs = j;
724 for (i = 0; i < f->maxascii; i++) {
725 if(f->ascii2glyph[i] > -1) {
726 if (f->use->chars[f->ascii2glyph[i]]<0) {
727 f->use->chars[f->ascii2glyph[i]] = 0;
728 f->ascii2glyph[i] = -1;
730 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
731 f->use->chars[f->ascii2glyph[i]] = 1;
736 f->maxascii = max_unicode;
737 f->use->is_reduced = 1;
743 int swf_FontReduce(SWFFONT * f)
748 if ((!f) || (!f->use) || f->use->is_reduced)
752 font_freeglyphnames(f);
754 f->use->used_glyphs= 0;
755 for (i = 0; i < f->numchars; i++) {
756 if(!f->use->chars[i]) {
758 f->glyph2ascii[i] = 0;
760 if(f->glyph[i].shape) {
761 swf_ShapeFree(f->glyph[i].shape);
762 f->glyph[i].shape = 0;
763 f->glyph[i].advance = 0;
765 // f->use->used_glyphs++;
767 f->use->used_glyphs++;
771 for (i = 0; i < f->maxascii; i++) {
772 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
774 f->ascii2glyph[i] = -1;
780 f->maxascii = max_unicode;
781 f->numchars = max_glyph;
786 void swf_FontSort(SWFFONT * font)
794 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
796 for (i = 0; i < font->numchars; i++) {
799 for (i = 0; i < font->numchars; i++)
800 for (j = 0; j < i; j++) {
801 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
810 n1 = font->glyph2ascii[i];
811 n2 = font->glyph2ascii[j];
812 font->glyph2ascii[j] = n1;
813 font->glyph2ascii[i] = n2;
818 if (font->glyphnames) {
819 c1 = font->glyphnames[i];
820 c2 = font->glyphnames[j];
821 font->glyphnames[j] = c1;
822 font->glyphnames[i] = c2;
825 r1 = font->layout->bounds[i];
826 r2 = font->layout->bounds[j];
827 font->layout->bounds[j] = r1;
828 font->layout->bounds[i] = r2;
832 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
833 for (i = 0; i < font->numchars; i++) {
834 newpos[newplace[i]] = i;
836 for (i = 0; i < font->maxascii; i++) {
837 if (font->ascii2glyph[i] >= 0)
838 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
845 void swf_FontPrepareForEditText(SWFFONT * font)
848 swf_FontCreateLayout(font);
852 int swf_FontInitUsage(SWFFONT * f)
857 fprintf(stderr, "Usage initialized twice");
860 f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE));
861 f->use->smallest_size = 0xffff;
862 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
866 void swf_FontClearUsage(SWFFONT * f)
870 rfx_free(f->use->chars); f->use->chars = 0;
871 rfx_free(f->use); f->use = 0;
874 int swf_FontUse(SWFFONT * f, U8 * s)
879 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
880 swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
886 int swf_FontUseUTF8(SWFFONT * f, U8 * s, U16 size)
893 ascii = readUTF8char(&s);
894 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
895 swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
900 int swf_FontUseAll(SWFFONT* f)
905 swf_FontInitUsage(f);
906 for (i = 0; i < f->numchars; i++)
907 f->use->chars[i] = 1;
908 f->use->used_glyphs = f->numchars;
912 static unsigned hash2(int char1, int char2)
914 unsigned hash = char1^(char2<<8);
916 hash ^= (hash >> 11);
917 hash += (hash << 15);
920 static void hashadd(FONTUSAGE*u, int char1, int char2, int nr)
922 unsigned hash = hash2(char1, char2);
924 hash = hash%u->neighbors_hash_size;
925 if(!u->neighbors_hash[hash]) {
926 u->neighbors_hash[hash] = nr+1;
932 int swf_FontUseGetPair(SWFFONT * f, int char1, int char2)
934 FONTUSAGE*u = f->use;
935 if(!u || !u->neighbors_hash_size)
937 unsigned hash = hash2(char1, char2);
939 hash = hash%u->neighbors_hash_size;
940 int pos = u->neighbors_hash[hash];
944 u->neighbors[pos-1].char1 == char1 &&
945 u->neighbors[pos-1].char2 == char2) {
952 void swf_FontUsePair(SWFFONT * f, int char1, int char2)
955 swf_FontInitUsage(f);
956 FONTUSAGE*u = f->use;
958 if(u->num_neighbors*3 >= u->neighbors_hash_size*2) {
959 if(u->neighbors_hash) {
960 free(u->neighbors_hash);
962 u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024;
963 u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int));
965 for(t=0;t<u->num_neighbors;t++) {
966 hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t);
970 int nr = swf_FontUseGetPair(f, char1, char2);
972 if(u->num_neighbors == u->neighbors_size) {
973 u->neighbors_size += 4096;
974 u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
976 u->neighbors[u->num_neighbors].char1 = char1;
977 u->neighbors[u->num_neighbors].char2 = char2;
978 u->neighbors[u->num_neighbors].num = 1;
979 hashadd(u, char1, char2, u->num_neighbors);
982 u->neighbors[nr-1].num++;
986 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
989 swf_FontInitUsage(f);
990 if(glyph < 0 || glyph >= f->numchars)
992 if(!f->use->chars[glyph])
993 f->use->used_glyphs++;
994 f->use->chars[glyph] = 1;
995 if(size && size < f->use->smallest_size)
996 f->use->smallest_size = size;
1000 int swf_FontSetDefine(TAG * t, SWFFONT * f)
1002 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
1007 swf_ResetWriteBits(t);
1008 swf_SetU16(t, f->id);
1012 for (i = 0; i < f->numchars; i++)
1013 if (f->glyph[i].shape) {
1015 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
1018 for (i = 0; i < j; i++)
1019 swf_SetU16(t, ofs[i] + j * 2);
1021 fprintf(stderr, "rfxswf: warning: Font is empty\n");
1025 for (i = 0; i < f->numchars; i++)
1026 if (f->glyph[i].shape)
1027 swf_SetSimpleShape(t, f->glyph[i].shape);
1029 swf_ResetWriteBits(t);
1034 static inline int fontSize(SWFFONT * font)
1038 for (t = 0; t < font->numchars; t++) {
1040 if(font->glyph[t].shape)
1041 l = (font->glyph[t].shape->bitlen + 7) / 8;
1046 return size + (font->numchars + 1) * 2;
1049 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
1054 swf_SetU16(tag, f->id);
1056 if (f->layout) flags |= 128; // haslayout
1057 if (f->numchars > 256)
1058 flags |= 4; // widecodes
1059 if (f->style & FONT_STYLE_BOLD)
1061 if (f->style & FONT_STYLE_ITALIC)
1062 flags |= 2; // italic
1063 if (f->maxascii >= 256)
1064 flags |= 4; //wide codecs
1065 if (fontSize(f) > 65535)
1066 flags |= 8; //wide offsets
1067 flags |= 8 | 4; //FIXME: the above check doesn't work
1069 if (f->encoding & FONT_ENCODING_ANSI)
1070 flags |= 16; // ansi
1071 if (f->encoding & FONT_ENCODING_UNICODE)
1072 flags |= 32; // unicode
1073 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1074 flags |= 64; // shiftjis
1076 swf_SetU8(tag, flags);
1077 swf_SetU8(tag, 0); //reserved flags
1080 swf_SetU8(tag, strlen((const char*)f->name)+1);
1081 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1083 /* font name (="") */
1087 /* number of glyphs */
1088 swf_SetU16(tag, f->numchars);
1089 /* font offset table */
1091 for (t = 0; t <= f->numchars; t++) {
1093 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1095 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1098 for (t = 0; t <= f->numchars; t++) {
1100 tag->data[pos + t * 4] = (tag->len - pos);
1101 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1102 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1103 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1105 if (tag->len - pos > 65535) {
1106 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1109 tag->data[pos + t * 2] = (tag->len - pos);
1110 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1112 if (t < f->numchars) {
1113 if(f->glyph[t].shape) {
1114 swf_SetSimpleShape(tag, f->glyph[t].shape);
1116 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1122 /* font code table */
1123 for (t = 0; t < f->numchars; t++) {
1124 if (flags & 4) { /* wide codes */
1125 if(f->glyph2ascii[t]) {
1126 swf_SetU16(tag, f->glyph2ascii[t]);
1131 if(f->glyph2ascii[t]) {
1132 swf_SetU8(tag, f->glyph2ascii[t]);
1140 swf_SetU16(tag, f->layout->ascent);
1141 swf_SetU16(tag, f->layout->descent);
1142 swf_SetU16(tag, f->layout->leading);
1143 for (t = 0; t < f->numchars; t++)
1144 swf_SetU16(tag, f->glyph[t].advance);
1145 for (t = 0; t < f->numchars; t++) {
1146 swf_ResetWriteBits(tag);
1147 swf_SetRect(tag, &f->layout->bounds[t]);
1149 swf_SetU16(tag, f->layout->kerningcount);
1150 for (t = 0; t < f->layout->kerningcount; t++) {
1151 if (flags & 4) { /* wide codes */
1152 swf_SetU16(tag, f->layout->kerning[t].char1);
1153 swf_SetU16(tag, f->layout->kerning[t].char2);
1155 swf_SetU8(tag, f->layout->kerning[t].char1);
1156 swf_SetU8(tag, f->layout->kerning[t].char2);
1158 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1164 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1166 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1167 f->layout->ascent = ascent;
1168 f->layout->descent = descent;
1169 f->layout->leading = leading;
1170 f->layout->kerningcount = 0;
1171 f->layout->kerning = 0;
1172 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1175 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1182 swf_ResetWriteBits(t);
1183 swf_SetU16(t, f->id);
1184 l = f->name ? strlen((const char *)f->name) : 0;
1189 swf_SetBlock(t, f->name, l);
1190 if (f->numchars >= 256)
1193 if (f->style & FONT_STYLE_BOLD)
1195 if (f->style & FONT_STYLE_ITALIC)
1197 if (f->style & FONT_ENCODING_ANSI)
1199 if (f->style & FONT_ENCODING_SHIFTJIS)
1201 if (f->style & FONT_ENCODING_UNICODE)
1204 swf_SetU8(t, (flags & 0xfe) | wide);
1206 for (i = 0; i < f->numchars; i++) {
1207 if (f->glyph[i].shape) {
1208 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1209 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1216 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1218 int id = swf_GetTagID(t);
1219 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1220 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1226 void swf_FontFree(SWFFONT * f)
1234 for (i = 0; i < f->numchars; i++)
1235 if (f->glyph[i].shape)
1237 swf_ShapeFree(f->glyph[i].shape);
1238 f->glyph[i].shape = NULL;
1245 rfx_free(f->ascii2glyph);
1246 f->ascii2glyph = NULL;
1250 rfx_free(f->glyph2ascii);
1251 f->glyph2ascii = NULL;
1255 font_freeglyphnames(f);
1261 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1267 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1268 | (y ? TF_HASYOFFSET : 0);
1270 swf_SetU8(t, flags);
1272 swf_SetU16(t, font->id);
1274 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1275 swf_SetRGBA(t, color);
1277 swf_SetRGB(t, color);
1280 if(x != SET_TO_ZERO) {
1281 if(x>32767 || x<-32768)
1282 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1289 if(y != SET_TO_ZERO) {
1290 if(y>32767 || y<-32768)
1291 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1298 swf_SetU16(t, size);
1303 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1307 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1311 if (!strcmp(encoding, "UTF8"))
1313 else if (!strcmp(encoding, "iso-8859-1"))
1316 fprintf(stderr, "Unknown encoding: %s", encoding);
1324 c = readUTF8char(&s);
1326 if (c < font->maxascii)
1327 glyph = font->ascii2glyph[c];
1329 g = swf_CountUBits(glyph, g);
1330 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1341 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1346 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1349 if (!strcmp(encoding, "UTF8"))
1351 else if (!strcmp(encoding, "iso-8859-1"))
1354 fprintf(stderr, "Unknown encoding: %s", encoding);
1357 swf_SetU8(t, l); //placeholder
1365 c = readUTF8char(&s);
1367 if (c < font->maxascii)
1368 g = font->ascii2glyph[c];
1370 swf_SetBits(t, g, gbits);
1371 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1373 /* We split into 127 characters per text field.
1374 We could do 255, by the (formerly wrong) flash specification,
1375 but some SWF parsing code out there still assumes that char blocks
1376 are at max 127 characters, and it would save only a few bits.
1383 PUT8(&t->data[pos], l);
1385 swf_ResetWriteBits(t);
1389 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1391 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1394 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1396 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1399 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1401 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1404 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1406 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1409 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1416 if (*s < font->maxascii)
1417 g = font->ascii2glyph[*s];
1419 res += font->glyph[g].advance / 20;
1423 res = (res * scale) / 100;
1428 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1435 int c = readUTF8char(&s);
1436 if(c==13 || c==10) {
1441 ypos+=font->layout->leading;
1444 if (c < font->maxascii) {
1445 int g = font->ascii2glyph[c];
1447 SRECT rn = font->layout->bounds[g];
1448 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1449 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1450 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1451 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1452 swf_ExpandRect2(&r, &rn);
1453 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1461 SWFFONT *swf_ReadFont(const char *filename)
1467 f = open(filename, O_RDONLY|O_BINARY);
1469 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1470 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1476 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1483 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)
1485 swf_SetRect(tag, &r);
1486 swf_ResetWriteBits(tag);
1488 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1490 flags |= ET_HASTEXT;
1492 flags |= ET_HASTEXTCOLOR;
1494 flags |= ET_HASMAXLENGTH;
1496 flags |= ET_HASFONT;
1498 flags |= ET_HASLAYOUT;
1500 swf_SetBits(tag, flags, 16);
1502 if (flags & ET_HASFONT) {
1503 swf_SetU16(tag, font); //font
1504 swf_SetU16(tag, height); //fontheight
1506 if (flags & ET_HASTEXTCOLOR) {
1507 swf_SetRGBA(tag, color);
1509 if (flags & ET_HASMAXLENGTH) {
1510 swf_SetU16(tag, maxlength); //maxlength
1512 if (flags & ET_HASLAYOUT) {
1513 swf_SetU8(tag, layout->align); //align
1514 swf_SetU16(tag, layout->leftmargin); //left margin
1515 swf_SetU16(tag, layout->rightmargin); //right margin
1516 swf_SetU16(tag, layout->indent); //indent
1517 swf_SetU16(tag, layout->leading); //leading
1519 swf_SetString(tag, variable);
1520 if (flags & ET_HASTEXT)
1521 swf_SetString(tag, text);
1524 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1528 U8 *utext = (U8 *) strdup(text);
1534 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1535 ystep = font->layout->leading;
1537 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1538 /* Hm, without layout information, we can't compute a bounding
1539 box. We could call swf_FontCreateLayout to create a layout,
1540 but the caller probably doesn't want us to mess up his font
1543 r.xmin = r.ymin = 0;
1544 r.xmax = r.ymax = 1024 * 20;
1548 swf_SetRect(tag, &r);
1550 /* The text matrix is pretty boring, as it doesn't apply to
1551 individual characters, but rather whole text objects (or
1552 at least whole char records- haven't tested).
1553 So it can't do anything which we can't already do with
1554 the placeobject tag we use for placing the text on the scene.
1556 swf_SetMatrix(tag, 0);
1558 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1559 swf_SetU8(tag, gbits);
1560 swf_SetU8(tag, abits);
1566 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1569 while(*next && *next!=13 && *next!=10 && count<127) {
1570 readUTF8char(&next);
1573 if(next[0] == 13 || next[0] == 10) {
1578 if(next[0] == 13 && next[1] == 10)
1581 if(next[0] == 13 || next[0] == 10) {
1586 /* now set the text params- notice that a font size of
1587 1024 (or 1024*20 for definefont3) means that the glyphs will
1588 be displayed exactly as they would be in/with a defineshape.
1589 This is not documented in the specs.
1592 /* set the actual text- notice that we just pass our scale
1593 parameter over, as TextSetCharRecord calculates with
1595 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1605 void swf_FontCreateLayout(SWFFONT * f)
1614 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1615 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1616 f->layout->ascent = 0;
1617 f->layout->descent = 0;
1619 for (t = 0; t < f->numchars; t++) {
1623 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1625 fprintf(stderr, "Shape parse error\n");
1628 bbox = swf_GetShapeBoundingBox(shape2);
1629 swf_Shape2Free(shape2);
1630 f->layout->bounds[t] = bbox;
1632 width = (bbox.xmax);
1634 /* The following is a heuristic- it may be that extractfont_DefineText
1635 has already found out some widths for individual characters (from the way
1636 they are used)- we now have to guess whether that width might be possible,
1637 which is the case if it isn't either much too big or much too small */
1638 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1639 f->glyph[t].advance = width;
1641 if (-bbox.ymin > f->layout->ascent)
1642 f->layout->ascent = -bbox.ymin;
1643 if (bbox.ymax > f->layout->descent)
1644 f->layout->descent = bbox.ymax;
1648 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1650 U8 *s = (U8 *) text;
1656 U32 c = readUTF8char(&s);
1657 int g = font->ascii2glyph[c];
1658 shape = font->glyph[g].shape;
1659 if (((int) g) < 0) {
1660 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1663 shape2 = swf_ShapeToShape2(shape);
1666 if (l->type == moveTo) {
1668 to.x = l->x * size / 100.0 / 20.0 + advance;
1669 to.y = l->y * size / 100.0 / 20.0;
1670 draw->moveTo(draw, &to);
1671 } else if (l->type == lineTo) {
1673 to.x = l->x * size / 100.0 / 20.0 + advance;
1674 to.y = l->y * size / 100.0 / 20.0;
1675 draw->lineTo(draw, &to);
1676 } else if (l->type == splineTo) {
1678 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1679 mid.y = l->sy * size / 100.0 / 20.0;
1680 to.x = l->x * size / 100.0 / 20.0 + advance;
1681 to.y = l->y * size / 100.0 / 20.0;
1682 draw->splineTo(draw, &mid, &to);
1686 swf_Shape2Free(shape2);
1687 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1691 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1694 swf_FontCreateLayout(font);
1697 memset(&swf, 0, sizeof(SWF));
1698 swf.fileVersion = 9;
1699 swf.frameRate = 0x4000;
1700 swf.movieSize.xmax = 200;
1701 swf.movieSize.ymax = 200;
1703 if(!font->id) font->id=1;
1706 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1707 swf_FontSetDefine2(tag, font);
1709 char*name = font->name?(char*)font->name:"font";
1711 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1712 swf_SetU16(tag, font->id);
1713 swf_SetString(tag, name);
1714 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1716 swf_SetU16(tag, font->id);
1717 swf_SetString(tag, name);
1718 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1720 tag = swf_InsertTag(tag, ST_END);
1721 swf_SaveSWF(&swf, filename);
1725 void swf_WriteFont(SWFFONT * font, char *filename)
1728 swf_FontCreateLayout(font);
1737 memset(&swf, 0, sizeof(SWF));
1738 swf.fileVersion = 8;
1739 swf.frameRate = 0x4000;
1740 swf.movieSize.xmax = 1024*20;
1741 swf.movieSize.ymax = 768*20;
1744 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1745 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1747 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1748 swf_FontSetDefine2(tag, font);
1750 if(font->glyphnames) {
1752 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1753 swf_SetU16(tag, font->id);
1754 swf_SetU16(tag, font->numchars);
1755 for (c = 0; c < font->numchars; c++) {
1756 if (font->glyphnames[c])
1757 swf_SetString(tag, font->glyphnames[c]);
1759 swf_SetString(tag, "");
1765 RGBA white = {255,255,255,255};
1766 RGBA black = {255,0,0,0};
1767 RGBA gray50 = {255,128,128,128};
1768 RGBA green = {255,0,255,0};
1770 SCOORD miny = SCOORD_MAX;
1771 SCOORD maxy = SCOORD_MIN;
1773 U16 max_advance = 0;
1774 char*flags = rfx_calloc(font->numchars);
1775 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1776 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1777 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1778 for(t=0;t<font->numchars;t++) {
1779 SHAPE*s = font->glyph[t].shape;
1780 SHAPE2*s2 = swf_ShapeToShape2(s);
1781 SRECT r = swf_GetShapeBoundingBox(s2);
1783 // inside a definefont3, everything is 20x the resolution:
1784 double rx1 = r.xmin / 20.0;
1785 double ry1 = r.ymin / 20.0;
1786 double rx2 = r.xmax / 20.0;
1787 double ry2 = r.ymax / 20.0;
1792 if(ry1<miny) {miny=ry1;}
1793 if(ry2>maxy) {maxy=ry2;}
1794 swf_Shape2Free(s2);free(s2);
1795 width += font->glyph[t].advance;
1796 if(font->glyph[t].advance>max_advance)
1797 max_advance = font->glyph[t].advance;
1800 if(miny==SCOORD_MAX) miny=maxy=0;
1801 if(miny==maxy) maxy=miny+1;
1803 /* scale the font so that it's 256 pixels high */
1804 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1805 double overlarge_factor;
1809 overlarge_factor = scale / 32767.0;
1812 overlarge_factor = 1.0;
1816 int spriteid = id++;
1819 r.ymin = miny*fontsize/1024;
1820 r.xmax = width*fontsize/20480;
1821 r.ymax = maxy*fontsize/1024;
1822 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1823 swf_SetU16(tag, textid);
1824 swf_SetRect(tag, &r);
1825 swf_SetMatrix(tag, NULL);
1828 U8 gbits = swf_CountBits(font->numchars, 0);
1829 swf_SetU8(tag, gbits);
1830 swf_SetU8(tag, abits);
1832 RGBA rgb = {255,0,0,0};
1834 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1835 ActionTAG*array = 0;
1837 array = action_PushString(array, "xpos");
1838 for(t=0;t<font->numchars;t++) {
1840 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1841 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1842 x += width * overlarge_factor;
1843 swf_SetBits(tag, t, gbits);
1844 swf_SetBits(tag, width, abits);
1845 swf_SetU8(tag, 128);
1847 array = action_PushInt(array, x/20);
1848 array = action_PushInt(array, font->numchars+1);
1849 array = action_InitArray(array);
1850 array = action_SetVariable(array);
1854 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1857 int ls = swf_ShapeAddLineStyle(s,20,&white);
1859 swf_SetU16(tag,shapeid);
1865 swf_SetRect(tag,&r);
1866 swf_SetShapeHeader(tag,s);
1867 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1869 /* Ç and  are good chars to test ascent/descent extend */
1870 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1871 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1873 swf_ShapeSetMove(tag,s,0,y1);
1874 swf_ShapeSetLine(tag,s,width,0);
1875 swf_ShapeSetMove(tag,s,0,y2);
1876 swf_ShapeSetLine(tag,s,width,0);
1878 swf_ShapeSetEnd(tag);
1880 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1881 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1886 for(t=0;t<font->numchars;t++) {
1887 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1890 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1891 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1892 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1894 swf_SetU16(tag,shapeid);
1900 swf_SetRect(tag,&r);
1901 swf_SetShapeHeader(tag,s);
1902 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1903 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1904 SHAPELINE*l = s2->lines;
1905 int lastx=0,lasty=0;
1907 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1908 double y1 = -miny*20*scale*2/20480.0;
1909 double scalex = scale*2/20480.0;
1910 double scaley = scale*2/20480.0;
1913 int lx = (l->x)*scalex+x1;
1914 int ly = (l->y)*scaley+y1;
1915 int sx = (l->sx)*scalex+x1;
1916 int sy = (l->sy)*scaley+y1;
1917 if(l->type == moveTo) {
1918 swf_ShapeSetMove(tag,s,lx,ly);
1919 } else if(l->type == lineTo) {
1920 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1921 } else if(l->type == splineTo) {
1922 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1929 if(font->alignzones) {
1930 ALIGNZONE*zone = &font->alignzones[t];
1931 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1932 if((zone->x&zone->dx)!=0xffff) {
1933 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1934 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1935 swf_ShapeSetMove(tag,s,x,0);
1936 swf_ShapeSetLine(tag,s,0,1024*20);
1937 swf_ShapeSetMove(tag,s,dx,0);
1938 swf_ShapeSetLine(tag,s,0,1024*20);
1940 if((zone->y&zone->dy)!=0xffff) {
1941 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
1942 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
1943 swf_ShapeSetMove(tag,s,0,y);
1944 swf_ShapeSetLine(tag,s,1024*20,0);
1945 swf_ShapeSetMove(tag,s,0,dy);
1946 swf_ShapeSetLine(tag,s,1024*20,0);
1950 swf_ShapeSetEnd(tag);
1953 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1955 swf_SetU16(tag, spriteid);
1957 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1958 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1959 tag = swf_InsertTag(tag, ST_END);
1960 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1962 swf_GetMatrix(0, &m);
1965 sprintf(txt, "char%d", font->numchars-t);
1966 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
1970 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1972 RGBA blue = {0xff,0xc0,0xc0,0xff};
1973 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
1974 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1976 swf_SetU16(tag, spriteid2);
1978 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1979 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1980 tag = swf_InsertTag(tag, ST_END);
1981 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1982 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
1985 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1986 swf_SetU16(tag, spriteid);
1988 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1990 swf_GetMatrix(0, &m);
1991 m.sx = 65536 * overlarge_factor;
1992 m.sy = 65536 * overlarge_factor;
1994 m.ty = -miny*256*20/(maxy-miny);
1995 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
1996 tag = swf_InsertTag(tag, ST_END);
1997 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1998 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
2001 RGBA blue2 = {0x80,0x80,0xff,0x80};
2002 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2004 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2005 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2007 swf_SetU16(tag, spriteid3);
2009 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2010 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2011 tag = swf_InsertTag(tag, ST_END);
2012 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2013 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2017 " var mouseListener = new Object();"
2020 " var currentMouseOver, currentChar;"
2021 " mouseListener.onMouseDown = function() { "
2022 " eval(\"_root.char\"+currentChar)._y = 20000;"
2023 " currentChar = currentMouseOver;"
2024 " var i = currentMouseOver;"
2025 " eval(\"_root.char\"+i)._y = 256;"
2026 " _root.marker2._yscale=256*100;"
2027 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2028 " _root.marker2._x=xpos[i]+myx;"
2030 " mouseListener.onMouseMove = function() { "
2031 " if(_ymouse<256) {"
2032 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2037 " setInterval( function(){ "
2038 " if(_ymouse<256) {"
2039 " var i, x=_xmouse-_root.textbar._x;"
2040 " for(i=xpos.length-1;i>0;i--) {"
2041 " if(x<xpos[i-1]) break;"
2043 " currentMouseOver = i;"
2044 " _root.marker._yscale=256*100;"
2045 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2046 " _root.marker._x=xpos[i]+myx;"
2047 " _root.textbar._x += 0.05;"
2049 " if(myx+speed>0) {"
2051 " } else if(myx+speed<-xpos[0]+1024) {"
2055 " _root.textbar._x = myx;"
2056 " _root.marker._x += speed;"
2057 " _root.marker2._x += speed;"
2059 " Mouse.addListener(mouseListener);"
2061 ActionTAG* atag = swf_ActionCompile(data, 6);
2063 tag = swf_InsertTag(tag, ST_DOACTION);
2064 swf_ActionSet(tag, array);
2065 swf_ActionSet(tag, atag);
2067 swf_ActionFree(atag);
2069 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2076 tag = swf_InsertTag(tag, ST_END);
2078 swf.compressed = -1;
2079 swf_SaveSWF(&swf, filename);