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 if(!swf_FontUseGetPair(f, char1, char2)) {
971 if(u->num_neighbors == u->neighbors_size) {
972 u->neighbors_size += 4096;
973 u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
975 u->neighbors[u->num_neighbors].char1 = char1;
976 u->neighbors[u->num_neighbors].char2 = char2;
977 hashadd(u, char1, char2, u->num_neighbors);
984 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
987 swf_FontInitUsage(f);
988 if(glyph < 0 || glyph >= f->numchars)
990 if(!f->use->chars[glyph])
991 f->use->used_glyphs++;
992 f->use->chars[glyph] = 1;
993 if(size && size < f->use->smallest_size)
994 f->use->smallest_size = size;
998 int swf_FontSetDefine(TAG * t, SWFFONT * f)
1000 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
1005 swf_ResetWriteBits(t);
1006 swf_SetU16(t, f->id);
1010 for (i = 0; i < f->numchars; i++)
1011 if (f->glyph[i].shape) {
1013 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
1016 for (i = 0; i < j; i++)
1017 swf_SetU16(t, ofs[i] + j * 2);
1019 fprintf(stderr, "rfxswf: warning: Font is empty\n");
1023 for (i = 0; i < f->numchars; i++)
1024 if (f->glyph[i].shape)
1025 swf_SetSimpleShape(t, f->glyph[i].shape);
1027 swf_ResetWriteBits(t);
1032 static inline int fontSize(SWFFONT * font)
1036 for (t = 0; t < font->numchars; t++) {
1038 if(font->glyph[t].shape)
1039 l = (font->glyph[t].shape->bitlen + 7) / 8;
1044 return size + (font->numchars + 1) * 2;
1047 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
1052 swf_SetU16(tag, f->id);
1054 if (f->layout) flags |= 128; // haslayout
1055 if (f->numchars > 256)
1056 flags |= 4; // widecodes
1057 if (f->style & FONT_STYLE_BOLD)
1059 if (f->style & FONT_STYLE_ITALIC)
1060 flags |= 2; // italic
1061 if (f->maxascii >= 256)
1062 flags |= 4; //wide codecs
1063 if (fontSize(f) > 65535)
1064 flags |= 8; //wide offsets
1065 flags |= 8 | 4; //FIXME: the above check doesn't work
1067 if (f->encoding & FONT_ENCODING_ANSI)
1068 flags |= 16; // ansi
1069 if (f->encoding & FONT_ENCODING_UNICODE)
1070 flags |= 32; // unicode
1071 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1072 flags |= 64; // shiftjis
1074 swf_SetU8(tag, flags);
1075 swf_SetU8(tag, 0); //reserved flags
1078 swf_SetU8(tag, strlen((const char*)f->name)+1);
1079 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1081 /* font name (="") */
1085 /* number of glyphs */
1086 swf_SetU16(tag, f->numchars);
1087 /* font offset table */
1089 for (t = 0; t <= f->numchars; t++) {
1091 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1093 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1096 for (t = 0; t <= f->numchars; t++) {
1098 tag->data[pos + t * 4] = (tag->len - pos);
1099 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1100 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1101 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1103 if (tag->len - pos > 65535) {
1104 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1107 tag->data[pos + t * 2] = (tag->len - pos);
1108 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1110 if (t < f->numchars) {
1111 if(f->glyph[t].shape) {
1112 swf_SetSimpleShape(tag, f->glyph[t].shape);
1114 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1120 /* font code table */
1121 for (t = 0; t < f->numchars; t++) {
1122 if (flags & 4) { /* wide codes */
1123 if(f->glyph2ascii[t]) {
1124 swf_SetU16(tag, f->glyph2ascii[t]);
1129 if(f->glyph2ascii[t]) {
1130 swf_SetU8(tag, f->glyph2ascii[t]);
1138 swf_SetU16(tag, f->layout->ascent);
1139 swf_SetU16(tag, f->layout->descent);
1140 swf_SetU16(tag, f->layout->leading);
1141 for (t = 0; t < f->numchars; t++)
1142 swf_SetU16(tag, f->glyph[t].advance);
1143 for (t = 0; t < f->numchars; t++) {
1144 swf_ResetWriteBits(tag);
1145 swf_SetRect(tag, &f->layout->bounds[t]);
1147 swf_SetU16(tag, f->layout->kerningcount);
1148 for (t = 0; t < f->layout->kerningcount; t++) {
1149 if (flags & 4) { /* wide codes */
1150 swf_SetU16(tag, f->layout->kerning[t].char1);
1151 swf_SetU16(tag, f->layout->kerning[t].char2);
1153 swf_SetU8(tag, f->layout->kerning[t].char1);
1154 swf_SetU8(tag, f->layout->kerning[t].char2);
1156 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1162 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1164 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1165 f->layout->ascent = ascent;
1166 f->layout->descent = descent;
1167 f->layout->leading = leading;
1168 f->layout->kerningcount = 0;
1169 f->layout->kerning = 0;
1170 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1173 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1180 swf_ResetWriteBits(t);
1181 swf_SetU16(t, f->id);
1182 l = f->name ? strlen((const char *)f->name) : 0;
1187 swf_SetBlock(t, f->name, l);
1188 if (f->numchars >= 256)
1191 if (f->style & FONT_STYLE_BOLD)
1193 if (f->style & FONT_STYLE_ITALIC)
1195 if (f->style & FONT_ENCODING_ANSI)
1197 if (f->style & FONT_ENCODING_SHIFTJIS)
1199 if (f->style & FONT_ENCODING_UNICODE)
1202 swf_SetU8(t, (flags & 0xfe) | wide);
1204 for (i = 0; i < f->numchars; i++) {
1205 if (f->glyph[i].shape) {
1206 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1207 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1214 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1216 int id = swf_GetTagID(t);
1217 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1218 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1224 void swf_FontFree(SWFFONT * f)
1232 for (i = 0; i < f->numchars; i++)
1233 if (f->glyph[i].shape)
1235 swf_ShapeFree(f->glyph[i].shape);
1236 f->glyph[i].shape = NULL;
1243 rfx_free(f->ascii2glyph);
1244 f->ascii2glyph = NULL;
1248 rfx_free(f->glyph2ascii);
1249 f->glyph2ascii = NULL;
1253 font_freeglyphnames(f);
1259 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1265 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1266 | (y ? TF_HASYOFFSET : 0);
1268 swf_SetU8(t, flags);
1270 swf_SetU16(t, font->id);
1272 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1273 swf_SetRGBA(t, color);
1275 swf_SetRGB(t, color);
1278 if(x != SET_TO_ZERO) {
1279 if(x>32767 || x<-32768)
1280 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1287 if(y != SET_TO_ZERO) {
1288 if(y>32767 || y<-32768)
1289 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1296 swf_SetU16(t, size);
1301 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1305 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1309 if (!strcmp(encoding, "UTF8"))
1311 else if (!strcmp(encoding, "iso-8859-1"))
1314 fprintf(stderr, "Unknown encoding: %s", encoding);
1322 c = readUTF8char(&s);
1324 if (c < font->maxascii)
1325 glyph = font->ascii2glyph[c];
1327 g = swf_CountUBits(glyph, g);
1328 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1339 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1344 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1347 if (!strcmp(encoding, "UTF8"))
1349 else if (!strcmp(encoding, "iso-8859-1"))
1352 fprintf(stderr, "Unknown encoding: %s", encoding);
1355 swf_SetU8(t, l); //placeholder
1363 c = readUTF8char(&s);
1365 if (c < font->maxascii)
1366 g = font->ascii2glyph[c];
1368 swf_SetBits(t, g, gbits);
1369 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1371 /* We split into 127 characters per text field.
1372 We could do 255, by the (formerly wrong) flash specification,
1373 but some SWF parsing code out there still assumes that char blocks
1374 are at max 127 characters, and it would save only a few bits.
1381 PUT8(&t->data[pos], l);
1383 swf_ResetWriteBits(t);
1387 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1389 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1392 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1394 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1397 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1399 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1402 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1404 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1407 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1414 if (*s < font->maxascii)
1415 g = font->ascii2glyph[*s];
1417 res += font->glyph[g].advance / 20;
1421 res = (res * scale) / 100;
1426 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1433 int c = readUTF8char(&s);
1434 if(c==13 || c==10) {
1439 ypos+=font->layout->leading;
1442 if (c < font->maxascii) {
1443 int g = font->ascii2glyph[c];
1445 SRECT rn = font->layout->bounds[g];
1446 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1447 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1448 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1449 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1450 swf_ExpandRect2(&r, &rn);
1451 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1459 SWFFONT *swf_ReadFont(const char *filename)
1465 f = open(filename, O_RDONLY|O_BINARY);
1467 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1468 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1474 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1481 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)
1483 swf_SetRect(tag, &r);
1484 swf_ResetWriteBits(tag);
1486 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1488 flags |= ET_HASTEXT;
1490 flags |= ET_HASTEXTCOLOR;
1492 flags |= ET_HASMAXLENGTH;
1494 flags |= ET_HASFONT;
1496 flags |= ET_HASLAYOUT;
1498 swf_SetBits(tag, flags, 16);
1500 if (flags & ET_HASFONT) {
1501 swf_SetU16(tag, font); //font
1502 swf_SetU16(tag, height); //fontheight
1504 if (flags & ET_HASTEXTCOLOR) {
1505 swf_SetRGBA(tag, color);
1507 if (flags & ET_HASMAXLENGTH) {
1508 swf_SetU16(tag, maxlength); //maxlength
1510 if (flags & ET_HASLAYOUT) {
1511 swf_SetU8(tag, layout->align); //align
1512 swf_SetU16(tag, layout->leftmargin); //left margin
1513 swf_SetU16(tag, layout->rightmargin); //right margin
1514 swf_SetU16(tag, layout->indent); //indent
1515 swf_SetU16(tag, layout->leading); //leading
1517 swf_SetString(tag, variable);
1518 if (flags & ET_HASTEXT)
1519 swf_SetString(tag, text);
1522 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1526 U8 *utext = (U8 *) strdup(text);
1532 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1533 ystep = font->layout->leading;
1535 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1536 /* Hm, without layout information, we can't compute a bounding
1537 box. We could call swf_FontCreateLayout to create a layout,
1538 but the caller probably doesn't want us to mess up his font
1541 r.xmin = r.ymin = 0;
1542 r.xmax = r.ymax = 1024 * 20;
1546 swf_SetRect(tag, &r);
1548 /* The text matrix is pretty boring, as it doesn't apply to
1549 individual characters, but rather whole text objects (or
1550 at least whole char records- haven't tested).
1551 So it can't do anything which we can't already do with
1552 the placeobject tag we use for placing the text on the scene.
1554 swf_SetMatrix(tag, 0);
1556 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1557 swf_SetU8(tag, gbits);
1558 swf_SetU8(tag, abits);
1564 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1567 while(*next && *next!=13 && *next!=10 && count<127) {
1568 readUTF8char(&next);
1571 if(next[0] == 13 || next[0] == 10) {
1576 if(next[0] == 13 && next[1] == 10)
1579 if(next[0] == 13 || next[0] == 10) {
1584 /* now set the text params- notice that a font size of
1585 1024 (or 1024*20 for definefont3) means that the glyphs will
1586 be displayed exactly as they would be in/with a defineshape.
1587 This is not documented in the specs.
1590 /* set the actual text- notice that we just pass our scale
1591 parameter over, as TextSetCharRecord calculates with
1593 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1603 void swf_FontCreateLayout(SWFFONT * f)
1612 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1613 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1614 f->layout->ascent = 0;
1615 f->layout->descent = 0;
1617 for (t = 0; t < f->numchars; t++) {
1621 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1623 fprintf(stderr, "Shape parse error\n");
1626 bbox = swf_GetShapeBoundingBox(shape2);
1627 swf_Shape2Free(shape2);
1628 f->layout->bounds[t] = bbox;
1630 width = (bbox.xmax);
1632 /* The following is a heuristic- it may be that extractfont_DefineText
1633 has already found out some widths for individual characters (from the way
1634 they are used)- we now have to guess whether that width might be possible,
1635 which is the case if it isn't either much too big or much too small */
1636 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1637 f->glyph[t].advance = width;
1639 if (-bbox.ymin > f->layout->ascent)
1640 f->layout->ascent = -bbox.ymin;
1641 if (bbox.ymax > f->layout->descent)
1642 f->layout->descent = bbox.ymax;
1646 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1648 U8 *s = (U8 *) text;
1654 U32 c = readUTF8char(&s);
1655 int g = font->ascii2glyph[c];
1656 shape = font->glyph[g].shape;
1657 if (((int) g) < 0) {
1658 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1661 shape2 = swf_ShapeToShape2(shape);
1664 if (l->type == moveTo) {
1666 to.x = l->x * size / 100.0 / 20.0 + advance;
1667 to.y = l->y * size / 100.0 / 20.0;
1668 draw->moveTo(draw, &to);
1669 } else if (l->type == lineTo) {
1671 to.x = l->x * size / 100.0 / 20.0 + advance;
1672 to.y = l->y * size / 100.0 / 20.0;
1673 draw->lineTo(draw, &to);
1674 } else if (l->type == splineTo) {
1676 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1677 mid.y = l->sy * size / 100.0 / 20.0;
1678 to.x = l->x * size / 100.0 / 20.0 + advance;
1679 to.y = l->y * size / 100.0 / 20.0;
1680 draw->splineTo(draw, &mid, &to);
1684 swf_Shape2Free(shape2);
1685 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1689 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1692 swf_FontCreateLayout(font);
1695 memset(&swf, 0, sizeof(SWF));
1696 swf.fileVersion = 9;
1697 swf.frameRate = 0x4000;
1698 swf.movieSize.xmax = 200;
1699 swf.movieSize.ymax = 200;
1701 if(!font->id) font->id=1;
1704 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1705 swf_FontSetDefine2(tag, font);
1707 char*name = font->name?(char*)font->name:"font";
1709 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1710 swf_SetU16(tag, font->id);
1711 swf_SetString(tag, name);
1712 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1714 swf_SetU16(tag, font->id);
1715 swf_SetString(tag, name);
1716 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1718 tag = swf_InsertTag(tag, ST_END);
1719 swf_SaveSWF(&swf, filename);
1723 void swf_WriteFont(SWFFONT * font, char *filename)
1726 swf_FontCreateLayout(font);
1735 memset(&swf, 0, sizeof(SWF));
1736 swf.fileVersion = 8;
1737 swf.frameRate = 0x4000;
1738 swf.movieSize.xmax = 1024*20;
1739 swf.movieSize.ymax = 768*20;
1742 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1743 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1745 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1746 swf_FontSetDefine2(tag, font);
1748 if(font->glyphnames) {
1750 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1751 swf_SetU16(tag, font->id);
1752 swf_SetU16(tag, font->numchars);
1753 for (c = 0; c < font->numchars; c++) {
1754 if (font->glyphnames[c])
1755 swf_SetString(tag, font->glyphnames[c]);
1757 swf_SetString(tag, "");
1763 RGBA white = {255,255,255,255};
1764 RGBA black = {255,0,0,0};
1765 RGBA gray50 = {255,128,128,128};
1766 RGBA green = {255,0,255,0};
1768 SCOORD miny = SCOORD_MAX;
1769 SCOORD maxy = SCOORD_MIN;
1771 U16 max_advance = 0;
1772 char*flags = rfx_calloc(font->numchars);
1773 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1774 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1775 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1776 for(t=0;t<font->numchars;t++) {
1777 SHAPE*s = font->glyph[t].shape;
1778 SHAPE2*s2 = swf_ShapeToShape2(s);
1779 SRECT r = swf_GetShapeBoundingBox(s2);
1781 // inside a definefont3, everything is 20x the resolution:
1782 double rx1 = r.xmin / 20.0;
1783 double ry1 = r.ymin / 20.0;
1784 double rx2 = r.xmax / 20.0;
1785 double ry2 = r.ymax / 20.0;
1790 if(ry1<miny) {miny=ry1;}
1791 if(ry2>maxy) {maxy=ry2;}
1792 swf_Shape2Free(s2);free(s2);
1793 width += font->glyph[t].advance;
1794 if(font->glyph[t].advance>max_advance)
1795 max_advance = font->glyph[t].advance;
1798 if(miny==SCOORD_MAX) miny=maxy=0;
1799 if(miny==maxy) maxy=miny+1;
1801 /* scale the font so that it's 256 pixels high */
1802 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1803 double overlarge_factor;
1807 overlarge_factor = scale / 32767.0;
1810 overlarge_factor = 1.0;
1814 int spriteid = id++;
1817 r.ymin = miny*fontsize/1024;
1818 r.xmax = width*fontsize/20480;
1819 r.ymax = maxy*fontsize/1024;
1820 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1821 swf_SetU16(tag, textid);
1822 swf_SetRect(tag, &r);
1823 swf_SetMatrix(tag, NULL);
1826 U8 gbits = swf_CountBits(font->numchars, 0);
1827 swf_SetU8(tag, gbits);
1828 swf_SetU8(tag, abits);
1830 RGBA rgb = {255,0,0,0};
1832 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1833 ActionTAG*array = 0;
1835 array = action_PushString(array, "xpos");
1836 for(t=0;t<font->numchars;t++) {
1838 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1839 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1840 x += width * overlarge_factor;
1841 swf_SetBits(tag, t, gbits);
1842 swf_SetBits(tag, width, abits);
1843 swf_SetU8(tag, 128);
1845 array = action_PushInt(array, x/20);
1846 array = action_PushInt(array, font->numchars+1);
1847 array = action_InitArray(array);
1848 array = action_SetVariable(array);
1852 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1855 int ls = swf_ShapeAddLineStyle(s,20,&white);
1857 swf_SetU16(tag,shapeid);
1863 swf_SetRect(tag,&r);
1864 swf_SetShapeHeader(tag,s);
1865 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1867 /* Ç and  are good chars to test ascent/descent extend */
1868 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1869 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1871 swf_ShapeSetMove(tag,s,0,y1);
1872 swf_ShapeSetLine(tag,s,width,0);
1873 swf_ShapeSetMove(tag,s,0,y2);
1874 swf_ShapeSetLine(tag,s,width,0);
1876 swf_ShapeSetEnd(tag);
1878 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1879 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1884 for(t=0;t<font->numchars;t++) {
1885 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1888 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1889 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1890 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1892 swf_SetU16(tag,shapeid);
1898 swf_SetRect(tag,&r);
1899 swf_SetShapeHeader(tag,s);
1900 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1901 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1902 SHAPELINE*l = s2->lines;
1903 int lastx=0,lasty=0;
1905 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1906 double y1 = -miny*20*scale*2/20480.0;
1907 double scalex = scale*2/20480.0;
1908 double scaley = scale*2/20480.0;
1911 int lx = (l->x)*scalex+x1;
1912 int ly = (l->y)*scaley+y1;
1913 int sx = (l->sx)*scalex+x1;
1914 int sy = (l->sy)*scaley+y1;
1915 if(l->type == moveTo) {
1916 swf_ShapeSetMove(tag,s,lx,ly);
1917 } else if(l->type == lineTo) {
1918 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1919 } else if(l->type == splineTo) {
1920 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1927 if(font->alignzones) {
1928 ALIGNZONE*zone = &font->alignzones[t];
1929 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1930 if((zone->x&zone->dx)!=0xffff) {
1931 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1932 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1933 swf_ShapeSetMove(tag,s,x,0);
1934 swf_ShapeSetLine(tag,s,0,1024*20);
1935 swf_ShapeSetMove(tag,s,dx,0);
1936 swf_ShapeSetLine(tag,s,0,1024*20);
1938 if((zone->y&zone->dy)!=0xffff) {
1939 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
1940 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
1941 swf_ShapeSetMove(tag,s,0,y);
1942 swf_ShapeSetLine(tag,s,1024*20,0);
1943 swf_ShapeSetMove(tag,s,0,dy);
1944 swf_ShapeSetLine(tag,s,1024*20,0);
1948 swf_ShapeSetEnd(tag);
1951 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1953 swf_SetU16(tag, spriteid);
1955 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1956 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1957 tag = swf_InsertTag(tag, ST_END);
1958 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1960 swf_GetMatrix(0, &m);
1963 sprintf(txt, "char%d", font->numchars-t);
1964 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
1968 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1970 RGBA blue = {0xff,0xc0,0xc0,0xff};
1971 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
1972 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1974 swf_SetU16(tag, spriteid2);
1976 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1977 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1978 tag = swf_InsertTag(tag, ST_END);
1979 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1980 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
1983 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1984 swf_SetU16(tag, spriteid);
1986 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1988 swf_GetMatrix(0, &m);
1989 m.sx = 65536 * overlarge_factor;
1990 m.sy = 65536 * overlarge_factor;
1992 m.ty = -miny*256*20/(maxy-miny);
1993 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
1994 tag = swf_InsertTag(tag, ST_END);
1995 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1996 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
1999 RGBA blue2 = {0x80,0x80,0xff,0x80};
2000 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2002 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2003 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2005 swf_SetU16(tag, spriteid3);
2007 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2008 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2009 tag = swf_InsertTag(tag, ST_END);
2010 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2011 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2015 " var mouseListener = new Object();"
2018 " var currentMouseOver, currentChar;"
2019 " mouseListener.onMouseDown = function() { "
2020 " eval(\"_root.char\"+currentChar)._y = 20000;"
2021 " currentChar = currentMouseOver;"
2022 " var i = currentMouseOver;"
2023 " eval(\"_root.char\"+i)._y = 256;"
2024 " _root.marker2._yscale=256*100;"
2025 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2026 " _root.marker2._x=xpos[i]+myx;"
2028 " mouseListener.onMouseMove = function() { "
2029 " if(_ymouse<256) {"
2030 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2035 " setInterval( function(){ "
2036 " if(_ymouse<256) {"
2037 " var i, x=_xmouse-_root.textbar._x;"
2038 " for(i=xpos.length-1;i>0;i--) {"
2039 " if(x<xpos[i-1]) break;"
2041 " currentMouseOver = i;"
2042 " _root.marker._yscale=256*100;"
2043 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2044 " _root.marker._x=xpos[i]+myx;"
2045 " _root.textbar._x += 0.05;"
2047 " if(myx+speed>0) {"
2049 " } else if(myx+speed<-xpos[0]+1024) {"
2053 " _root.textbar._x = myx;"
2054 " _root.marker._x += speed;"
2055 " _root.marker2._x += speed;"
2057 " Mouse.addListener(mouseListener);"
2059 ActionTAG* atag = swf_ActionCompile(data, 6);
2061 tag = swf_InsertTag(tag, ST_DOACTION);
2062 swf_ActionSet(tag, array);
2063 swf_ActionSet(tag, atag);
2065 swf_ActionFree(atag);
2067 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2074 tag = swf_InsertTag(tag, ST_END);
2076 swf.compressed = -1;
2077 swf_SaveSWF(&swf, filename);