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]);
354 kerningcount = swf_GetU16(tag);
355 font->layout->kerningcount = kerningcount;
357 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
359 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
360 for (t = 0; t < kerningcount; t++) {
361 if (flags1 & 4) { // wide codes
362 font->layout->kerning[t].char1 = swf_GetU16(tag);
363 font->layout->kerning[t].char2 = swf_GetU16(tag);
365 font->layout->kerning[t].char1 = swf_GetU8(tag);
366 font->layout->kerning[t].char2 = swf_GetU8(tag);
368 font->layout->kerning[t].adjustment = swf_GetS16(tag);
375 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
378 swf_SetTagPos(tag, 0);
379 fid = swf_GetU16(tag);
382 font->alignzone_flags = swf_GetU8(tag);
383 font->alignzones = rfx_calloc(sizeof(ALIGNZONE)*font->numchars);
385 while(tag->pos < tag->len) {
386 if(i>=font->numchars)
388 int nr = swf_GetU8(tag); // should be 2
390 fprintf(stderr, "rfxswf: Can't parse alignzone tags with %d zones", nr);
393 U16 x = swf_GetU16(tag);
394 U16 y = swf_GetU16(tag);
395 U16 dx = (nr==2)?swf_GetU16(tag):0xffff;
396 U16 dy = (nr==2)?swf_GetU16(tag):0xffff;
397 U8 xy = swf_GetU8(tag);
400 if((!(xy&1) && (x!=0 || (dx!=0 && dx!=0xffff))) ||
401 (!(xy&2) && (y!=0 || (dy!=0 && dy!=0xffff)))) {
402 fprintf(stderr, "Warning: weird combination of alignzone bits and values (%d x:%04x-%04x y:%04x-%04x)\n", xy,
413 font->alignzones[i].x = x;
414 font->alignzones[i].y = y;
415 font->alignzones[i].dx = dx;
416 font->alignzones[i].dy = dy;
424 #define FEDTJ_PRINT 0x01
425 #define FEDTJ_MODIFY 0x02
426 #define FEDTJ_CALLBACK 0x04
429 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
430 void (*callback) (void *self,
431 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
442 memset(&color, 0, sizeof(color));
448 swf_GetMatrix(t, &m);
449 gbits = swf_GetU8(t);
450 abits = swf_GetU8(t);
454 flags = swf_GetU8(t);
458 if (flags & TF_TEXTCONTROL) {
459 if (flags & TF_HASFONT)
461 if (flags & TF_HASCOLOR) {
462 color.r = swf_GetU8(t); // rgb
463 color.g = swf_GetU8(t);
464 color.b = swf_GetU8(t);
465 if (swf_GetTagID(t) == ST_DEFINETEXT2)
466 color.a = swf_GetU8(t);
470 if (flags & TF_HASXOFFSET)
472 if (flags & TF_HASYOFFSET)
474 if (flags & TF_HASFONT)
475 fontsize = swf_GetU16(t);
487 for (i = 0; i < num; i++) {
491 glyph = swf_GetBits(t, gbits);
492 adv = swf_GetBits(t, abits);
496 if (jobs & FEDTJ_PRINT) {
497 int code = f->glyph2ascii[glyph];
500 if (jobs & FEDTJ_MODIFY)
501 f->glyph[glyph].advance = adv * 20; //?
506 if ((id == fid) && (jobs & FEDTJ_PRINT))
508 if (jobs & FEDTJ_CALLBACK)
509 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
517 int swf_ParseDefineText(TAG * tag,
518 void (*callback) (void *self, int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
520 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
523 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
525 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
528 typedef struct _usagetmp {
533 static void updateusage(void *self, int *chars, int *xpos, int nr,
534 int fontid, int fontsize, int xstart, int ystart, RGBA * color)
536 usagetmp_t*u = (usagetmp_t*)self;
538 swf_FontInitUsage(u->font);
540 if(fontid!=u->font->id)
548 if(c<0 || c>u->font->numchars)
550 swf_FontUseGlyph(u->font, c, fontsize);
551 if(u->lasty == y && x>=u->lastx-200 && abs(u->lastx-x)<200 &&
552 u->last!=c && !swf_ShapeIsEmpty(u->font->glyph[u->last].shape) &&
553 !swf_ShapeIsEmpty(u->font->glyph[c].shape))
555 swf_FontUsePair(u->font, u->last, c);
558 /* FIXME: do we still need to divide advance by 20 for definefont3? */
559 u->lastx = x + (u->font->glyph[c].advance*fontsize/20480);
564 void swf_FontUpdateUsage(SWFFONT*f, TAG* tag)
568 u.lastx = -0x80000000;
569 u.lasty = -0x80000000;
571 swf_ParseDefineText(tag, updateusage, &u);
574 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
579 if ((!swf) || (!font))
582 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
588 switch (swf_GetTagID(t)) {
590 nid = swf_FontExtract_DefineFont(id, f, t);
595 nid = swf_FontExtract_DefineFont2(id, f, t);
598 case ST_DEFINEFONTALIGNZONES:
599 nid = swf_FontExtract_DefineFontAlignZones(id, f, t);
602 case ST_DEFINEFONTINFO:
603 case ST_DEFINEFONTINFO2:
604 nid = swf_FontExtract_DefineFontInfo(id, f, t);
610 nid = swf_FontExtract_DefineText(id, f, t, FEDTJ_MODIFY);
612 if(f->version>=3 && f->layout)
613 swf_FontUpdateUsage(f, t);
617 nid = swf_FontExtract_GlyphNames(id, f, t);
632 int swf_FontSetID(SWFFONT * f, U16 id)
640 void swf_LayoutFree(SWFLAYOUT * l)
644 rfx_free(l->kerning);
654 static void font_freeglyphnames(SWFFONT*f)
659 for (t = 0; t < f->numchars; t++)
661 if (f->glyphnames[t])
663 rfx_free(f->glyphnames[t]);
664 f->glyphnames[t] = 0;
667 rfx_free(f->glyphnames);
671 static void font_freeusage(SWFFONT*f)
675 rfx_free(f->use->chars);f->use->chars = 0;
677 if(f->use->neighbors) {
678 rfx_free(f->use->neighbors);f->use->neighbors = 0;
680 if(f->use->neighbors_hash) {
681 rfx_free(f->use->neighbors_hash);f->use->neighbors_hash = 0;
683 rfx_free(f->use); f->use = 0;
686 static void font_freelayout(SWFFONT*f)
689 swf_LayoutFree(f->layout);
693 static void font_freename(SWFFONT*f)
701 int swf_FontReduce_old(SWFFONT * f)
705 if ((!f) || (!f->use) || f->use->is_reduced)
710 for (i = 0; i < f->numchars; i++) {
711 if (f->glyph[i].shape && f->use->chars[i]) {
712 f->glyph2ascii[j] = f->glyph2ascii[i];
713 f->glyph[j] = f->glyph[i];
714 f->use->chars[i] = j;
717 f->glyph2ascii[i] = 0;
718 if(f->glyph[i].shape) {
719 swf_ShapeFree(f->glyph[i].shape);
720 f->glyph[i].shape = 0;
721 f->glyph[i].advance = 0;
723 f->use->chars[i] = -1;
727 for (i = 0; i < f->maxascii; i++) {
728 if(f->use->chars[f->ascii2glyph[i]]<0) {
729 f->ascii2glyph[i] = -1;
731 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
735 f->maxascii = max_unicode;
736 f->use->is_reduced = 1;
739 font_freeglyphnames(f);
744 int swf_FontReduce_swfc(SWFFONT * f)
748 if ((!f) || (!f->use) || f->use->is_reduced)
751 font_freeglyphnames(f);
754 for (i = 0; i < f->numchars; i++) {
755 if (f->glyph[i].shape && f->use->chars[i]) {
756 f->glyph2ascii[j] = f->glyph2ascii[i];
758 f->layout->bounds[j] = f->layout->bounds[i];
759 f->glyph[j] = f->glyph[i];
760 f->use->chars[i] = j;
763 f->glyph2ascii[i] = 0;
764 if(f->glyph[i].shape) {
765 swf_ShapeFree(f->glyph[i].shape);
766 f->glyph[i].shape = 0;
767 f->glyph[i].advance = 0;
769 f->use->chars[i] = -1;
772 f->use->used_glyphs = j;
773 for (i = 0; i < f->maxascii; i++) {
774 if(f->ascii2glyph[i] > -1) {
775 if (f->use->chars[f->ascii2glyph[i]]<0) {
776 f->use->chars[f->ascii2glyph[i]] = 0;
777 f->ascii2glyph[i] = -1;
779 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
780 f->use->chars[f->ascii2glyph[i]] = 1;
785 f->maxascii = max_unicode;
786 f->use->is_reduced = 1;
792 int swf_FontReduce(SWFFONT * f)
797 if ((!f) || (!f->use) || f->use->is_reduced)
801 font_freeglyphnames(f);
803 f->use->used_glyphs= 0;
804 for (i = 0; i < f->numchars; i++) {
805 if(!f->use->chars[i]) {
807 f->glyph2ascii[i] = 0;
809 if(f->glyph[i].shape) {
810 swf_ShapeFree(f->glyph[i].shape);
811 f->glyph[i].shape = 0;
812 f->glyph[i].advance = 0;
814 // f->use->used_glyphs++;
816 f->use->used_glyphs++;
820 for (i = 0; i < f->maxascii; i++) {
821 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
823 f->ascii2glyph[i] = -1;
829 f->maxascii = max_unicode;
830 f->numchars = max_glyph;
835 static SWFFONT* font_to_sort;
836 int cmp_chars(const void*a, const void*b)
838 int x = *(const int*)a;
839 int y = *(const int*)b;
841 void swf_FontSort(SWFFONT * font)
849 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
851 for (i = 0; i < font->numchars; i++) {
854 //qsort(newplace, sizeof(newplace[0]), font->numchars, cmp_chars);
856 for (i = 0; i < font->numchars; i++)
857 for (j = 0; j < i; j++) {
858 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
867 n1 = font->glyph2ascii[i];
868 n2 = font->glyph2ascii[j];
869 font->glyph2ascii[j] = n1;
870 font->glyph2ascii[i] = n2;
875 if (font->glyphnames) {
876 c1 = font->glyphnames[i];
877 c2 = font->glyphnames[j];
878 font->glyphnames[j] = c1;
879 font->glyphnames[i] = c2;
882 r1 = font->layout->bounds[i];
883 r2 = font->layout->bounds[j];
884 font->layout->bounds[j] = r1;
885 font->layout->bounds[i] = r2;
889 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
890 for (i = 0; i < font->numchars; i++) {
891 newpos[newplace[i]] = i;
893 for (i = 0; i < font->maxascii; i++) {
894 if (font->ascii2glyph[i] >= 0)
895 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
899 font->glyph2glyph = newpos;
902 void swf_FontPrepareForEditText(SWFFONT * font)
905 swf_FontCreateLayout(font);
909 int swf_FontInitUsage(SWFFONT * f)
914 fprintf(stderr, "Usage initialized twice");
917 f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE));
918 f->use->smallest_size = 0xffff;
919 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
923 void swf_FontClearUsage(SWFFONT * f)
927 rfx_free(f->use->chars); f->use->chars = 0;
928 rfx_free(f->use); f->use = 0;
931 int swf_FontUse(SWFFONT * f, U8 * s)
936 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
937 swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
943 int swf_FontUseUTF8(SWFFONT * f, const U8 * s, U16 size)
950 ascii = readUTF8char((U8**)&s);
951 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
952 swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
957 int swf_FontUseAll(SWFFONT* f)
962 swf_FontInitUsage(f);
963 for (i = 0; i < f->numchars; i++)
964 f->use->chars[i] = 1;
965 f->use->used_glyphs = f->numchars;
969 static unsigned hash2(int char1, int char2)
971 unsigned hash = char1^(char2<<8);
973 hash ^= (hash >> 11);
974 hash += (hash << 15);
977 static void hashadd(FONTUSAGE*u, int char1, int char2, int nr)
979 unsigned hash = hash2(char1, char2);
981 hash = hash%u->neighbors_hash_size;
982 if(!u->neighbors_hash[hash]) {
983 u->neighbors_hash[hash] = nr+1;
989 int swf_FontUseGetPair(SWFFONT * f, int char1, int char2)
991 FONTUSAGE*u = f->use;
992 if(!u || !u->neighbors_hash_size)
994 unsigned hash = hash2(char1, char2);
996 hash = hash%u->neighbors_hash_size;
997 int pos = u->neighbors_hash[hash];
1001 u->neighbors[pos-1].char1 == char1 &&
1002 u->neighbors[pos-1].char2 == char2) {
1009 void swf_FontUsePair(SWFFONT * f, int char1, int char2)
1012 swf_FontInitUsage(f);
1013 FONTUSAGE*u = f->use;
1015 if(u->num_neighbors*3 >= u->neighbors_hash_size*2) {
1016 if(u->neighbors_hash) {
1017 free(u->neighbors_hash);
1019 u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024;
1020 u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int));
1022 for(t=0;t<u->num_neighbors;t++) {
1023 hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t);
1027 int nr = swf_FontUseGetPair(f, char1, char2);
1029 if(u->num_neighbors == u->neighbors_size) {
1030 u->neighbors_size += 4096;
1031 u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
1033 u->neighbors[u->num_neighbors].char1 = char1;
1034 u->neighbors[u->num_neighbors].char2 = char2;
1035 u->neighbors[u->num_neighbors].num = 1;
1036 hashadd(u, char1, char2, u->num_neighbors);
1039 u->neighbors[nr-1].num++;
1043 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
1046 swf_FontInitUsage(f);
1047 if(glyph < 0 || glyph >= f->numchars)
1049 if(!f->use->chars[glyph])
1050 f->use->used_glyphs++;
1051 f->use->chars[glyph] = 1;
1052 if(size && size < f->use->smallest_size)
1053 f->use->smallest_size = size;
1057 int swf_FontSetDefine(TAG * t, SWFFONT * f)
1059 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
1064 swf_ResetWriteBits(t);
1065 swf_SetU16(t, f->id);
1069 for (i = 0; i < f->numchars; i++)
1070 if (f->glyph[i].shape) {
1072 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
1075 for (i = 0; i < j; i++)
1076 swf_SetU16(t, ofs[i] + j * 2);
1078 fprintf(stderr, "rfxswf: warning: Font is empty\n");
1082 for (i = 0; i < f->numchars; i++)
1083 if (f->glyph[i].shape)
1084 swf_SetSimpleShape(t, f->glyph[i].shape);
1086 swf_ResetWriteBits(t);
1091 static inline int fontSize(SWFFONT * font)
1095 for (t = 0; t < font->numchars; t++) {
1097 if(font->glyph[t].shape)
1098 l = (font->glyph[t].shape->bitlen + 7) / 8;
1103 return size + (font->numchars + 1) * 2;
1106 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
1111 swf_SetU16(tag, f->id);
1113 if (f->layout) flags |= 128; // haslayout
1114 if (f->numchars > 256)
1115 flags |= 4; // widecodes
1116 if (f->style & FONT_STYLE_BOLD)
1118 if (f->style & FONT_STYLE_ITALIC)
1119 flags |= 2; // italic
1120 if (f->maxascii >= 256)
1121 flags |= 4; //wide codecs
1122 if (fontSize(f) > 65535)
1123 flags |= 8; //wide offsets
1124 flags |= 8 | 4; //FIXME: the above check doesn't work
1126 if (f->encoding & FONT_ENCODING_ANSI)
1127 flags |= 16; // ansi
1128 if (f->encoding & FONT_ENCODING_UNICODE)
1129 flags |= 32; // unicode
1130 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1131 flags |= 64; // shiftjis
1133 swf_SetU8(tag, flags);
1134 swf_SetU8(tag, 0); //reserved flags
1137 swf_SetU8(tag, strlen((const char*)f->name)+1);
1138 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1140 /* font name (="") */
1144 /* number of glyphs */
1145 swf_SetU16(tag, f->numchars);
1146 /* font offset table */
1148 for (t = 0; t <= f->numchars; t++) {
1150 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1152 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1155 for (t = 0; t <= f->numchars; t++) {
1157 tag->data[pos + t * 4] = (tag->len - pos);
1158 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1159 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1160 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1162 if (tag->len - pos > 65535) {
1163 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1166 tag->data[pos + t * 2] = (tag->len - pos);
1167 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1169 if (t < f->numchars) {
1170 if(f->glyph[t].shape) {
1171 swf_SetSimpleShape(tag, f->glyph[t].shape);
1173 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1179 /* font code table */
1180 for (t = 0; t < f->numchars; t++) {
1181 if (flags & 4) { /* wide codes */
1182 if(f->glyph2ascii[t]) {
1183 swf_SetU16(tag, f->glyph2ascii[t]);
1188 if(f->glyph2ascii[t]) {
1189 swf_SetU8(tag, f->glyph2ascii[t]);
1197 swf_SetU16(tag, f->layout->ascent);
1198 swf_SetU16(tag, f->layout->descent);
1199 swf_SetU16(tag, 0); // flash ignores leading
1201 for (t = 0; t < f->numchars; t++)
1202 swf_SetU16(tag, f->glyph[t].advance);
1203 for (t = 0; t < f->numchars; t++) {
1204 swf_ResetWriteBits(tag);
1205 /* not used by flash, so leave this empty */
1206 SRECT b = {0,0,0,0};
1207 swf_SetRect(tag, &b);
1209 swf_SetU16(tag, f->layout->kerningcount);
1210 for (t = 0; t < f->layout->kerningcount; t++) {
1211 if (flags & 4) { /* wide codes */
1212 swf_SetU16(tag, f->layout->kerning[t].char1);
1213 swf_SetU16(tag, f->layout->kerning[t].char2);
1215 swf_SetU8(tag, f->layout->kerning[t].char1);
1216 swf_SetU8(tag, f->layout->kerning[t].char2);
1218 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1224 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1226 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1227 f->layout->ascent = ascent;
1228 f->layout->descent = descent;
1229 f->layout->leading = leading;
1230 f->layout->kerningcount = 0;
1231 f->layout->kerning = 0;
1232 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1235 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1242 swf_ResetWriteBits(t);
1243 swf_SetU16(t, f->id);
1244 l = f->name ? strlen((const char *)f->name) : 0;
1249 swf_SetBlock(t, f->name, l);
1250 if (f->numchars >= 256)
1253 if (f->style & FONT_STYLE_BOLD)
1255 if (f->style & FONT_STYLE_ITALIC)
1257 if (f->style & FONT_ENCODING_ANSI)
1259 if (f->style & FONT_ENCODING_SHIFTJIS)
1261 if (f->style & FONT_ENCODING_UNICODE)
1264 swf_SetU8(t, (flags & 0xfe) | wide);
1266 for (i = 0; i < f->numchars; i++) {
1267 if (f->glyph[i].shape) {
1268 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1269 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1276 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1278 int id = swf_GetTagID(t);
1279 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1280 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1286 void swf_FontFree(SWFFONT * f)
1294 for (i = 0; i < f->numchars; i++)
1295 if (f->glyph[i].shape)
1297 swf_ShapeFree(f->glyph[i].shape);
1298 f->glyph[i].shape = NULL;
1305 rfx_free(f->ascii2glyph);
1306 f->ascii2glyph = NULL;
1310 rfx_free(f->glyph2ascii);
1311 f->glyph2ascii = NULL;
1313 if (f->glyph2glyph) {
1314 rfx_free(f->glyph2glyph);
1315 f->glyph2glyph = NULL;
1319 font_freeglyphnames(f);
1325 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1331 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1332 | (y ? TF_HASYOFFSET : 0);
1334 swf_SetU8(t, flags);
1336 swf_SetU16(t, font->id);
1338 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1339 swf_SetRGBA(t, color);
1341 swf_SetRGB(t, color);
1344 if(x != SET_TO_ZERO) {
1345 if(x>32767 || x<-32768)
1346 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1353 if(y != SET_TO_ZERO) {
1354 if(y>32767 || y<-32768)
1355 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1362 swf_SetU16(t, size);
1367 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1371 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1375 if (!strcmp(encoding, "UTF8"))
1377 else if (!strcmp(encoding, "iso-8859-1"))
1380 fprintf(stderr, "Unknown encoding: %s", encoding);
1388 c = readUTF8char(&s);
1390 if (c < font->maxascii)
1391 glyph = font->ascii2glyph[c];
1393 g = swf_CountUBits(glyph, g);
1394 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1405 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1410 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1413 if (!strcmp(encoding, "UTF8"))
1415 else if (!strcmp(encoding, "iso-8859-1"))
1418 fprintf(stderr, "Unknown encoding: %s", encoding);
1421 swf_SetU8(t, l); //placeholder
1429 c = readUTF8char(&s);
1431 if (c < font->maxascii)
1432 g = font->ascii2glyph[c];
1434 swf_SetBits(t, g, gbits);
1435 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1437 /* We split into 127 characters per text field.
1438 We could do 255, by the (formerly wrong) flash specification,
1439 but some SWF parsing code out there still assumes that char blocks
1440 are at max 127 characters, and it would save only a few bits.
1447 PUT8(&t->data[pos], l);
1449 swf_ResetWriteBits(t);
1453 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1455 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1458 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1460 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1463 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1465 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1468 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1470 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1473 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1480 if (*s < font->maxascii)
1481 g = font->ascii2glyph[*s];
1483 res += font->glyph[g].advance / 20;
1487 res = (res * scale) / 100;
1492 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1499 int c = readUTF8char(&s);
1500 if(c==13 || c==10) {
1505 ypos+=font->layout->leading;
1508 if (c < font->maxascii) {
1509 int g = font->ascii2glyph[c];
1511 SRECT rn = font->layout->bounds[g];
1512 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1513 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1514 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1515 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1516 swf_ExpandRect2(&r, &rn);
1517 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1525 SWFFONT *swf_ReadFont(const char *filename)
1531 f = open(filename, O_RDONLY|O_BINARY);
1533 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1534 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1540 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1547 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)
1549 swf_SetRect(tag, &r);
1550 swf_ResetWriteBits(tag);
1552 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1554 flags |= ET_HASTEXT;
1556 flags |= ET_HASTEXTCOLOR;
1558 flags |= ET_HASMAXLENGTH;
1560 flags |= ET_HASFONT;
1562 flags |= ET_HASLAYOUT;
1564 swf_SetBits(tag, flags, 16);
1566 if (flags & ET_HASFONT) {
1567 swf_SetU16(tag, font); //font
1568 swf_SetU16(tag, height); //fontheight
1570 if (flags & ET_HASTEXTCOLOR) {
1571 swf_SetRGBA(tag, color);
1573 if (flags & ET_HASMAXLENGTH) {
1574 swf_SetU16(tag, maxlength); //maxlength
1576 if (flags & ET_HASLAYOUT) {
1577 swf_SetU8(tag, layout->align); //align
1578 swf_SetU16(tag, layout->leftmargin); //left margin
1579 swf_SetU16(tag, layout->rightmargin); //right margin
1580 swf_SetU16(tag, layout->indent); //indent
1581 swf_SetU16(tag, layout->leading); //leading
1583 swf_SetString(tag, variable);
1584 if (flags & ET_HASTEXT)
1585 swf_SetString(tag, text);
1588 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1592 U8 *utext = (U8 *) strdup(text);
1598 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1599 ystep = font->layout->leading;
1601 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1602 /* Hm, without layout information, we can't compute a bounding
1603 box. We could call swf_FontCreateLayout to create a layout,
1604 but the caller probably doesn't want us to mess up his font
1607 r.xmin = r.ymin = 0;
1608 r.xmax = r.ymax = 1024 * 20;
1612 swf_SetRect(tag, &r);
1614 /* The text matrix is pretty boring, as it doesn't apply to
1615 individual characters, but rather whole text objects (or
1616 at least whole char records- haven't tested).
1617 So it can't do anything which we can't already do with
1618 the placeobject tag we use for placing the text on the scene.
1620 swf_SetMatrix(tag, 0);
1622 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1623 swf_SetU8(tag, gbits);
1624 swf_SetU8(tag, abits);
1630 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1633 while(*next && *next!=13 && *next!=10 && count<127) {
1634 readUTF8char(&next);
1637 if(next[0] == 13 || next[0] == 10) {
1642 if(next[0] == 13 && next[1] == 10)
1645 if(next[0] == 13 || next[0] == 10) {
1650 /* now set the text params- notice that a font size of
1651 1024 (or 1024*20 for definefont3) means that the glyphs will
1652 be displayed exactly as they would be in/with a defineshape.
1653 This is not documented in the specs.
1656 /* set the actual text- notice that we just pass our scale
1657 parameter over, as TextSetCharRecord calculates with
1659 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1669 void swf_FontCreateLayout(SWFFONT * f)
1678 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1679 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1680 f->layout->ascent = 0;
1681 f->layout->descent = 0;
1683 for (t = 0; t < f->numchars; t++) {
1687 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1689 fprintf(stderr, "Shape parse error\n");
1692 bbox = swf_GetShapeBoundingBox(shape2);
1693 swf_Shape2Free(shape2);
1694 f->layout->bounds[t] = bbox;
1696 width = (bbox.xmax);
1698 /* The following is a heuristic- it may be that extractfont_DefineText
1699 has already found out some widths for individual characters (from the way
1700 they are used)- we now have to guess whether that width might be possible,
1701 which is the case if it isn't either much too big or much too small */
1702 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1703 f->glyph[t].advance = width;
1705 if (-bbox.ymin > f->layout->ascent)
1706 f->layout->ascent = -bbox.ymin;
1707 if (bbox.ymax > f->layout->descent)
1708 f->layout->descent = bbox.ymax;
1712 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1714 U8 *s = (U8 *) text;
1720 U32 c = readUTF8char(&s);
1721 int g = font->ascii2glyph[c];
1722 shape = font->glyph[g].shape;
1723 if (((int) g) < 0) {
1724 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1727 shape2 = swf_ShapeToShape2(shape);
1730 if (l->type == moveTo) {
1732 to.x = l->x * size / 100.0 / 20.0 + advance;
1733 to.y = l->y * size / 100.0 / 20.0;
1734 draw->moveTo(draw, &to);
1735 } else if (l->type == lineTo) {
1737 to.x = l->x * size / 100.0 / 20.0 + advance;
1738 to.y = l->y * size / 100.0 / 20.0;
1739 draw->lineTo(draw, &to);
1740 } else if (l->type == splineTo) {
1742 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1743 mid.y = l->sy * size / 100.0 / 20.0;
1744 to.x = l->x * size / 100.0 / 20.0 + advance;
1745 to.y = l->y * size / 100.0 / 20.0;
1746 draw->splineTo(draw, &mid, &to);
1750 swf_Shape2Free(shape2);
1751 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1755 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1758 swf_FontCreateLayout(font);
1761 memset(&swf, 0, sizeof(SWF));
1762 swf.fileVersion = 9;
1763 swf.frameRate = 0x4000;
1764 swf.movieSize.xmax = 200;
1765 swf.movieSize.ymax = 200;
1767 if(!font->id) font->id=1;
1770 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1771 swf_FontSetDefine2(tag, font);
1773 char*name = font->name?(char*)font->name:"font";
1775 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1776 swf_SetU16(tag, font->id);
1777 swf_SetString(tag, name);
1778 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1780 swf_SetU16(tag, font->id);
1781 swf_SetString(tag, name);
1782 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1784 tag = swf_InsertTag(tag, ST_END);
1785 swf_SaveSWF(&swf, filename);
1789 void swf_WriteFont(SWFFONT * font, char *filename)
1792 swf_FontCreateLayout(font);
1801 memset(&swf, 0, sizeof(SWF));
1802 swf.fileVersion = 8;
1803 swf.frameRate = 0x4000;
1804 swf.movieSize.xmax = 1024*20;
1805 swf.movieSize.ymax = 768*20;
1808 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1809 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1811 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1812 swf_FontSetDefine2(tag, font);
1814 if(font->glyphnames) {
1816 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1817 swf_SetU16(tag, font->id);
1818 swf_SetU16(tag, font->numchars);
1819 for (c = 0; c < font->numchars; c++) {
1820 if (font->glyphnames[c])
1821 swf_SetString(tag, font->glyphnames[c]);
1823 swf_SetString(tag, "");
1829 RGBA white = {255,255,255,255};
1830 RGBA black = {255,0,0,0};
1831 RGBA gray50 = {255,128,128,128};
1832 RGBA green = {255,0,255,0};
1834 SCOORD miny = SCOORD_MAX;
1835 SCOORD maxy = SCOORD_MIN;
1837 U16 max_advance = 0;
1838 char*flags = rfx_calloc(font->numchars);
1839 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1840 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1841 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1842 for(t=0;t<font->numchars;t++) {
1843 SHAPE*s = font->glyph[t].shape;
1844 SHAPE2*s2 = swf_ShapeToShape2(s);
1845 SRECT r = swf_GetShapeBoundingBox(s2);
1847 // inside a definefont3, everything is 20x the resolution:
1848 double rx1 = r.xmin / 20.0;
1849 double ry1 = r.ymin / 20.0;
1850 double rx2 = r.xmax / 20.0;
1851 double ry2 = r.ymax / 20.0;
1856 if(ry1<miny) {miny=ry1;}
1857 if(ry2>maxy) {maxy=ry2;}
1858 swf_Shape2Free(s2);free(s2);
1859 width += font->glyph[t].advance;
1860 if(font->glyph[t].advance>max_advance)
1861 max_advance = font->glyph[t].advance;
1864 if(miny==SCOORD_MAX) miny=maxy=0;
1865 if(miny==maxy) maxy=miny+1;
1867 /* scale the font so that it's 256 pixels high */
1868 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1869 double overlarge_factor;
1873 overlarge_factor = scale / 32767.0;
1876 overlarge_factor = 1.0;
1880 int spriteid = id++;
1883 r.ymin = miny*fontsize/1024;
1884 r.xmax = width*fontsize/20480;
1885 r.ymax = maxy*fontsize/1024;
1886 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1887 swf_SetU16(tag, textid);
1888 swf_SetRect(tag, &r);
1889 swf_SetMatrix(tag, NULL);
1892 U8 gbits = swf_CountBits(font->numchars, 0);
1893 swf_SetU8(tag, gbits);
1894 swf_SetU8(tag, abits);
1896 RGBA rgb = {255,0,0,0};
1898 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1899 ActionTAG*array = 0;
1901 array = action_PushString(array, "xpos");
1902 for(t=0;t<font->numchars;t++) {
1904 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1905 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1906 x += width * overlarge_factor;
1907 swf_SetBits(tag, t, gbits);
1908 swf_SetBits(tag, width, abits);
1909 swf_SetU8(tag, 128);
1911 array = action_PushInt(array, x/20);
1912 array = action_PushInt(array, font->numchars+1);
1913 array = action_InitArray(array);
1914 array = action_SetVariable(array);
1918 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1921 int ls = swf_ShapeAddLineStyle(s,20,&white);
1923 swf_SetU16(tag,shapeid);
1929 swf_SetRect(tag,&r);
1930 swf_SetShapeHeader(tag,s);
1931 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1933 /* Ç and  are good chars to test ascent/descent extend */
1934 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1935 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1937 swf_ShapeSetMove(tag,s,0,y1);
1938 swf_ShapeSetLine(tag,s,width,0);
1939 swf_ShapeSetMove(tag,s,0,y2);
1940 swf_ShapeSetLine(tag,s,width,0);
1942 swf_ShapeSetEnd(tag);
1944 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1945 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1950 for(t=0;t<font->numchars;t++) {
1951 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1954 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1955 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1956 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1958 swf_SetU16(tag,shapeid);
1964 swf_SetRect(tag,&r);
1965 swf_SetShapeHeader(tag,s);
1966 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1967 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1968 SHAPELINE*l = s2->lines;
1969 int lastx=0,lasty=0;
1971 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1972 double y1 = -miny*20*scale*2/20480.0;
1973 double scalex = scale*2/20480.0;
1974 double scaley = scale*2/20480.0;
1977 int lx = (l->x)*scalex+x1;
1978 int ly = (l->y)*scaley+y1;
1979 int sx = (l->sx)*scalex+x1;
1980 int sy = (l->sy)*scaley+y1;
1981 if(l->type == moveTo) {
1982 swf_ShapeSetMove(tag,s,lx,ly);
1983 } else if(l->type == lineTo) {
1984 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1985 } else if(l->type == splineTo) {
1986 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1993 if(font->alignzones) {
1994 ALIGNZONE*zone = &font->alignzones[t];
1995 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1996 if((zone->x&zone->dx)!=0xffff) {
1997 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1998 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1999 swf_ShapeSetMove(tag,s,x,0);
2000 swf_ShapeSetLine(tag,s,0,1024*20);
2001 swf_ShapeSetMove(tag,s,dx,0);
2002 swf_ShapeSetLine(tag,s,0,1024*20);
2004 if((zone->y&zone->dy)!=0xffff) {
2005 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
2006 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
2007 swf_ShapeSetMove(tag,s,0,y);
2008 swf_ShapeSetLine(tag,s,1024*20,0);
2009 swf_ShapeSetMove(tag,s,0,dy);
2010 swf_ShapeSetLine(tag,s,1024*20,0);
2014 swf_ShapeSetEnd(tag);
2017 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2019 swf_SetU16(tag, spriteid);
2021 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2022 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2023 tag = swf_InsertTag(tag, ST_END);
2024 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2026 swf_GetMatrix(0, &m);
2029 sprintf(txt, "char%d", font->numchars-t);
2030 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
2034 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
2036 RGBA blue = {0xff,0xc0,0xc0,0xff};
2037 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
2038 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2040 swf_SetU16(tag, spriteid2);
2042 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2043 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2044 tag = swf_InsertTag(tag, ST_END);
2045 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2046 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
2049 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2050 swf_SetU16(tag, spriteid);
2052 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2054 swf_GetMatrix(0, &m);
2055 m.sx = 65536 * overlarge_factor;
2056 m.sy = 65536 * overlarge_factor;
2058 m.ty = -miny*256*20/(maxy-miny);
2059 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
2060 tag = swf_InsertTag(tag, ST_END);
2061 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2062 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
2065 RGBA blue2 = {0x80,0x80,0xff,0x80};
2066 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2068 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2069 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2071 swf_SetU16(tag, spriteid3);
2073 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2074 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2075 tag = swf_InsertTag(tag, ST_END);
2076 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2077 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2081 " var mouseListener = new Object();"
2084 " var currentMouseOver, currentChar;"
2085 " mouseListener.onMouseDown = function() { "
2086 " eval(\"_root.char\"+currentChar)._y = 20000;"
2087 " currentChar = currentMouseOver;"
2088 " var i = currentMouseOver;"
2089 " eval(\"_root.char\"+i)._y = 256;"
2090 " _root.marker2._yscale=256*100;"
2091 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2092 " _root.marker2._x=xpos[i]+myx;"
2094 " mouseListener.onMouseMove = function() { "
2095 " if(_ymouse<256) {"
2096 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2101 " setInterval( function(){ "
2102 " if(_ymouse<256) {"
2103 " var i, x=_xmouse-_root.textbar._x;"
2104 " for(i=xpos.length-1;i>0;i--) {"
2105 " if(x<xpos[i-1]) break;"
2107 " currentMouseOver = i;"
2108 " _root.marker._yscale=256*100;"
2109 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2110 " _root.marker._x=xpos[i]+myx;"
2111 " _root.textbar._x += 0.05;"
2113 " if(myx+speed>0) {"
2115 " } else if(myx+speed<-xpos[0]+1024) {"
2119 " _root.textbar._x = myx;"
2120 " _root.marker._x += speed;"
2121 " _root.marker2._x += speed;"
2123 " Mouse.addListener(mouseListener);"
2125 ActionTAG* atag = swf_ActionCompile(data, 6);
2127 tag = swf_InsertTag(tag, ST_DOACTION);
2128 swf_ActionSet(tag, array);
2129 swf_ActionSet(tag, atag);
2131 swf_ActionFree(atag);
2133 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2140 tag = swf_InsertTag(tag, ST_END);
2142 swf.compressed = -1;
2143 swf_SaveSWF(&swf, filename);