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);
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;
848 void swf_FontSort(SWFFONT * font)
856 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
858 for (i = 0; i < font->numchars; i++) {
861 //qsort(newplace, sizeof(newplace[0]), font->numchars, cmp_chars);
863 for (i = 0; i < font->numchars; i++)
864 for (j = 0; j < i; j++) {
865 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
874 n1 = font->glyph2ascii[i];
875 n2 = font->glyph2ascii[j];
876 font->glyph2ascii[j] = n1;
877 font->glyph2ascii[i] = n2;
882 if (font->glyphnames) {
883 c1 = font->glyphnames[i];
884 c2 = font->glyphnames[j];
885 font->glyphnames[j] = c1;
886 font->glyphnames[i] = c2;
889 r1 = font->layout->bounds[i];
890 r2 = font->layout->bounds[j];
891 font->layout->bounds[j] = r1;
892 font->layout->bounds[i] = r2;
896 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
897 for (i = 0; i < font->numchars; i++) {
898 newpos[newplace[i]] = i;
900 for (i = 0; i < font->maxascii; i++) {
901 if (font->ascii2glyph[i] >= 0)
902 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
906 font->glyph2glyph = newpos;
909 void swf_FontPrepareForEditText(SWFFONT * font)
912 swf_FontCreateLayout(font);
916 int swf_FontInitUsage(SWFFONT * f)
921 fprintf(stderr, "Usage initialized twice");
924 f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE));
925 f->use->smallest_size = 0xffff;
926 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
930 void swf_FontClearUsage(SWFFONT * f)
934 rfx_free(f->use->chars); f->use->chars = 0;
935 rfx_free(f->use); f->use = 0;
938 int swf_FontUse(SWFFONT * f, U8 * s)
943 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
944 swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
950 int swf_FontUseUTF8(SWFFONT * f, const U8 * s, U16 size)
957 ascii = readUTF8char((U8**)&s);
958 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
959 swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
964 int swf_FontUseAll(SWFFONT* f)
969 swf_FontInitUsage(f);
970 for (i = 0; i < f->numchars; i++)
971 f->use->chars[i] = 1;
972 f->use->used_glyphs = f->numchars;
976 static unsigned hash2(int char1, int char2)
978 unsigned hash = char1^(char2<<8);
980 hash ^= (hash >> 11);
981 hash += (hash << 15);
984 static void hashadd(FONTUSAGE*u, int char1, int char2, int nr)
986 unsigned hash = hash2(char1, char2);
988 hash = hash%u->neighbors_hash_size;
989 if(!u->neighbors_hash[hash]) {
990 u->neighbors_hash[hash] = nr+1;
996 int swf_FontUseGetPair(SWFFONT * f, int char1, int char2)
998 FONTUSAGE*u = f->use;
999 if(!u || !u->neighbors_hash_size)
1001 unsigned hash = hash2(char1, char2);
1003 hash = hash%u->neighbors_hash_size;
1004 int pos = u->neighbors_hash[hash];
1008 u->neighbors[pos-1].char1 == char1 &&
1009 u->neighbors[pos-1].char2 == char2) {
1016 void swf_FontUsePair(SWFFONT * f, int char1, int char2)
1019 swf_FontInitUsage(f);
1020 FONTUSAGE*u = f->use;
1022 if(u->num_neighbors*3 >= u->neighbors_hash_size*2) {
1023 if(u->neighbors_hash) {
1024 free(u->neighbors_hash);
1026 u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024;
1027 u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int));
1029 for(t=0;t<u->num_neighbors;t++) {
1030 hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t);
1034 int nr = swf_FontUseGetPair(f, char1, char2);
1036 if(u->num_neighbors == u->neighbors_size) {
1037 u->neighbors_size += 4096;
1038 u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
1040 u->neighbors[u->num_neighbors].char1 = char1;
1041 u->neighbors[u->num_neighbors].char2 = char2;
1042 u->neighbors[u->num_neighbors].num = 1;
1043 hashadd(u, char1, char2, u->num_neighbors);
1046 u->neighbors[nr-1].num++;
1050 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
1053 swf_FontInitUsage(f);
1054 if(glyph < 0 || glyph >= f->numchars)
1056 if(!f->use->chars[glyph])
1057 f->use->used_glyphs++;
1058 f->use->chars[glyph] = 1;
1059 if(size && size < f->use->smallest_size)
1060 f->use->smallest_size = size;
1064 int swf_FontSetDefine(TAG * t, SWFFONT * f)
1066 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
1071 swf_ResetWriteBits(t);
1072 swf_SetU16(t, f->id);
1076 for (i = 0; i < f->numchars; i++)
1077 if (f->glyph[i].shape) {
1079 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
1082 for (i = 0; i < j; i++)
1083 swf_SetU16(t, ofs[i] + j * 2);
1085 fprintf(stderr, "rfxswf: warning: Font is empty\n");
1089 for (i = 0; i < f->numchars; i++)
1090 if (f->glyph[i].shape)
1091 swf_SetSimpleShape(t, f->glyph[i].shape);
1093 swf_ResetWriteBits(t);
1098 static inline int fontSize(SWFFONT * font)
1102 for (t = 0; t < font->numchars; t++) {
1104 if(font->glyph[t].shape)
1105 l = (font->glyph[t].shape->bitlen + 7) / 8;
1110 return size + (font->numchars + 1) * 2;
1113 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
1118 swf_SetU16(tag, f->id);
1120 if (f->layout) flags |= 128; // haslayout
1121 if (f->numchars > 256)
1122 flags |= 4; // widecodes
1123 if (f->style & FONT_STYLE_BOLD)
1125 if (f->style & FONT_STYLE_ITALIC)
1126 flags |= 2; // italic
1127 if (f->maxascii >= 256)
1128 flags |= 4; //wide codecs
1129 if (fontSize(f) > 65535)
1130 flags |= 8; //wide offsets
1131 flags |= 8 | 4; //FIXME: the above check doesn't work
1133 if (f->encoding & FONT_ENCODING_ANSI)
1134 flags |= 16; // ansi
1135 if (f->encoding & FONT_ENCODING_UNICODE)
1136 flags |= 32; // unicode
1137 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1138 flags |= 64; // shiftjis
1140 swf_SetU8(tag, flags);
1141 swf_SetU8(tag, 0); //reserved flags
1144 swf_SetU8(tag, strlen((const char*)f->name)+1);
1145 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1147 /* font name (="") */
1151 /* number of glyphs */
1152 swf_SetU16(tag, f->numchars);
1153 /* font offset table */
1155 for (t = 0; t <= f->numchars; t++) {
1157 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1159 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1162 for (t = 0; t <= f->numchars; t++) {
1164 tag->data[pos + t * 4] = (tag->len - pos);
1165 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1166 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1167 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1169 if (tag->len - pos > 65535) {
1170 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1173 tag->data[pos + t * 2] = (tag->len - pos);
1174 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1176 if (t < f->numchars) {
1177 if(f->glyph[t].shape) {
1178 swf_SetSimpleShape(tag, f->glyph[t].shape);
1180 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1186 /* font code table */
1187 for (t = 0; t < f->numchars; t++) {
1188 if (flags & 4) { /* wide codes */
1189 if(f->glyph2ascii[t]) {
1190 swf_SetU16(tag, f->glyph2ascii[t]);
1195 if(f->glyph2ascii[t]) {
1196 swf_SetU8(tag, f->glyph2ascii[t]);
1204 swf_SetU16(tag, f->layout->ascent);
1205 swf_SetU16(tag, f->layout->descent);
1206 swf_SetU16(tag, 0); // flash ignores leading
1208 for (t = 0; t < f->numchars; t++)
1209 swf_SetU16(tag, f->glyph[t].advance);
1210 for (t = 0; t < f->numchars; t++) {
1211 swf_ResetWriteBits(tag);
1212 /* not used by flash, so leave this empty */
1213 SRECT b = {0,0,0,0};
1214 swf_SetRect(tag, &b);
1216 swf_SetU16(tag, f->layout->kerningcount);
1217 for (t = 0; t < f->layout->kerningcount; t++) {
1218 if (flags & 4) { /* wide codes */
1219 swf_SetU16(tag, f->layout->kerning[t].char1);
1220 swf_SetU16(tag, f->layout->kerning[t].char2);
1222 swf_SetU8(tag, f->layout->kerning[t].char1);
1223 swf_SetU8(tag, f->layout->kerning[t].char2);
1225 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1231 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1233 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1234 f->layout->ascent = ascent;
1235 f->layout->descent = descent;
1236 f->layout->leading = leading;
1237 f->layout->kerningcount = 0;
1238 f->layout->kerning = 0;
1239 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1242 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1249 swf_ResetWriteBits(t);
1250 swf_SetU16(t, f->id);
1251 l = f->name ? strlen((const char *)f->name) : 0;
1256 swf_SetBlock(t, f->name, l);
1257 if (f->numchars >= 256)
1260 if (f->style & FONT_STYLE_BOLD)
1262 if (f->style & FONT_STYLE_ITALIC)
1264 if (f->style & FONT_ENCODING_ANSI)
1266 if (f->style & FONT_ENCODING_SHIFTJIS)
1268 if (f->style & FONT_ENCODING_UNICODE)
1271 swf_SetU8(t, (flags & 0xfe) | wide);
1273 for (i = 0; i < f->numchars; i++) {
1274 if (f->glyph[i].shape) {
1275 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1276 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1283 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1285 int id = swf_GetTagID(t);
1286 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1287 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1293 void swf_FontFree(SWFFONT * f)
1301 for (i = 0; i < f->numchars; i++)
1302 if (f->glyph[i].shape)
1304 swf_ShapeFree(f->glyph[i].shape);
1305 f->glyph[i].shape = NULL;
1312 rfx_free(f->ascii2glyph);
1313 f->ascii2glyph = NULL;
1317 rfx_free(f->glyph2ascii);
1318 f->glyph2ascii = NULL;
1320 if (f->glyph2glyph) {
1321 rfx_free(f->glyph2glyph);
1322 f->glyph2glyph = NULL;
1326 font_freeglyphnames(f);
1332 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1338 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1339 | (y ? TF_HASYOFFSET : 0);
1341 swf_SetU8(t, flags);
1343 swf_SetU16(t, font->id);
1345 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1346 swf_SetRGBA(t, color);
1348 swf_SetRGB(t, color);
1351 if(x != SET_TO_ZERO) {
1352 if(x>32767 || x<-32768)
1353 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1360 if(y != SET_TO_ZERO) {
1361 if(y>32767 || y<-32768)
1362 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1369 swf_SetU16(t, size);
1374 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1378 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1382 if (!strcmp(encoding, "UTF8"))
1384 else if (!strcmp(encoding, "iso-8859-1"))
1387 fprintf(stderr, "Unknown encoding: %s", encoding);
1395 c = readUTF8char(&s);
1397 if (c < font->maxascii)
1398 glyph = font->ascii2glyph[c];
1400 g = swf_CountUBits(glyph, g);
1401 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1412 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1417 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1420 if (!strcmp(encoding, "UTF8"))
1422 else if (!strcmp(encoding, "iso-8859-1"))
1425 fprintf(stderr, "Unknown encoding: %s", encoding);
1428 swf_SetU8(t, l); //placeholder
1436 c = readUTF8char(&s);
1438 if (c < font->maxascii)
1439 g = font->ascii2glyph[c];
1441 swf_SetBits(t, g, gbits);
1442 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1444 /* We split into 127 characters per text field.
1445 We could do 255, by the (formerly wrong) flash specification,
1446 but some SWF parsing code out there still assumes that char blocks
1447 are at max 127 characters, and it would save only a few bits.
1454 PUT8(&t->data[pos], l);
1456 swf_ResetWriteBits(t);
1460 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1462 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1465 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1467 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1470 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1472 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1475 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1477 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1480 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1487 if (*s < font->maxascii)
1488 g = font->ascii2glyph[*s];
1490 res += font->glyph[g].advance / 20;
1494 res = (res * scale) / 100;
1499 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1506 int c = readUTF8char(&s);
1507 if(c==13 || c==10) {
1512 ypos+=font->layout->leading;
1515 if (c < font->maxascii) {
1516 int g = font->ascii2glyph[c];
1518 SRECT rn = font->layout->bounds[g];
1519 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1520 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1521 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1522 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1523 swf_ExpandRect2(&r, &rn);
1524 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1532 SWFFONT *swf_ReadFont(const char *filename)
1538 f = open(filename, O_RDONLY|O_BINARY);
1540 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1541 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1547 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1554 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)
1556 swf_SetRect(tag, &r);
1557 swf_ResetWriteBits(tag);
1559 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1561 flags |= ET_HASTEXT;
1563 flags |= ET_HASTEXTCOLOR;
1565 flags |= ET_HASMAXLENGTH;
1567 flags |= ET_HASFONT;
1569 flags |= ET_HASLAYOUT;
1571 swf_SetBits(tag, flags, 16);
1573 if (flags & ET_HASFONT) {
1574 swf_SetU16(tag, font); //font
1575 swf_SetU16(tag, height); //fontheight
1577 if (flags & ET_HASTEXTCOLOR) {
1578 swf_SetRGBA(tag, color);
1580 if (flags & ET_HASMAXLENGTH) {
1581 swf_SetU16(tag, maxlength); //maxlength
1583 if (flags & ET_HASLAYOUT) {
1584 swf_SetU8(tag, layout->align); //align
1585 swf_SetU16(tag, layout->leftmargin); //left margin
1586 swf_SetU16(tag, layout->rightmargin); //right margin
1587 swf_SetU16(tag, layout->indent); //indent
1588 swf_SetU16(tag, layout->leading); //leading
1590 swf_SetString(tag, variable);
1591 if (flags & ET_HASTEXT)
1592 swf_SetString(tag, text);
1595 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1599 U8 *utext = (U8 *) strdup(text);
1605 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1606 ystep = font->layout->leading;
1608 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1609 /* Hm, without layout information, we can't compute a bounding
1610 box. We could call swf_FontCreateLayout to create a layout,
1611 but the caller probably doesn't want us to mess up his font
1614 r.xmin = r.ymin = 0;
1615 r.xmax = r.ymax = 1024 * 20;
1619 swf_SetRect(tag, &r);
1621 /* The text matrix is pretty boring, as it doesn't apply to
1622 individual characters, but rather whole text objects (or
1623 at least whole char records- haven't tested).
1624 So it can't do anything which we can't already do with
1625 the placeobject tag we use for placing the text on the scene.
1627 swf_SetMatrix(tag, 0);
1629 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1630 swf_SetU8(tag, gbits);
1631 swf_SetU8(tag, abits);
1637 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1640 while(*next && *next!=13 && *next!=10 && count<127) {
1641 readUTF8char(&next);
1644 if(next[0] == 13 || next[0] == 10) {
1649 if(next[0] == 13 && next[1] == 10)
1652 if(next[0] == 13 || next[0] == 10) {
1657 /* now set the text params- notice that a font size of
1658 1024 (or 1024*20 for definefont3) means that the glyphs will
1659 be displayed exactly as they would be in/with a defineshape.
1660 This is not documented in the specs.
1663 /* set the actual text- notice that we just pass our scale
1664 parameter over, as TextSetCharRecord calculates with
1666 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1676 void swf_FontCreateLayout(SWFFONT * f)
1685 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1686 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1687 f->layout->ascent = 0;
1688 f->layout->descent = 0;
1690 for (t = 0; t < f->numchars; t++) {
1694 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1696 fprintf(stderr, "Shape parse error\n");
1699 bbox = swf_GetShapeBoundingBox(shape2);
1700 swf_Shape2Free(shape2);
1701 f->layout->bounds[t] = bbox;
1703 width = (bbox.xmax);
1705 /* The following is a heuristic- it may be that extractfont_DefineText
1706 has already found out some widths for individual characters (from the way
1707 they are used)- we now have to guess whether that width might be possible,
1708 which is the case if it isn't either much too big or much too small */
1709 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1710 f->glyph[t].advance = width;
1712 if (-bbox.ymin > f->layout->ascent)
1713 f->layout->ascent = -bbox.ymin;
1714 if (bbox.ymax > f->layout->descent)
1715 f->layout->descent = bbox.ymax;
1719 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1721 U8 *s = (U8 *) text;
1727 U32 c = readUTF8char(&s);
1728 int g = font->ascii2glyph[c];
1729 shape = font->glyph[g].shape;
1730 if (((int) g) < 0) {
1731 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1734 shape2 = swf_ShapeToShape2(shape);
1737 if (l->type == moveTo) {
1739 to.x = l->x * size / 100.0 / 20.0 + advance;
1740 to.y = l->y * size / 100.0 / 20.0;
1741 draw->moveTo(draw, &to);
1742 } else if (l->type == lineTo) {
1744 to.x = l->x * size / 100.0 / 20.0 + advance;
1745 to.y = l->y * size / 100.0 / 20.0;
1746 draw->lineTo(draw, &to);
1747 } else if (l->type == splineTo) {
1749 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1750 mid.y = l->sy * size / 100.0 / 20.0;
1751 to.x = l->x * size / 100.0 / 20.0 + advance;
1752 to.y = l->y * size / 100.0 / 20.0;
1753 draw->splineTo(draw, &mid, &to);
1757 swf_Shape2Free(shape2);
1758 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1762 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1765 swf_FontCreateLayout(font);
1768 memset(&swf, 0, sizeof(SWF));
1769 swf.fileVersion = 9;
1770 swf.frameRate = 0x4000;
1771 swf.movieSize.xmax = 200;
1772 swf.movieSize.ymax = 200;
1774 if(!font->id) font->id=1;
1777 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1778 swf_FontSetDefine2(tag, font);
1780 char*name = font->name?(char*)font->name:"font";
1782 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1783 swf_SetU16(tag, font->id);
1784 swf_SetString(tag, name);
1785 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1787 swf_SetU16(tag, font->id);
1788 swf_SetString(tag, name);
1789 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1791 tag = swf_InsertTag(tag, ST_END);
1792 swf_SaveSWF(&swf, filename);
1796 void swf_WriteFont(SWFFONT * font, char *filename)
1799 swf_FontCreateLayout(font);
1808 memset(&swf, 0, sizeof(SWF));
1809 swf.fileVersion = 8;
1810 swf.frameRate = 0x4000;
1811 swf.movieSize.xmax = 1024*20;
1812 swf.movieSize.ymax = 768*20;
1815 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1816 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1818 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1819 swf_FontSetDefine2(tag, font);
1821 if(font->glyphnames) {
1823 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1824 swf_SetU16(tag, font->id);
1825 swf_SetU16(tag, font->numchars);
1826 for (c = 0; c < font->numchars; c++) {
1827 if (font->glyphnames[c])
1828 swf_SetString(tag, font->glyphnames[c]);
1830 swf_SetString(tag, "");
1836 RGBA white = {255,255,255,255};
1837 RGBA black = {255,0,0,0};
1838 RGBA gray50 = {255,128,128,128};
1839 RGBA green = {255,0,255,0};
1841 SCOORD miny = SCOORD_MAX;
1842 SCOORD maxy = SCOORD_MIN;
1844 U16 max_advance = 0;
1845 char*flags = rfx_calloc(font->numchars);
1846 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1847 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1848 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1849 for(t=0;t<font->numchars;t++) {
1850 SHAPE*s = font->glyph[t].shape;
1851 SHAPE2*s2 = swf_ShapeToShape2(s);
1852 SRECT r = swf_GetShapeBoundingBox(s2);
1854 // inside a definefont3, everything is 20x the resolution:
1855 double rx1 = r.xmin / 20.0;
1856 double ry1 = r.ymin / 20.0;
1857 double rx2 = r.xmax / 20.0;
1858 double ry2 = r.ymax / 20.0;
1863 if(ry1<miny) {miny=ry1;}
1864 if(ry2>maxy) {maxy=ry2;}
1865 swf_Shape2Free(s2);free(s2);
1866 width += font->glyph[t].advance;
1867 if(font->glyph[t].advance>max_advance)
1868 max_advance = font->glyph[t].advance;
1871 if(miny==SCOORD_MAX) miny=maxy=0;
1872 if(miny==maxy) maxy=miny+1;
1874 /* scale the font so that it's 256 pixels high */
1875 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1876 double overlarge_factor;
1880 overlarge_factor = scale / 32767.0;
1883 overlarge_factor = 1.0;
1887 int spriteid = id++;
1890 r.ymin = miny*fontsize/1024;
1891 r.xmax = width*fontsize/20480;
1892 r.ymax = maxy*fontsize/1024;
1893 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1894 swf_SetU16(tag, textid);
1895 swf_SetRect(tag, &r);
1896 swf_SetMatrix(tag, NULL);
1899 U8 gbits = swf_CountBits(font->numchars, 0);
1900 swf_SetU8(tag, gbits);
1901 swf_SetU8(tag, abits);
1903 RGBA rgb = {255,0,0,0};
1905 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1906 ActionTAG*array = 0;
1908 array = action_PushString(array, "xpos");
1909 for(t=0;t<font->numchars;t++) {
1911 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1912 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1913 x += width * overlarge_factor;
1914 swf_SetBits(tag, t, gbits);
1915 swf_SetBits(tag, width, abits);
1916 swf_SetU8(tag, 128);
1918 array = action_PushInt(array, x/20);
1919 array = action_PushInt(array, font->numchars+1);
1920 array = action_InitArray(array);
1921 array = action_SetVariable(array);
1925 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1928 int ls = swf_ShapeAddLineStyle(s,20,&white);
1930 swf_SetU16(tag,shapeid);
1936 swf_SetRect(tag,&r);
1937 swf_SetShapeHeader(tag,s);
1938 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1940 /* Ç and  are good chars to test ascent/descent extend */
1941 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1942 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1944 swf_ShapeSetMove(tag,s,0,y1);
1945 swf_ShapeSetLine(tag,s,width,0);
1946 swf_ShapeSetMove(tag,s,0,y2);
1947 swf_ShapeSetLine(tag,s,width,0);
1949 swf_ShapeSetEnd(tag);
1951 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1952 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1957 for(t=0;t<font->numchars;t++) {
1958 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1961 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1962 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1963 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1965 swf_SetU16(tag,shapeid);
1971 swf_SetRect(tag,&r);
1972 swf_SetShapeHeader(tag,s);
1973 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1974 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1975 SHAPELINE*l = s2->lines;
1976 int lastx=0,lasty=0;
1978 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1979 double y1 = -miny*20*scale*2/20480.0;
1980 double scalex = scale*2/20480.0;
1981 double scaley = scale*2/20480.0;
1984 int lx = (l->x)*scalex+x1;
1985 int ly = (l->y)*scaley+y1;
1986 int sx = (l->sx)*scalex+x1;
1987 int sy = (l->sy)*scaley+y1;
1988 if(l->type == moveTo) {
1989 swf_ShapeSetMove(tag,s,lx,ly);
1990 } else if(l->type == lineTo) {
1991 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1992 } else if(l->type == splineTo) {
1993 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
2000 if(font->alignzones) {
2001 ALIGNZONE*zone = &font->alignzones[t];
2002 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
2003 if((zone->x&zone->dx)!=0xffff) {
2004 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
2005 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
2006 swf_ShapeSetMove(tag,s,x,0);
2007 swf_ShapeSetLine(tag,s,0,1024*20);
2008 swf_ShapeSetMove(tag,s,dx,0);
2009 swf_ShapeSetLine(tag,s,0,1024*20);
2011 if((zone->y&zone->dy)!=0xffff) {
2012 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
2013 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
2014 swf_ShapeSetMove(tag,s,0,y);
2015 swf_ShapeSetLine(tag,s,1024*20,0);
2016 swf_ShapeSetMove(tag,s,0,dy);
2017 swf_ShapeSetLine(tag,s,1024*20,0);
2021 swf_ShapeSetEnd(tag);
2024 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2026 swf_SetU16(tag, spriteid);
2028 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2029 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2030 tag = swf_InsertTag(tag, ST_END);
2031 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2033 swf_GetMatrix(0, &m);
2036 sprintf(txt, "char%d", font->numchars-t);
2037 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
2041 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
2043 RGBA blue = {0xff,0xc0,0xc0,0xff};
2044 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
2045 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2047 swf_SetU16(tag, spriteid2);
2049 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2050 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2051 tag = swf_InsertTag(tag, ST_END);
2052 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2053 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
2056 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2057 swf_SetU16(tag, spriteid);
2059 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2061 swf_GetMatrix(0, &m);
2062 m.sx = 65536 * overlarge_factor;
2063 m.sy = 65536 * overlarge_factor;
2065 m.ty = -miny*256*20/(maxy-miny);
2066 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
2067 tag = swf_InsertTag(tag, ST_END);
2068 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2069 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
2072 RGBA blue2 = {0x80,0x80,0xff,0x80};
2073 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2075 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2076 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2078 swf_SetU16(tag, spriteid3);
2080 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2081 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2082 tag = swf_InsertTag(tag, ST_END);
2083 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2084 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2088 " var mouseListener = new Object();"
2091 " var currentMouseOver, currentChar;"
2092 " mouseListener.onMouseDown = function() { "
2093 " eval(\"_root.char\"+currentChar)._y = 20000;"
2094 " currentChar = currentMouseOver;"
2095 " var i = currentMouseOver;"
2096 " eval(\"_root.char\"+i)._y = 256;"
2097 " _root.marker2._yscale=256*100;"
2098 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2099 " _root.marker2._x=xpos[i]+myx;"
2101 " mouseListener.onMouseMove = function() { "
2102 " if(_ymouse<256) {"
2103 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2108 " setInterval( function(){ "
2109 " if(_ymouse<256) {"
2110 " var i, x=_xmouse-_root.textbar._x;"
2111 " for(i=xpos.length-1;i>0;i--) {"
2112 " if(x<xpos[i-1]) break;"
2114 " currentMouseOver = i;"
2115 " _root.marker._yscale=256*100;"
2116 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2117 " _root.marker._x=xpos[i]+myx;"
2118 " _root.textbar._x += 0.05;"
2120 " if(myx+speed>0) {"
2122 " } else if(myx+speed<-xpos[0]+1024) {"
2126 " _root.textbar._x = myx;"
2127 " _root.marker._x += speed;"
2128 " _root.marker2._x += speed;"
2130 " Mouse.addListener(mouseListener);"
2132 ActionTAG* atag = swf_ActionCompile(data, 6);
2134 tag = swf_InsertTag(tag, ST_DOACTION);
2135 swf_ActionSet(tag, array);
2136 swf_ActionSet(tag, atag);
2138 swf_ActionFree(atag);
2140 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2147 tag = swf_InsertTag(tag, ST_END);
2149 swf.compressed = -1;
2150 swf_SaveSWF(&swf, filename);