5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9 Copyright (c) 2003,2004,2005,2006,2007,2008,2009 Matthias Kramm
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../rfxswf.h"
27 U32 readUTF8char(U8 ** text)
30 if (!(*(*text) & 0x80))
33 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
34 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
35 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
39 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
40 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
41 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
45 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
46 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
48 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
52 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
53 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
56 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
60 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
61 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
63 && (*text)[4] && (*text)[5]) {
64 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
65 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
72 #define TF_TEXTCONTROL 0x80
73 #define TF_HASFONT 0x08
74 #define TF_HASCOLOR 0x04
75 #define TF_HASYOFFSET 0x02
76 #define TF_HASXOFFSET 0x01
78 #define FF_WIDECODES 0x01
80 #define FF_ITALIC 0x04
82 #define FF_SHIFTJIS 0x10
83 #define FF_UNICODE 0x20
86 #define FF2_ITALIC 0x02
87 #define FF2_WIDECODES 0x04
88 #define FF2_WIDEOFFSETS 0x08
90 #define FF2_UNICODE 0x20
91 #define FF2_SHIFTJIS 0x40
92 #define FF2_LAYOUT 0x80
94 int swf_FontIsItalic(SWFFONT * f)
96 return f->style & FONT_STYLE_ITALIC;
99 int swf_FontIsBold(SWFFONT * f)
101 return f->style & FONT_STYLE_BOLD;
104 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
106 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
116 if (swf_isFontTag(t)) {
126 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
129 swf_GetBlock(t, s, l);
133 (FontCallback) (self, id, s);
141 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
147 if ((!id) || (id == fid)) {
158 f->glyph = (SWFGLYPH*)rfx_calloc(sizeof(SWFGLYPH) * n);
160 for (i = 1; i < n; i++)
162 for (i = 0; i < n; i++)
163 swf_GetSimpleShape(t, &f->glyph[i].shape);
168 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
180 if (f->version > 1) {
181 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
182 too. However, they only add little information to what's already
183 inside the DefineFont2 tag */
190 f->name = (U8 *) rfx_alloc(l + 1);
191 swf_GetBlock(t, f->name, l);
194 flags = swf_GetU8(t);
196 f->style |= FONT_STYLE_BOLD;
198 f->style |= FONT_STYLE_ITALIC;
200 f->encoding |= FONT_ENCODING_ANSI;
202 f->encoding |= FONT_ENCODING_SHIFTJIS;
204 f->encoding |= FONT_ENCODING_UNICODE;
206 if (t->id == ST_DEFINEFONTINFO2) {
207 f->language = swf_GetU8(t);
210 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
212 for (i = 0; i < f->numchars; i++) {
213 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
214 if (f->glyph2ascii[i] > maxcode)
215 maxcode = f->glyph2ascii[i];
220 f->maxascii = maxcode;
221 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
222 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
224 for (i = 0; i < f->numchars; i++)
225 f->ascii2glyph[f->glyph2ascii[i]] = i;
230 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
233 swf_SetTagPos(tag, 0);
235 fid = swf_GetU16(tag);
238 int num = swf_GetU16(tag);
240 f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num);
241 for (t = 0; t < num; t++) {
242 f->glyphnames[t] = strdup(swf_GetString(tag));
249 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
256 U8 flags1, langcode, namelen;
257 swf_SetTagPos(tag, 0);
258 font->version = tag->id==ST_DEFINEFONT3?3:2;
259 fid = swf_GetU16(tag);
263 flags1 = swf_GetU8(tag);
264 langcode = swf_GetU8(tag); //reserved flags
267 font->style |= FONT_STYLE_BOLD;
269 font->style |= FONT_STYLE_ITALIC;
271 font->encoding |= FONT_ENCODING_ANSI;
273 font->encoding |= FONT_ENCODING_UNICODE;
275 font->encoding |= FONT_ENCODING_SHIFTJIS;
277 namelen = swf_GetU8(tag);
278 font->name = (U8 *) rfx_alloc(namelen + 1);
279 font->name[namelen] = 0;
280 swf_GetBlock(tag, font->name, namelen);
281 glyphcount = swf_GetU16(tag);
282 font->numchars = glyphcount;
284 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
285 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
287 offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
288 offset_start = tag->pos;
290 if (flags1 & 8) { // wide offsets
291 for (t = 0; t < glyphcount; t++)
292 offset[t] = swf_GetU32(tag); //offset[t]
294 if (glyphcount) /* this _if_ is not in the specs */
295 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
297 offset[glyphcount] = tag->pos;
299 for (t = 0; t < glyphcount; t++)
300 offset[t] = swf_GetU16(tag); //offset[t]
302 if (glyphcount) /* this _if_ is not in the specs */
303 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
305 offset[glyphcount] = tag->pos;
307 for (t = 0; t < glyphcount; t++) {
308 swf_SetTagPos(tag, offset[t]+offset_start);
309 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
313 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
318 for (t = 0; t < glyphcount; t++) {
320 if (flags1 & 4) // wide codes (always on for definefont3)
321 code = swf_GetU16(tag);
323 code = swf_GetU8(tag);
324 font->glyph2ascii[t] = code;
331 font->maxascii = maxcode;
332 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
333 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
334 for (t = 0; t < glyphcount; t++) {
335 font->ascii2glyph[font->glyph2ascii[t]] = t;
338 if (flags1 & 128) { // has layout
340 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
341 font->layout->ascent = swf_GetU16(tag);
342 font->layout->descent = swf_GetU16(tag);
343 font->layout->leading = swf_GetU16(tag);
344 for (t = 0; t < glyphcount; t++) {
345 S16 advance = swf_GetS16(tag);
346 font->glyph[t].advance = advance;
348 font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
349 for (t = 0; t < glyphcount; t++) {
350 swf_ResetReadBits(tag);
351 swf_GetRect(tag, &font->layout->bounds[t]);
352 SRECT b = font->layout->bounds[t];
353 if((b.xmin|b.xmax|b.ymin|b.ymax) == 0) {
354 // recalculate bounding box
355 SHAPE2 *shape2 = swf_ShapeToShape2(font->glyph[t].shape);
356 font->layout->bounds[t] = swf_GetShapeBoundingBox(shape2);
357 swf_Shape2Free(shape2);free(shape2);
361 kerningcount = swf_GetU16(tag);
362 font->layout->kerningcount = kerningcount;
364 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
366 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
367 for (t = 0; t < kerningcount; t++) {
368 if (flags1 & 4) { // wide codes
369 font->layout->kerning[t].char1 = swf_GetU16(tag);
370 font->layout->kerning[t].char2 = swf_GetU16(tag);
372 font->layout->kerning[t].char1 = swf_GetU8(tag);
373 font->layout->kerning[t].char2 = swf_GetU8(tag);
375 font->layout->kerning[t].adjustment = swf_GetS16(tag);
382 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
385 swf_SetTagPos(tag, 0);
386 fid = swf_GetU16(tag);
389 font->alignzone_flags = swf_GetU8(tag);
390 font->alignzones = rfx_calloc(sizeof(ALIGNZONE)*font->numchars);
392 while(tag->pos < tag->len) {
393 if(i>=font->numchars)
395 int nr = swf_GetU8(tag); // should be 2
397 fprintf(stderr, "rfxswf: Can't parse alignzone tags with %d zones", nr);
400 U16 x = swf_GetU16(tag);
401 U16 y = swf_GetU16(tag);
402 U16 dx = (nr==2)?swf_GetU16(tag):0xffff;
403 U16 dy = (nr==2)?swf_GetU16(tag):0xffff;
404 U8 xy = swf_GetU8(tag);
407 if((!(xy&1) && (x!=0 || (dx!=0 && dx!=0xffff))) ||
408 (!(xy&2) && (y!=0 || (dy!=0 && dy!=0xffff)))) {
409 fprintf(stderr, "Warning: weird combination of alignzone bits and values (%d x:%04x-%04x y:%04x-%04x)\n", xy,
420 font->alignzones[i].x = x;
421 font->alignzones[i].y = y;
422 font->alignzones[i].dx = dx;
423 font->alignzones[i].dy = dy;
431 #define FEDTJ_PRINT 0x01
432 #define FEDTJ_MODIFY 0x02
433 #define FEDTJ_CALLBACK 0x04
436 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
437 void (*callback) (void *self,
438 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
449 memset(&color, 0, sizeof(color));
455 swf_GetMatrix(t, &m);
456 gbits = swf_GetU8(t);
457 abits = swf_GetU8(t);
461 flags = swf_GetU8(t);
465 if (flags & TF_TEXTCONTROL) {
466 if (flags & TF_HASFONT)
468 if (flags & TF_HASCOLOR) {
469 color.r = swf_GetU8(t); // rgb
470 color.g = swf_GetU8(t);
471 color.b = swf_GetU8(t);
472 if (swf_GetTagID(t) == ST_DEFINETEXT2)
473 color.a = swf_GetU8(t);
477 if (flags & TF_HASXOFFSET)
479 if (flags & TF_HASYOFFSET)
481 if (flags & TF_HASFONT)
482 fontsize = swf_GetU16(t);
494 for (i = 0; i < num; i++) {
498 glyph = swf_GetBits(t, gbits);
499 adv = swf_GetBits(t, abits);
503 if (jobs & FEDTJ_PRINT) {
504 int code = f->glyph2ascii[glyph];
507 if (jobs & FEDTJ_MODIFY)
508 f->glyph[glyph].advance = adv * 20; //?
513 if ((id == fid) && (jobs & FEDTJ_PRINT))
515 if (jobs & FEDTJ_CALLBACK)
516 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
524 int swf_ParseDefineText(TAG * tag,
525 void (*callback) (void *self, int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
527 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
530 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
532 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
535 typedef struct _usagetmp {
540 static void updateusage(void *self, int *chars, int *xpos, int nr,
541 int fontid, int fontsize, int xstart, int ystart, RGBA * color)
543 usagetmp_t*u = (usagetmp_t*)self;
545 swf_FontInitUsage(u->font);
547 if(fontid!=u->font->id)
555 if(c<0 || c>u->font->numchars)
557 swf_FontUseGlyph(u->font, c, fontsize);
558 if(u->lasty == y && x>=u->lastx-200 && abs(u->lastx-x)<200 &&
559 u->last!=c && !swf_ShapeIsEmpty(u->font->glyph[u->last].shape) &&
560 !swf_ShapeIsEmpty(u->font->glyph[c].shape))
562 swf_FontUsePair(u->font, u->last, c);
565 /* FIXME: do we still need to divide advance by 20 for definefont3? */
566 u->lastx = x + (u->font->glyph[c].advance*fontsize/20480);
571 void swf_FontUpdateUsage(SWFFONT*f, TAG* tag)
575 u.lastx = -0x80000000;
576 u.lasty = -0x80000000;
578 swf_ParseDefineText(tag, updateusage, &u);
581 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
586 if ((!swf) || (!font))
589 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
595 switch (swf_GetTagID(t)) {
597 nid = swf_FontExtract_DefineFont(id, f, t);
602 nid = swf_FontExtract_DefineFont2(id, f, t);
605 case ST_DEFINEFONTALIGNZONES:
606 nid = swf_FontExtract_DefineFontAlignZones(id, f, t);
609 case ST_DEFINEFONTINFO:
610 case ST_DEFINEFONTINFO2:
611 nid = swf_FontExtract_DefineFontInfo(id, f, t);
617 nid = swf_FontExtract_DefineText(id, f, t, FEDTJ_MODIFY);
619 if(f->version>=3 && f->layout)
620 swf_FontUpdateUsage(f, t);
624 nid = swf_FontExtract_GlyphNames(id, f, t);
639 int swf_FontSetID(SWFFONT * f, U16 id)
647 void swf_LayoutFree(SWFLAYOUT * l)
651 rfx_free(l->kerning);
661 static void font_freeglyphnames(SWFFONT*f)
666 for (t = 0; t < f->numchars; t++)
668 if (f->glyphnames[t])
670 rfx_free(f->glyphnames[t]);
671 f->glyphnames[t] = 0;
674 rfx_free(f->glyphnames);
678 static void font_freeusage(SWFFONT*f)
682 rfx_free(f->use->chars);f->use->chars = 0;
684 if(f->use->neighbors) {
685 rfx_free(f->use->neighbors);f->use->neighbors = 0;
687 if(f->use->neighbors_hash) {
688 rfx_free(f->use->neighbors_hash);f->use->neighbors_hash = 0;
690 rfx_free(f->use); f->use = 0;
693 static void font_freelayout(SWFFONT*f)
696 swf_LayoutFree(f->layout);
700 static void font_freename(SWFFONT*f)
708 int swf_FontReduce_old(SWFFONT * f)
712 if ((!f) || (!f->use) || f->use->is_reduced)
717 for (i = 0; i < f->numchars; i++) {
718 if (f->glyph[i].shape && f->use->chars[i]) {
719 f->glyph2ascii[j] = f->glyph2ascii[i];
720 f->glyph[j] = f->glyph[i];
721 f->use->chars[i] = j;
724 f->glyph2ascii[i] = 0;
725 if(f->glyph[i].shape) {
726 swf_ShapeFree(f->glyph[i].shape);
727 f->glyph[i].shape = 0;
728 f->glyph[i].advance = 0;
730 f->use->chars[i] = -1;
734 for (i = 0; i < f->maxascii; i++) {
735 if(f->use->chars[f->ascii2glyph[i]]<0) {
736 f->ascii2glyph[i] = -1;
738 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
742 f->maxascii = max_unicode;
743 f->use->is_reduced = 1;
746 font_freeglyphnames(f);
751 int swf_FontReduce_swfc(SWFFONT * f)
755 if ((!f) || (!f->use) || f->use->is_reduced)
758 font_freeglyphnames(f);
761 for (i = 0; i < f->numchars; i++) {
762 if (f->glyph[i].shape && f->use->chars[i]) {
763 f->glyph2ascii[j] = f->glyph2ascii[i];
765 f->layout->bounds[j] = f->layout->bounds[i];
766 f->glyph[j] = f->glyph[i];
767 f->use->chars[i] = j;
770 f->glyph2ascii[i] = 0;
771 if(f->glyph[i].shape) {
772 swf_ShapeFree(f->glyph[i].shape);
773 f->glyph[i].shape = 0;
774 f->glyph[i].advance = 0;
776 f->use->chars[i] = -1;
779 f->use->used_glyphs = j;
780 for (i = 0; i < f->maxascii; i++) {
781 if(f->ascii2glyph[i] > -1) {
782 if (f->use->chars[f->ascii2glyph[i]]<0) {
783 f->use->chars[f->ascii2glyph[i]] = 0;
784 f->ascii2glyph[i] = -1;
786 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
787 f->use->chars[f->ascii2glyph[i]] = 1;
792 f->maxascii = max_unicode;
793 f->use->is_reduced = 1;
799 int swf_FontReduce(SWFFONT * f)
804 if ((!f) || (!f->use) || f->use->is_reduced)
808 font_freeglyphnames(f);
810 f->use->used_glyphs= 0;
811 for (i = 0; i < f->numchars; i++) {
812 if(!f->use->chars[i]) {
814 f->glyph2ascii[i] = 0;
816 if(f->glyph[i].shape) {
817 swf_ShapeFree(f->glyph[i].shape);
818 f->glyph[i].shape = 0;
819 f->glyph[i].advance = 0;
821 // f->use->used_glyphs++;
823 f->use->used_glyphs++;
827 for (i = 0; i < f->maxascii; i++) {
828 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
830 f->ascii2glyph[i] = -1;
836 f->maxascii = max_unicode;
837 f->numchars = max_glyph;
842 static SWFFONT* font_to_sort;
843 int cmp_chars(const void*a, const void*b)
845 int x = *(const int*)a;
846 int y = *(const int*)b;
850 void swf_FontSort(SWFFONT * font)
858 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
860 for (i = 0; i < font->numchars; i++) {
863 //qsort(newplace, sizeof(newplace[0]), font->numchars, cmp_chars);
865 for (i = 0; i < font->numchars; i++)
866 for (j = 0; j < i; j++) {
867 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
876 n1 = font->glyph2ascii[i];
877 n2 = font->glyph2ascii[j];
878 font->glyph2ascii[j] = n1;
879 font->glyph2ascii[i] = n2;
884 if (font->glyphnames) {
885 c1 = font->glyphnames[i];
886 c2 = font->glyphnames[j];
887 font->glyphnames[j] = c1;
888 font->glyphnames[i] = c2;
891 r1 = font->layout->bounds[i];
892 r2 = font->layout->bounds[j];
893 font->layout->bounds[j] = r1;
894 font->layout->bounds[i] = r2;
898 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
899 for (i = 0; i < font->numchars; i++) {
900 newpos[newplace[i]] = i;
902 for (i = 0; i < font->maxascii; i++) {
903 if (font->ascii2glyph[i] >= 0)
904 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
908 font->glyph2glyph = newpos;
911 void swf_FontPrepareForEditText(SWFFONT * font)
914 swf_FontCreateLayout(font);
918 int swf_FontInitUsage(SWFFONT * f)
923 fprintf(stderr, "Usage initialized twice");
926 f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE));
927 f->use->smallest_size = 0xffff;
928 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
932 void swf_FontClearUsage(SWFFONT * f)
936 rfx_free(f->use->chars); f->use->chars = 0;
937 rfx_free(f->use); f->use = 0;
940 int swf_FontUse(SWFFONT * f, U8 * s)
945 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
946 swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
952 int swf_FontUseUTF8(SWFFONT * f, const U8 * s, U16 size)
959 ascii = readUTF8char((U8**)&s);
960 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
961 swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
966 int swf_FontUseAll(SWFFONT* f)
971 swf_FontInitUsage(f);
972 for (i = 0; i < f->numchars; i++)
973 f->use->chars[i] = 1;
974 f->use->used_glyphs = f->numchars;
978 static unsigned hash2(int char1, int char2)
980 unsigned hash = char1^(char2<<8);
982 hash ^= (hash >> 11);
983 hash += (hash << 15);
986 static void hashadd(FONTUSAGE*u, int char1, int char2, int nr)
988 unsigned hash = hash2(char1, char2);
990 hash = hash%u->neighbors_hash_size;
991 if(!u->neighbors_hash[hash]) {
992 u->neighbors_hash[hash] = nr+1;
998 int swf_FontUseGetPair(SWFFONT * f, int char1, int char2)
1000 FONTUSAGE*u = f->use;
1001 if(!u || !u->neighbors_hash_size)
1003 unsigned hash = hash2(char1, char2);
1005 hash = hash%u->neighbors_hash_size;
1006 int pos = u->neighbors_hash[hash];
1010 u->neighbors[pos-1].char1 == char1 &&
1011 u->neighbors[pos-1].char2 == char2) {
1018 void swf_FontUsePair(SWFFONT * f, int char1, int char2)
1021 swf_FontInitUsage(f);
1022 FONTUSAGE*u = f->use;
1024 if(u->num_neighbors*3 >= u->neighbors_hash_size*2) {
1025 if(u->neighbors_hash) {
1026 free(u->neighbors_hash);
1028 u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024;
1029 u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int));
1031 for(t=0;t<u->num_neighbors;t++) {
1032 hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t);
1036 int nr = swf_FontUseGetPair(f, char1, char2);
1038 if(u->num_neighbors == u->neighbors_size) {
1039 u->neighbors_size += 4096;
1040 u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
1042 u->neighbors[u->num_neighbors].char1 = char1;
1043 u->neighbors[u->num_neighbors].char2 = char2;
1044 u->neighbors[u->num_neighbors].num = 1;
1045 hashadd(u, char1, char2, u->num_neighbors);
1048 u->neighbors[nr-1].num++;
1052 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
1055 swf_FontInitUsage(f);
1056 if(glyph < 0 || glyph >= f->numchars)
1058 if(!f->use->chars[glyph])
1059 f->use->used_glyphs++;
1060 f->use->chars[glyph] = 1;
1061 if(size && size < f->use->smallest_size)
1062 f->use->smallest_size = size;
1066 int swf_FontSetDefine(TAG * t, SWFFONT * f)
1068 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
1073 swf_ResetWriteBits(t);
1074 swf_SetU16(t, f->id);
1078 for (i = 0; i < f->numchars; i++)
1079 if (f->glyph[i].shape) {
1081 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
1084 for (i = 0; i < j; i++)
1085 swf_SetU16(t, ofs[i] + j * 2);
1087 fprintf(stderr, "rfxswf: warning: Font is empty\n");
1091 for (i = 0; i < f->numchars; i++)
1092 if (f->glyph[i].shape)
1093 swf_SetSimpleShape(t, f->glyph[i].shape);
1095 swf_ResetWriteBits(t);
1100 static inline int fontSize(SWFFONT * font)
1104 for (t = 0; t < font->numchars; t++) {
1106 if(font->glyph[t].shape)
1107 l = (font->glyph[t].shape->bitlen + 7) / 8;
1112 return size + (font->numchars + 1) * 2;
1115 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
1120 swf_SetU16(tag, f->id);
1122 if (f->layout) flags |= 128; // haslayout
1123 if (f->numchars > 256)
1124 flags |= 4; // widecodes
1125 if (f->style & FONT_STYLE_BOLD)
1127 if (f->style & FONT_STYLE_ITALIC)
1128 flags |= 2; // italic
1129 if (f->maxascii >= 256)
1130 flags |= 4; //wide codecs
1131 if (fontSize(f) > 65535)
1132 flags |= 8; //wide offsets
1133 flags |= 8 | 4; //FIXME: the above check doesn't work
1135 if (f->encoding & FONT_ENCODING_ANSI)
1136 flags |= 16; // ansi
1137 if (f->encoding & FONT_ENCODING_UNICODE)
1138 flags |= 32; // unicode
1139 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1140 flags |= 64; // shiftjis
1142 swf_SetU8(tag, flags);
1143 swf_SetU8(tag, 0); //reserved flags
1146 swf_SetU8(tag, strlen((const char*)f->name)+1);
1147 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1149 /* font name (="") */
1153 /* number of glyphs */
1154 swf_SetU16(tag, f->numchars);
1155 /* font offset table */
1157 for (t = 0; t <= f->numchars; t++) {
1159 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1161 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1164 for (t = 0; t <= f->numchars; t++) {
1166 tag->data[pos + t * 4] = (tag->len - pos);
1167 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1168 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1169 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1171 if (tag->len - pos > 65535) {
1172 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1175 tag->data[pos + t * 2] = (tag->len - pos);
1176 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1178 if (t < f->numchars) {
1179 if(f->glyph[t].shape) {
1180 swf_SetSimpleShape(tag, f->glyph[t].shape);
1182 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1188 /* font code table */
1189 for (t = 0; t < f->numchars; t++) {
1190 if (flags & 4) { /* wide codes */
1191 if(f->glyph2ascii[t]) {
1192 swf_SetU16(tag, f->glyph2ascii[t]);
1197 if(f->glyph2ascii[t]) {
1198 swf_SetU8(tag, f->glyph2ascii[t]);
1206 swf_SetU16(tag, f->layout->ascent);
1207 swf_SetU16(tag, f->layout->descent);
1208 swf_SetU16(tag, 0); // flash ignores leading
1210 for (t = 0; t < f->numchars; t++)
1211 swf_SetU16(tag, f->glyph[t].advance);
1212 for (t = 0; t < f->numchars; t++) {
1213 swf_ResetWriteBits(tag);
1214 /* not used by flash, so leave this empty */
1215 SRECT b = {0,0,0,0};
1216 swf_SetRect(tag, &b);
1218 swf_SetU16(tag, f->layout->kerningcount);
1219 for (t = 0; t < f->layout->kerningcount; t++) {
1220 if (flags & 4) { /* wide codes */
1221 swf_SetU16(tag, f->layout->kerning[t].char1);
1222 swf_SetU16(tag, f->layout->kerning[t].char2);
1224 swf_SetU8(tag, f->layout->kerning[t].char1);
1225 swf_SetU8(tag, f->layout->kerning[t].char2);
1227 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1233 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1235 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1236 f->layout->ascent = ascent;
1237 f->layout->descent = descent;
1238 f->layout->leading = leading;
1239 f->layout->kerningcount = 0;
1240 f->layout->kerning = 0;
1241 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1244 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1251 swf_ResetWriteBits(t);
1252 swf_SetU16(t, f->id);
1253 l = f->name ? strlen((const char *)f->name) : 0;
1258 swf_SetBlock(t, f->name, l);
1259 if (f->numchars >= 256)
1262 if (f->style & FONT_STYLE_BOLD)
1264 if (f->style & FONT_STYLE_ITALIC)
1266 if (f->style & FONT_ENCODING_ANSI)
1268 if (f->style & FONT_ENCODING_SHIFTJIS)
1270 if (f->style & FONT_ENCODING_UNICODE)
1273 swf_SetU8(t, (flags & 0xfe) | wide);
1275 for (i = 0; i < f->numchars; i++) {
1276 if (f->glyph[i].shape) {
1277 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1278 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1285 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1287 int id = swf_GetTagID(t);
1288 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1289 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1295 static void font_freealignzones(SWFFONT * f)
1298 free(f->alignzones);
1302 void swf_FontFree(SWFFONT * f)
1310 for (i = 0; i < f->numchars; i++)
1311 if (f->glyph[i].shape)
1313 swf_ShapeFree(f->glyph[i].shape);
1314 f->glyph[i].shape = NULL;
1321 rfx_free(f->ascii2glyph);
1322 f->ascii2glyph = NULL;
1326 rfx_free(f->glyph2ascii);
1327 f->glyph2ascii = NULL;
1329 if (f->glyph2glyph) {
1330 rfx_free(f->glyph2glyph);
1331 f->glyph2glyph = NULL;
1335 font_freeglyphnames(f);
1337 font_freealignzones(f);
1342 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1348 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1349 | (y ? TF_HASYOFFSET : 0);
1351 swf_SetU8(t, flags);
1353 swf_SetU16(t, font->id);
1355 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1356 swf_SetRGBA(t, color);
1358 swf_SetRGB(t, color);
1361 if(x != SET_TO_ZERO) {
1362 if(x>32767 || x<-32768)
1363 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1370 if(y != SET_TO_ZERO) {
1371 if(y>32767 || y<-32768)
1372 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1379 swf_SetU16(t, size);
1384 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1388 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1392 if (!strcmp(encoding, "UTF8"))
1394 else if (!strcmp(encoding, "iso-8859-1"))
1397 fprintf(stderr, "Unknown encoding: %s", encoding);
1405 c = readUTF8char(&s);
1407 if (c < font->maxascii)
1408 glyph = font->ascii2glyph[c];
1410 g = swf_CountUBits(glyph, g);
1411 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1422 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1427 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1430 if (!strcmp(encoding, "UTF8"))
1432 else if (!strcmp(encoding, "iso-8859-1"))
1435 fprintf(stderr, "Unknown encoding: %s", encoding);
1438 swf_SetU8(t, l); //placeholder
1446 c = readUTF8char(&s);
1448 if (c < font->maxascii)
1449 g = font->ascii2glyph[c];
1451 swf_SetBits(t, g, gbits);
1452 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1454 /* We split into 127 characters per text field.
1455 We could do 255, by the (formerly wrong) flash specification,
1456 but some SWF parsing code out there still assumes that char blocks
1457 are at max 127 characters, and it would save only a few bits.
1464 PUT8(&t->data[pos], l);
1466 swf_ResetWriteBits(t);
1470 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1472 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1475 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1477 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1480 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1482 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1485 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1487 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1490 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1497 if (*s < font->maxascii)
1498 g = font->ascii2glyph[*s];
1500 res += font->glyph[g].advance / 20;
1504 res = (res * scale) / 100;
1509 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1516 int c = readUTF8char(&s);
1517 if(c==13 || c==10) {
1522 ypos+=font->layout->leading;
1525 if (c < font->maxascii) {
1526 int g = font->ascii2glyph[c];
1528 SRECT rn = font->layout->bounds[g];
1529 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1530 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1531 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1532 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1533 swf_ExpandRect2(&r, &rn);
1534 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1542 SWFFONT *swf_ReadFont(const char *filename)
1548 f = open(filename, O_RDONLY|O_BINARY);
1550 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1551 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1557 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1564 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)
1566 swf_SetRect(tag, &r);
1567 swf_ResetWriteBits(tag);
1569 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1571 flags |= ET_HASTEXT;
1573 flags |= ET_HASTEXTCOLOR;
1575 flags |= ET_HASMAXLENGTH;
1577 flags |= ET_HASFONT;
1579 flags |= ET_HASLAYOUT;
1581 swf_SetBits(tag, flags, 16);
1583 if (flags & ET_HASFONT) {
1584 swf_SetU16(tag, font); //font
1585 swf_SetU16(tag, height); //fontheight
1587 if (flags & ET_HASTEXTCOLOR) {
1588 swf_SetRGBA(tag, color);
1590 if (flags & ET_HASMAXLENGTH) {
1591 swf_SetU16(tag, maxlength); //maxlength
1593 if (flags & ET_HASLAYOUT) {
1594 swf_SetU8(tag, layout->align); //align
1595 swf_SetU16(tag, layout->leftmargin); //left margin
1596 swf_SetU16(tag, layout->rightmargin); //right margin
1597 swf_SetU16(tag, layout->indent); //indent
1598 swf_SetU16(tag, layout->leading); //leading
1600 swf_SetString(tag, variable);
1601 if (flags & ET_HASTEXT)
1602 swf_SetString(tag, text);
1605 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1609 U8 *utext = (U8 *) strdup(text);
1615 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1616 ystep = font->layout->leading;
1618 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1619 /* Hm, without layout information, we can't compute a bounding
1620 box. We could call swf_FontCreateLayout to create a layout,
1621 but the caller probably doesn't want us to mess up his font
1624 r.xmin = r.ymin = 0;
1625 r.xmax = r.ymax = 1024 * 20;
1629 swf_SetRect(tag, &r);
1631 /* The text matrix is pretty boring, as it doesn't apply to
1632 individual characters, but rather whole text objects (or
1633 at least whole char records- haven't tested).
1634 So it can't do anything which we can't already do with
1635 the placeobject tag we use for placing the text on the scene.
1637 swf_SetMatrix(tag, 0);
1639 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1640 swf_SetU8(tag, gbits);
1641 swf_SetU8(tag, abits);
1647 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1650 while(*next && *next!=13 && *next!=10 && count<127) {
1651 readUTF8char(&next);
1654 if(next[0] == 13 || next[0] == 10) {
1659 if(next[0] == 13 && next[1] == 10)
1662 if(next[0] == 13 || next[0] == 10) {
1667 /* now set the text params- notice that a font size of
1668 1024 (or 1024*20 for definefont3) means that the glyphs will
1669 be displayed exactly as they would be in/with a defineshape.
1670 This is not documented in the specs.
1673 /* set the actual text- notice that we just pass our scale
1674 parameter over, as TextSetCharRecord calculates with
1676 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1686 void swf_FontCreateLayout(SWFFONT * f)
1695 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1696 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1697 f->layout->ascent = 0;
1698 f->layout->descent = 0;
1700 for (t = 0; t < f->numchars; t++) {
1704 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1706 fprintf(stderr, "Shape parse error\n");
1709 bbox = swf_GetShapeBoundingBox(shape2);
1710 swf_Shape2Free(shape2);
1711 f->layout->bounds[t] = bbox;
1713 width = (bbox.xmax);
1715 /* The following is a heuristic- it may be that extractfont_DefineText
1716 has already found out some widths for individual characters (from the way
1717 they are used)- we now have to guess whether that width might be possible,
1718 which is the case if it isn't either much too big or much too small */
1719 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1720 f->glyph[t].advance = width;
1722 if (-bbox.ymin > f->layout->ascent)
1723 f->layout->ascent = -bbox.ymin;
1724 if (bbox.ymax > f->layout->descent)
1725 f->layout->descent = bbox.ymax;
1729 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1731 U8 *s = (U8 *) text;
1737 U32 c = readUTF8char(&s);
1738 int g = font->ascii2glyph[c];
1739 shape = font->glyph[g].shape;
1740 if (((int) g) < 0) {
1741 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1744 shape2 = swf_ShapeToShape2(shape);
1747 if (l->type == moveTo) {
1749 to.x = l->x * size / 100.0 / 20.0 + advance;
1750 to.y = l->y * size / 100.0 / 20.0;
1751 draw->moveTo(draw, &to);
1752 } else if (l->type == lineTo) {
1754 to.x = l->x * size / 100.0 / 20.0 + advance;
1755 to.y = l->y * size / 100.0 / 20.0;
1756 draw->lineTo(draw, &to);
1757 } else if (l->type == splineTo) {
1759 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1760 mid.y = l->sy * size / 100.0 / 20.0;
1761 to.x = l->x * size / 100.0 / 20.0 + advance;
1762 to.y = l->y * size / 100.0 / 20.0;
1763 draw->splineTo(draw, &mid, &to);
1767 swf_Shape2Free(shape2);
1768 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1772 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1775 swf_FontCreateLayout(font);
1778 memset(&swf, 0, sizeof(SWF));
1779 swf.fileVersion = 9;
1780 swf.frameRate = 0x4000;
1781 swf.movieSize.xmax = 200;
1782 swf.movieSize.ymax = 200;
1784 if(!font->id) font->id=1;
1787 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1788 swf_FontSetDefine2(tag, font);
1790 char*name = font->name?(char*)font->name:"font";
1792 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1793 swf_SetU16(tag, font->id);
1794 swf_SetString(tag, name);
1795 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1797 swf_SetU16(tag, font->id);
1798 swf_SetString(tag, name);
1799 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1801 tag = swf_InsertTag(tag, ST_END);
1802 swf_SaveSWF(&swf, filename);
1806 void swf_WriteFont(SWFFONT * font, char *filename)
1809 swf_FontCreateLayout(font);
1818 memset(&swf, 0, sizeof(SWF));
1819 swf.fileVersion = 8;
1820 swf.frameRate = 0x4000;
1821 swf.movieSize.xmax = 1024*20;
1822 swf.movieSize.ymax = 768*20;
1825 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1826 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1828 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1829 swf_FontSetDefine2(tag, font);
1831 if(font->glyphnames) {
1833 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1834 swf_SetU16(tag, font->id);
1835 swf_SetU16(tag, font->numchars);
1836 for (c = 0; c < font->numchars; c++) {
1837 if (font->glyphnames[c])
1838 swf_SetString(tag, font->glyphnames[c]);
1840 swf_SetString(tag, "");
1846 RGBA white = {255,255,255,255};
1847 RGBA black = {255,0,0,0};
1848 RGBA gray50 = {255,128,128,128};
1849 RGBA green = {255,0,255,0};
1851 SCOORD miny = SCOORD_MAX;
1852 SCOORD maxy = SCOORD_MIN;
1854 U16 max_advance = 0;
1855 char*flags = rfx_calloc(font->numchars);
1856 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1857 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1858 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1859 for(t=0;t<font->numchars;t++) {
1860 SHAPE*s = font->glyph[t].shape;
1861 SHAPE2*s2 = swf_ShapeToShape2(s);
1862 SRECT r = swf_GetShapeBoundingBox(s2);
1864 // inside a definefont3, everything is 20x the resolution:
1865 double rx1 = r.xmin / 20.0;
1866 double ry1 = r.ymin / 20.0;
1867 double rx2 = r.xmax / 20.0;
1868 double ry2 = r.ymax / 20.0;
1873 if(ry1<miny) {miny=ry1;}
1874 if(ry2>maxy) {maxy=ry2;}
1875 swf_Shape2Free(s2);free(s2);
1876 width += font->glyph[t].advance;
1877 if(font->glyph[t].advance>max_advance)
1878 max_advance = font->glyph[t].advance;
1881 if(miny==SCOORD_MAX) miny=maxy=0;
1882 if(miny==maxy) maxy=miny+1;
1884 /* scale the font so that it's 256 pixels high */
1885 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1886 double overlarge_factor;
1890 overlarge_factor = scale / 32767.0;
1893 overlarge_factor = 1.0;
1897 int spriteid = id++;
1900 r.ymin = miny*fontsize/1024;
1901 r.xmax = width*fontsize/20480;
1902 r.ymax = maxy*fontsize/1024;
1903 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1904 swf_SetU16(tag, textid);
1905 swf_SetRect(tag, &r);
1906 swf_SetMatrix(tag, NULL);
1909 U8 gbits = swf_CountBits(font->numchars, 0);
1910 swf_SetU8(tag, gbits);
1911 swf_SetU8(tag, abits);
1913 RGBA rgb = {255,0,0,0};
1915 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1916 ActionTAG*array = 0;
1918 array = action_PushString(array, "xpos");
1919 for(t=0;t<font->numchars;t++) {
1921 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1922 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1923 x += width * overlarge_factor;
1924 swf_SetBits(tag, t, gbits);
1925 swf_SetBits(tag, width, abits);
1926 swf_SetU8(tag, 128);
1928 array = action_PushInt(array, x/20);
1929 array = action_PushInt(array, font->numchars+1);
1930 array = action_InitArray(array);
1931 array = action_SetVariable(array);
1935 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1938 int ls = swf_ShapeAddLineStyle(s,20,&white);
1940 swf_SetU16(tag,shapeid);
1946 swf_SetRect(tag,&r);
1947 swf_SetShapeHeader(tag,s);
1948 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1950 /* Ç and  are good chars to test ascent/descent extend */
1951 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1952 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1954 swf_ShapeSetMove(tag,s,0,y1);
1955 swf_ShapeSetLine(tag,s,width,0);
1956 swf_ShapeSetMove(tag,s,0,y2);
1957 swf_ShapeSetLine(tag,s,width,0);
1959 swf_ShapeSetEnd(tag);
1961 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1962 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1967 for(t=0;t<font->numchars;t++) {
1968 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1971 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1972 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1973 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1975 swf_SetU16(tag,shapeid);
1981 swf_SetRect(tag,&r);
1982 swf_SetShapeHeader(tag,s);
1983 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1984 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1985 SHAPELINE*l = s2->lines;
1986 int lastx=0,lasty=0;
1988 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1989 double y1 = -miny*20*scale*2/20480.0;
1990 double scalex = scale*2/20480.0;
1991 double scaley = scale*2/20480.0;
1994 int lx = (l->x)*scalex+x1;
1995 int ly = (l->y)*scaley+y1;
1996 int sx = (l->sx)*scalex+x1;
1997 int sy = (l->sy)*scaley+y1;
1998 if(l->type == moveTo) {
1999 swf_ShapeSetMove(tag,s,lx,ly);
2000 } else if(l->type == lineTo) {
2001 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
2002 } else if(l->type == splineTo) {
2003 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
2010 if(font->alignzones) {
2011 ALIGNZONE*zone = &font->alignzones[t];
2012 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
2013 if((zone->x&zone->dx)!=0xffff) {
2014 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
2015 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
2016 swf_ShapeSetMove(tag,s,x,0);
2017 swf_ShapeSetLine(tag,s,0,1024*20);
2018 swf_ShapeSetMove(tag,s,dx,0);
2019 swf_ShapeSetLine(tag,s,0,1024*20);
2021 if((zone->y&zone->dy)!=0xffff) {
2022 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
2023 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
2024 swf_ShapeSetMove(tag,s,0,y);
2025 swf_ShapeSetLine(tag,s,1024*20,0);
2026 swf_ShapeSetMove(tag,s,0,dy);
2027 swf_ShapeSetLine(tag,s,1024*20,0);
2031 swf_ShapeSetEnd(tag);
2034 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2036 swf_SetU16(tag, spriteid);
2038 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2039 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2040 tag = swf_InsertTag(tag, ST_END);
2041 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2043 swf_GetMatrix(0, &m);
2046 sprintf(txt, "char%d", font->numchars-t);
2047 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
2051 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
2053 RGBA blue = {0xff,0xc0,0xc0,0xff};
2054 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
2055 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2057 swf_SetU16(tag, spriteid2);
2059 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2060 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2061 tag = swf_InsertTag(tag, ST_END);
2062 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2063 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
2066 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2067 swf_SetU16(tag, spriteid);
2069 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2071 swf_GetMatrix(0, &m);
2072 m.sx = 65536 * overlarge_factor;
2073 m.sy = 65536 * overlarge_factor;
2075 m.ty = -miny*256*20/(maxy-miny);
2076 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
2077 tag = swf_InsertTag(tag, ST_END);
2078 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2079 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
2082 RGBA blue2 = {0x80,0x80,0xff,0x80};
2083 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2085 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2086 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2088 swf_SetU16(tag, spriteid3);
2090 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2091 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2092 tag = swf_InsertTag(tag, ST_END);
2093 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2094 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2098 " var mouseListener = new Object();"
2101 " var currentMouseOver, currentChar;"
2102 " mouseListener.onMouseDown = function() { "
2103 " eval(\"_root.char\"+currentChar)._y = 20000;"
2104 " currentChar = currentMouseOver;"
2105 " var i = currentMouseOver;"
2106 " eval(\"_root.char\"+i)._y = 256;"
2107 " _root.marker2._yscale=256*100;"
2108 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2109 " _root.marker2._x=xpos[i]+myx;"
2111 " mouseListener.onMouseMove = function() { "
2112 " if(_ymouse<256) {"
2113 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2118 " setInterval( function(){ "
2119 " if(_ymouse<256) {"
2120 " var i, x=_xmouse-_root.textbar._x;"
2121 " for(i=xpos.length-1;i>0;i--) {"
2122 " if(x<xpos[i-1]) break;"
2124 " currentMouseOver = i;"
2125 " _root.marker._yscale=256*100;"
2126 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2127 " _root.marker._x=xpos[i]+myx;"
2128 " _root.textbar._x += 0.05;"
2130 " if(myx+speed>0) {"
2132 " } else if(myx+speed<-xpos[0]+1024) {"
2136 " _root.textbar._x = myx;"
2137 " _root.marker._x += speed;"
2138 " _root.marker2._x += speed;"
2140 " Mouse.addListener(mouseListener);"
2142 ActionTAG* atag = swf_ActionCompile(data, 6);
2144 tag = swf_InsertTag(tag, ST_DOACTION);
2145 swf_ActionSet(tag, array);
2146 swf_ActionSet(tag, atag);
2148 swf_ActionFree(atag);
2150 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2157 tag = swf_InsertTag(tag, ST_END);
2159 swf.compressed = -1;
2160 swf_SaveSWF(&swf, filename);