5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9 Copyright (c) 2003,2004 Matthias Kramm
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 static U32 readUTF8char(U8 ** text)
28 if (!(*(*text) & 0x80))
31 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
32 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
33 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
37 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
38 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
39 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
43 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
44 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
46 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
50 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
51 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
54 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
58 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
59 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
61 && (*text)[4] && (*text)[5]) {
62 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
63 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
70 #define TF_TEXTCONTROL 0x80
71 #define TF_HASFONT 0x08
72 #define TF_HASCOLOR 0x04
73 #define TF_HASYOFFSET 0x02
74 #define TF_HASXOFFSET 0x01
76 #define FF_WIDECODES 0x01
78 #define FF_ITALIC 0x04
80 #define FF_SHIFTJIS 0x10
81 #define FF_UNICODE 0x20
84 #define FF2_ITALIC 0x02
85 #define FF2_WIDECODES 0x04
86 #define FF2_WIDEOFFSETS 0x08
88 #define FF2_UNICODE 0x20
89 #define FF2_SHIFTJIS 0x40
90 #define FF2_LAYOUT 0x80
92 int swf_FontIsItalic(SWFFONT * f)
94 return f->style & FONT_STYLE_ITALIC;
97 int swf_FontIsBold(SWFFONT * f)
99 return f->style & FONT_STYLE_BOLD;
102 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
104 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
114 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
125 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
128 swf_GetBlock(t, s, l);
132 (FontCallback) (self, id, s);
134 swf_RestoreTagPos(t);
142 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
149 if ((!id) || (id == fid)) {
160 f->glyph = rfx_calloc(sizeof(SWFGLYPH) * n);
162 for (i = 1; i < n; i++)
164 for (i = 0; i < n; i++)
165 swf_GetSimpleShape(t, &f->glyph[i].shape);
168 swf_RestoreTagPos(t);
172 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
185 if (f->version > 1) {
186 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
187 too. However, they only add little information to what's already
188 inside the DefineFont2 tag */
195 f->name = (U8 *) rfx_alloc(l + 1);
196 swf_GetBlock(t, f->name, l);
199 flags = swf_GetU8(t);
201 f->style |= FONT_STYLE_BOLD;
203 f->style |= FONT_STYLE_ITALIC;
205 f->encoding |= FONT_ENCODING_ANSI;
207 f->encoding |= FONT_ENCODING_SHIFTJIS;
209 f->encoding |= FONT_ENCODING_UNICODE;
211 if (t->id == ST_DEFINEFONTINFO2) {
212 f->language = swf_GetU8(t);
215 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
217 for (i = 0; i < f->numchars; i++) {
218 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
219 if (f->glyph2ascii[i] > maxcode)
220 maxcode = f->glyph2ascii[i];
225 f->maxascii = maxcode;
226 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
227 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
229 for (i = 0; i < f->numchars; i++)
230 f->ascii2glyph[f->glyph2ascii[i]] = i;
233 swf_RestoreTagPos(t);
237 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
243 swf_SetTagPos(tag, 0);
245 fid = swf_GetU16(tag);
248 int num = swf_GetU16(tag);
250 f->glyphnames = rfx_alloc(sizeof(char *) * num);
251 for (t = 0; t < num; t++) {
252 f->glyphnames[t] = strdup(swf_GetString(tag));
256 swf_RestoreTagPos(tag);
261 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
268 U8 flags1, flags2, namelen;
270 swf_SetTagPos(tag, 0);
272 fid = swf_GetU16(tag);
276 flags1 = swf_GetU8(tag);
277 flags2 = swf_GetU8(tag); //reserved flags
280 font->style |= FONT_STYLE_BOLD;
282 font->style |= FONT_STYLE_ITALIC;
284 font->encoding |= FONT_ENCODING_ANSI;
286 font->encoding |= FONT_ENCODING_UNICODE;
288 font->encoding |= FONT_ENCODING_SHIFTJIS;
290 namelen = swf_GetU8(tag);
291 font->name = (U8 *) rfx_alloc(namelen + 1);
292 font->name[namelen] = 0;
293 swf_GetBlock(tag, font->name, namelen);
295 glyphcount = swf_GetU16(tag);
296 font->numchars = glyphcount;
298 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
299 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
301 offset = rfx_calloc(sizeof(U32)*(glyphcount+1));
302 offset_start = tag->pos;
304 if (flags1 & 8) { // wide offsets
305 for (t = 0; t < glyphcount; t++)
306 offset[t] = swf_GetU32(tag); //offset[t]
308 if (glyphcount) /* this _if_ is not in the specs */
309 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
311 offset[glyphcount] = tag->pos;
313 for (t = 0; t < glyphcount; t++)
314 offset[t] = swf_GetU16(tag); //offset[t]
316 if (glyphcount) /* this _if_ is not in the specs */
317 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
319 offset[glyphcount] = tag->pos;
321 for (t = 0; t < glyphcount; t++) {
322 swf_SetTagPos(tag, offset[t]+offset_start);
323 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
326 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
331 for (t = 0; t < glyphcount; t++) {
333 if (flags1 & 4) // wide codes
334 code = swf_GetU16(tag);
336 code = swf_GetU8(tag);
337 font->glyph2ascii[t] = code;
344 font->maxascii = maxcode;
345 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
346 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
347 for (t = 0; t < glyphcount; t++) {
348 font->ascii2glyph[font->glyph2ascii[t]] = t;
351 if (flags1 & 128) { // has layout
353 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
354 font->layout->ascent = swf_GetU16(tag);
355 font->layout->descent = swf_GetU16(tag);
356 font->layout->leading = swf_GetU16(tag);
357 for (t = 0; t < glyphcount; t++) {
358 S16 advance = swf_GetS16(tag);
359 font->glyph[t].advance = advance;
361 font->layout->bounds = rfx_alloc(glyphcount * sizeof(SRECT));
362 for (t = 0; t < glyphcount; t++) {
363 swf_ResetReadBits(tag);
364 swf_GetRect(tag, &font->layout->bounds[t]);
367 kerningcount = swf_GetU16(tag);
368 font->layout->kerningcount = kerningcount;
370 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
372 font->layout->kerning = rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
373 for (t = 0; t < kerningcount; t++) {
374 if (flags1 & 4) { // wide codes
375 font->layout->kerning[t].char1 = swf_GetU16(tag);
376 font->layout->kerning[t].char2 = swf_GetU16(tag);
378 font->layout->kerning[t].char1 = swf_GetU8(tag);
379 font->layout->kerning[t].char2 = swf_GetU8(tag);
381 font->layout->kerning[t].adjustment = swf_GetS16(tag);
385 swf_RestoreTagPos(t);
390 #define FEDTJ_PRINT 0x01
391 #define FEDTJ_MODIFY 0x02
392 #define FEDTJ_CALLBACK 0x04
395 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
396 void (*callback) (void *self,
397 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
408 memset(&color, 0, sizeof(color));
415 swf_GetMatrix(t, &m);
416 gbits = swf_GetU8(t);
417 abits = swf_GetU8(t);
421 flags = swf_GetU8(t);
425 if (flags & TF_TEXTCONTROL) {
426 if (flags & TF_HASFONT)
428 if (flags & TF_HASCOLOR) {
429 color.r = swf_GetU8(t); // rgb
430 color.g = swf_GetU8(t);
431 color.b = swf_GetU8(t);
432 if (swf_GetTagID(t) == ST_DEFINETEXT2)
433 color.a = swf_GetU8(t);
437 if (flags & TF_HASXOFFSET)
439 if (flags & TF_HASYOFFSET)
441 if (flags & TF_HASFONT)
442 fontsize = swf_GetU16(t);
454 for (i = 0; i < num; i++) {
458 glyph = swf_GetBits(t, gbits);
459 adv = swf_GetBits(t, abits);
464 if (jobs & FEDTJ_PRINT) {
465 int code = f->glyph2ascii[glyph];
468 if (jobs & FEDTJ_MODIFY)
469 f->glyph[glyph].advance = adv * 20; //?
471 if (jobs & FEDTJ_PRINT) {
479 if ((id == fid) && (jobs & FEDTJ_PRINT))
481 if (jobs & FEDTJ_CALLBACK)
482 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
487 swf_RestoreTagPos(t);
491 int swf_ParseDefineText(TAG * tag,
492 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
494 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
497 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
499 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
502 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
507 if ((!swf) || (!font))
510 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
516 switch (swf_GetTagID(t)) {
518 nid = swf_FontExtract_DefineFont(id, f, t);
522 nid = swf_FontExtract_DefineFont2(id, f, t);
525 case ST_DEFINEFONTINFO:
526 case ST_DEFINEFONTINFO2:
527 nid = swf_FontExtract_DefineFontInfo(id, f, t);
532 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
536 nid = swf_FontExtract_GlyphNames(id, f, t);
551 int swf_FontSetID(SWFFONT * f, U16 id)
559 void swf_LayoutFree(SWFLAYOUT * l)
563 rfx_free(l->kerning);
573 static void font_freeglyphnames(SWFFONT*f)
577 for (t = 0; t < f->numchars; t++) {
578 if (f->glyphnames[t]) {
579 rfx_free(f->glyphnames[t]);
580 f->glyphnames[t] = 0;
583 rfx_free(f->glyphnames);
588 static void font_freeusage(SWFFONT*f)
592 rfx_free(f->use->chars);f->use->chars = 0;
594 rfx_free(f->use); f->use = 0;
597 static void font_freelayout(SWFFONT*f)
600 swf_LayoutFree(f->layout);
604 static void font_freename(SWFFONT*f)
612 int swf_FontReduce_old(SWFFONT * f)
616 if ((!f) || (!f->use) || f->use->is_reduced)
621 for (i = 0; i < f->numchars; i++) {
622 if (f->glyph[i].shape && f->use->chars[i]) {
623 f->glyph2ascii[j] = f->glyph2ascii[i];
624 f->glyph[j] = f->glyph[i];
625 f->use->chars[i] = j;
628 f->glyph2ascii[i] = 0;
629 if(f->glyph[i].shape) {
630 swf_ShapeFree(f->glyph[i].shape);
631 f->glyph[i].shape = 0;
632 f->glyph[i].advance = 0;
634 f->use->chars[i] = -1;
638 for (i = 0; i < f->maxascii; i++) {
639 if(f->use->chars[f->ascii2glyph[i]]<0) {
640 f->ascii2glyph[i] = -1;
642 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
646 f->maxascii = max_unicode;
647 f->use->is_reduced = 1;
650 font_freeglyphnames(f);
655 int swf_FontReduce(SWFFONT * f)
660 if ((!f) || (!f->use) || f->use->is_reduced)
664 font_freeglyphnames(f);
666 f->use->used_glyphs= 0;
667 for (i = 0; i < f->numchars; i++) {
668 if(!f->use->chars[i]) {
670 f->glyph2ascii[i] = 0;
672 if(f->glyph[i].shape) {
673 swf_ShapeFree(f->glyph[i].shape);
674 f->glyph[i].shape = 0;
675 f->glyph[i].advance = 0;
677 f->use->used_glyphs++;
682 for (i = 0; i < f->maxascii; i++) {
683 if(!f->use->chars[f->ascii2glyph[i]]) {
685 f->ascii2glyph[i] = -1;
691 f->maxascii = max_unicode;
692 f->numchars = max_glyph;
697 void swf_FontSort(SWFFONT * font)
705 newplace = rfx_alloc(sizeof(int) * font->numchars);
707 for (i = 0; i < font->numchars; i++) {
710 for (i = 0; i < font->numchars; i++)
711 for (j = 0; j < i; j++) {
712 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
721 n1 = font->glyph2ascii[i];
722 n2 = font->glyph2ascii[j];
723 font->glyph2ascii[j] = n1;
724 font->glyph2ascii[i] = n2;
729 if (font->glyphnames) {
730 c1 = font->glyphnames[i];
731 c2 = font->glyphnames[j];
732 font->glyphnames[j] = c1;
733 font->glyphnames[i] = c2;
736 r1 = font->layout->bounds[i];
737 r2 = font->layout->bounds[j];
738 font->layout->bounds[j] = r1;
739 font->layout->bounds[i] = r2;
743 newpos = rfx_alloc(sizeof(int) * font->numchars);
744 for (i = 0; i < font->numchars; i++) {
745 newpos[newplace[i]] = i;
747 for (i = 0; i < font->maxascii; i++) {
748 if (font->ascii2glyph[i] >= 0)
749 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
756 void swf_FontPrepareForEditText(SWFFONT * font)
759 swf_FontCreateLayout(font);
763 int swf_FontInitUsage(SWFFONT * f)
768 fprintf(stderr, "Usage initialized twice");
771 f->use = rfx_alloc(sizeof(FONTUSAGE));
772 f->use->is_reduced = 0;
773 f->use->chars = rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
777 void swf_FontClearUsage(SWFFONT * f)
781 rfx_free(f->use->chars); f->use->chars = 0;
782 rfx_free(f->use); f->use = 0;
785 int swf_FontUse(SWFFONT * f, U8 * s)
790 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
791 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
797 int swf_FontUseGlyph(SWFFONT * f, int glyph)
800 swf_FontInitUsage(f);
801 if(glyph < 0 || glyph >= f->numchars)
803 if(!f->use->chars[glyph])
804 f->use->used_glyphs++;
805 f->use->chars[glyph] = 1;
809 int swf_FontSetDefine(TAG * t, SWFFONT * f)
811 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
816 swf_ResetWriteBits(t);
817 swf_SetU16(t, f->id);
821 for (i = 0; i < f->numchars; i++)
822 if (f->glyph[i].shape) {
824 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
827 for (i = 0; i < j; i++)
828 swf_SetU16(t, ofs[i] + j * 2);
830 fprintf(stderr, "rfxswf: warning: Font is empty\n");
834 for (i = 0; i < f->numchars; i++)
835 if (f->glyph[i].shape)
836 swf_SetSimpleShape(t, f->glyph[i].shape);
838 swf_ResetWriteBits(t);
843 static inline int fontSize(SWFFONT * font)
847 for (t = 0; t < font->numchars; t++) {
849 if(font->glyph[t].shape)
850 l = (font->glyph[t].shape->bitlen + 7) / 8;
855 return size + (font->numchars + 1) * 2;
858 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
864 swf_SetU16(tag, f->id);
866 if (f->layout) flags |= 128; // haslayout
867 if (f->numchars > 256)
868 flags |= 4; // widecodes
869 if (f->style & FONT_STYLE_BOLD)
871 if (f->style & FONT_STYLE_ITALIC)
872 flags |= 2; // italic
873 if (f->maxascii >= 256)
874 flags |= 4; //wide codecs
875 if (fontSize(f) > 65535)
876 flags |= 8; //wide offsets
877 flags |= 8 | 4; //FIXME: the above check doesn't work
879 if (f->encoding & FONT_ENCODING_ANSI)
881 if (f->encoding & FONT_ENCODING_UNICODE)
882 flags |= 32; // unicode
883 if (f->encoding & FONT_ENCODING_SHIFTJIS)
884 flags |= 64; // shiftjis
886 swf_SetU8(tag, flags);
887 swf_SetU8(tag, 0); //reserved flags
890 swf_SetU8(tag, strlen(f->name));
891 swf_SetBlock(tag, f->name, strlen(f->name));
893 /* font name (="") */
896 /* number of glyphs */
897 swf_SetU16(tag, f->numchars);
898 /* font offset table */
900 for (t = 0; t <= f->numchars; t++) {
902 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
904 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
907 for (t = 0; t <= f->numchars; t++) {
909 tag->data[pos + t * 4] = (tag->len - pos);
910 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
911 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
912 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
914 if (tag->len - pos > 65535) {
915 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
918 tag->data[pos + t * 2] = (tag->len - pos);
919 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
921 if (t < f->numchars) {
922 if(f->glyph[t].shape) {
923 swf_SetSimpleShape(tag, f->glyph[t].shape);
925 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
931 /* font code table */
932 for (t = 0; t < f->numchars; t++) {
933 if (flags & 4) { /* wide codes */
934 if(f->glyph2ascii[t]) {
935 swf_SetU16(tag, f->glyph2ascii[t]);
940 if(f->glyph2ascii[t]) {
941 swf_SetU8(tag, f->glyph2ascii[t]);
949 swf_SetU16(tag, f->layout->ascent);
950 swf_SetU16(tag, f->layout->descent);
951 swf_SetU16(tag, f->layout->leading);
952 for (t = 0; t < f->numchars; t++)
953 swf_SetU16(tag, f->glyph[t].advance);
954 for (t = 0; t < f->numchars; t++) {
955 swf_ResetWriteBits(tag);
956 swf_SetRect(tag, &f->layout->bounds[t]);
958 swf_SetU16(tag, f->layout->kerningcount);
959 for (t = 0; t < f->layout->kerningcount; t++) {
960 if (flags & 4) { /* wide codes */
961 swf_SetU16(tag, f->layout->kerning[t].char1);
962 swf_SetU16(tag, f->layout->kerning[t].char2);
964 swf_SetU8(tag, f->layout->kerning[t].char1);
965 swf_SetU8(tag, f->layout->kerning[t].char2);
967 swf_SetU16(tag, f->layout->kerning[t].adjustment);
973 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
975 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
976 f->layout->ascent = ascent;
977 f->layout->descent = descent;
978 f->layout->leading = leading;
979 f->layout->kerningcount = 0;
980 f->layout->kerning = 0;
981 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
984 int swf_FontSetInfo(TAG * t, SWFFONT * f)
991 swf_ResetWriteBits(t);
992 swf_SetU16(t, f->id);
993 l = f->name ? strlen(f->name) : 0;
998 swf_SetBlock(t, f->name, l);
999 if (f->numchars >= 256)
1002 if (f->style & FONT_STYLE_BOLD)
1004 if (f->style & FONT_STYLE_ITALIC)
1006 if (f->style & FONT_ENCODING_ANSI)
1008 if (f->style & FONT_ENCODING_SHIFTJIS)
1010 if (f->style & FONT_ENCODING_UNICODE)
1013 swf_SetU8(t, (flags & 0xfe) | wide);
1015 for (i = 0; i < f->numchars; i++) {
1016 if (f->glyph[i].shape) {
1017 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1018 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1025 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1027 int id = swf_GetTagID(t);
1028 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1029 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1035 void swf_FontFree(SWFFONT * f)
1042 for (i = 0; i < f->numchars; i++)
1043 if (f->glyph[i].shape) {
1044 swf_ShapeFree(f->glyph[i].shape);
1045 f->glyph[i].shape = NULL;
1050 if (f->ascii2glyph) {
1051 rfx_free(f->ascii2glyph);
1052 f->ascii2glyph = NULL;
1054 if (f->glyph2ascii) {
1055 rfx_free(f->glyph2ascii);
1056 f->glyph2ascii = NULL;
1060 font_freeglyphnames(f);
1066 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1072 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1073 | (dy ? TF_HASYOFFSET : 0);
1075 swf_SetU8(t, flags);
1077 swf_SetU16(t, font->id);
1079 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1080 swf_SetRGBA(t, color);
1082 swf_SetRGB(t, color);
1085 if(dx != SET_TO_ZERO) {
1086 if(dx>32767 || dx<-32768)
1087 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1094 if(dy != SET_TO_ZERO) {
1095 if(dy>32767 || dy<-32768)
1096 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1103 swf_SetU16(t, size);
1108 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1112 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1116 if (!strcmp(encoding, "UTF8"))
1118 else if (!strcmp(encoding, "iso-8859-1"))
1121 fprintf(stderr, "Unknown encoding: %s", encoding);
1129 c = readUTF8char(&s);
1131 if (c < font->maxascii)
1132 glyph = font->ascii2glyph[c];
1134 g = swf_CountUBits(glyph, g);
1135 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1146 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1151 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1154 if (!strcmp(encoding, "UTF8"))
1156 else if (!strcmp(encoding, "iso-8859-1"))
1159 fprintf(stderr, "Unknown encoding: %s", encoding);
1162 swf_SetU8(t, l); //placeholder
1170 c = readUTF8char(&s);
1172 if (c < font->maxascii)
1173 g = font->ascii2glyph[c];
1175 swf_SetBits(t, g, gbits);
1176 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1178 /* We split into 127 characters per text field.
1179 We could do 255, by the (formerly wrong) flash specification,
1180 but some SWF parsing code out there still assumes that char blocks
1181 are at max 127 characters, and it would save only a few bits.
1188 PUT8(&t->data[pos], l);
1190 swf_ResetWriteBits(t);
1194 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1196 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1199 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1201 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1204 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1206 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1209 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1211 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1214 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1221 if (*s < font->maxascii)
1222 g = font->ascii2glyph[*s];
1224 res += font->glyph[g].advance / 20;
1228 res = (res * scale) / 100;
1233 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1240 int c = readUTF8char(&s);
1241 if(c==13 || c==10) {
1246 ypos+=font->layout->leading;
1249 if (c < font->maxascii) {
1250 int g = font->ascii2glyph[c];
1252 SRECT rn = font->layout->bounds[g];
1253 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1254 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1255 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1256 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1257 swf_ExpandRect2(&r, &rn);
1258 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1266 SWFFONT *swf_ReadFont(char *filename)
1272 f = open(filename, O_RDONLY|O_BINARY);
1274 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1275 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1281 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1288 void swf_WriteFont(SWFFONT * font, char *filename)
1295 int useDefineFont2 = 0;
1296 int storeGlyphNames = 1;
1299 useDefineFont2 = 1; /* the only thing new in definefont2
1300 is layout information. */
1302 font->id = WRITEFONTID; //"FN"
1304 memset(&swf, 0x00, sizeof(SWF));
1306 swf.fileVersion = 4;
1307 swf.frameRate = 0x4000;
1309 /* if we use DefineFont1 to store the characters,
1310 we have to build a textfield to store the
1311 advance values. While at it, we can also
1312 make the whole .swf viewable */
1314 /* we now always create viewable swfs, even if we
1315 did use definefont2 -mk */
1316 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1321 swf_SetRGB(t, &rgb);
1322 if (!useDefineFont2) {
1323 t = swf_InsertTag(t, ST_DEFINEFONT);
1324 swf_FontSetDefine(t, font);
1325 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1326 swf_FontSetInfo(t, font);
1328 t = swf_InsertTag(t, ST_DEFINEFONT2);
1329 swf_FontSetDefine2(t, font);
1332 if (storeGlyphNames && font->glyphnames) {
1334 t = swf_InsertTag(t, ST_GLYPHNAMES);
1335 swf_SetU16(t, WRITEFONTID);
1336 swf_SetU16(t, font->numchars);
1337 for (c = 0; c < font->numchars; c++) {
1338 if (font->glyphnames[c])
1339 swf_SetString(t, font->glyphnames[c]);
1341 swf_SetString(t, "");
1345 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1347 int textscale = 400;
1354 int range = font->maxascii;
1357 if (useDefineFont2 && range > 256) {
1361 for (s = 0; s < range; s++) {
1362 int g = font->ascii2glyph[s];
1364 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1365 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1369 if ((s & 15) == 0) {
1376 ymax = ypos * textscale * 2;
1378 swf.movieSize.xmax = xmax * 20;
1379 swf.movieSize.ymax = ymax;
1381 t = swf_InsertTag(t, ST_DEFINETEXT);
1383 swf_SetU16(t, font->id + 1); // ID
1387 r.xmax = swf.movieSize.xmax;
1388 r.ymax = swf.movieSize.ymax;
1392 swf_SetMatrix(t, NULL);
1394 abits = swf_CountBits(xmax * 16, 0);
1397 swf_SetU8(t, gbits);
1398 swf_SetU8(t, abits);
1404 for (y = 0; y < ((range + 15) / 16); y++) {
1405 int c = 0, lastx = -1;
1406 for (x = 0; x < 16; x++) {
1407 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1408 if (g >= 0 && font->glyph[g].shape) {
1415 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1416 for (x = 0; x < 16; x++) {
1417 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1418 if (g >= 0 && font->glyph[g].shape) {
1419 if (lastx != x * xmax) {
1420 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1423 swf_SetBits(t, g, gbits);
1424 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1425 lastx = x * xmax + (font->glyph[g].advance / 20);
1426 swf_ResetWriteBits(t);
1435 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1437 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1439 t = swf_InsertTag(t, ST_SHOWFRAME);
1443 t = swf_InsertTag(t, ST_END);
1445 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1447 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1454 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1456 swf_SetRect(tag, &r);
1457 swf_ResetWriteBits(tag);
1459 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1461 flags |= ET_HASTEXT;
1463 flags |= ET_HASTEXTCOLOR;
1465 flags |= ET_HASMAXLENGTH;
1467 flags |= ET_HASFONT;
1469 flags |= ET_HASLAYOUT;
1471 swf_SetBits(tag, flags, 16);
1473 if (flags & ET_HASFONT) {
1474 swf_SetU16(tag, font); //font
1475 swf_SetU16(tag, height); //fontheight
1477 if (flags & ET_HASTEXTCOLOR) {
1478 swf_SetRGBA(tag, color);
1480 if (flags & ET_HASMAXLENGTH) {
1481 swf_SetU16(tag, maxlength); //maxlength
1483 if (flags & ET_HASLAYOUT) {
1484 swf_SetU8(tag, layout->align); //align
1485 swf_SetU16(tag, layout->leftmargin); //left margin
1486 swf_SetU16(tag, layout->rightmargin); //right margin
1487 swf_SetU16(tag, layout->indent); //indent
1488 swf_SetU16(tag, layout->leading); //leading
1490 swf_SetString(tag, variable);
1491 if (flags & ET_HASTEXT)
1492 swf_SetString(tag, text);
1495 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1499 U8 *utext = (U8 *) strdup(text);
1505 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1506 ystep = font->layout->leading;
1508 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1509 /* Hm, without layout information, we can't compute a bounding
1510 box. We could call swf_FontCreateLayout to create a layout,
1511 but the caller probably doesn't want us to mess up his font
1514 r.xmin = r.ymin = 0;
1515 r.xmax = r.ymax = 1024 * 20;
1519 swf_SetRect(tag, &r);
1521 /* The text matrix is pretty boring, as it doesn't apply to
1522 individual characters, but rather whole text objects (or
1523 at least whole char records- haven't tested).
1524 So it can't do anything which we can't already do with
1525 the placeobject tag we use for placing the text on the scene.
1527 swf_SetMatrix(tag, 0);
1529 swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1530 swf_SetU8(tag, gbits);
1531 swf_SetU8(tag, abits);
1537 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1540 while(*next && *next!=13 && *next!=10 && count<127) {
1541 readUTF8char(&next);
1544 if(next[0] == 13 || next[0] == 10) {
1549 if(next[0] == 13 && next[1] == 10)
1552 if(next[0] == 13 || next[0] == 10) {
1557 /* now set the text params- notice that a font size of
1558 1024 means that the glyphs will be displayed exactly
1559 as they would be in/with a defineshape. (Try to find
1560 *that* in the flash specs)
1562 /* set the actual text- notice that we just pass our scale
1563 parameter over, as TextSetCharRecord calculates with
1565 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1575 void swf_FontCreateLayout(SWFFONT * f)
1584 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1585 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1586 f->layout->ascent = -32767;
1587 f->layout->descent = -32767;
1589 for (t = 0; t < f->numchars; t++) {
1593 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1595 fprintf(stderr, "Shape parse error\n");
1598 bbox = swf_GetShapeBoundingBox(shape2);
1599 swf_Shape2Free(shape2);
1600 f->layout->bounds[t] = bbox;
1602 width = (bbox.xmax);
1604 /* The following is a heuristic- it may be that extractfont_DefineText
1605 has already found out some widths for individual characters (from the way
1606 they are used)- we now have to guess whether that width might be possible,
1607 which is the case if it isn't either much too big or much too small */
1608 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1609 f->glyph[t].advance = width;
1611 if (-bbox.ymin > f->layout->ascent)
1612 f->layout->ascent = bbox.ymin;
1613 if (bbox.ymax > f->layout->descent)
1614 f->layout->descent = bbox.ymax;
1618 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1620 U8 *s = (U8 *) text;
1626 U32 c = readUTF8char(&s);
1627 int g = font->ascii2glyph[c];
1628 shape = font->glyph[g].shape;
1629 if (((int) g) < 0) {
1630 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1633 shape2 = swf_ShapeToShape2(shape);
1636 if (l->type == moveTo) {
1638 to.x = l->x * size / 100.0 / 20.0 + advance;
1639 to.y = l->y * size / 100.0 / 20.0;
1640 draw->moveTo(draw, &to);
1641 } else if (l->type == lineTo) {
1643 to.x = l->x * size / 100.0 / 20.0 + advance;
1644 to.y = l->y * size / 100.0 / 20.0;
1645 draw->lineTo(draw, &to);
1646 } else if (l->type == splineTo) {
1648 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1649 mid.y = l->sy * size / 100.0 / 20.0;
1650 to.x = l->x * size / 100.0 / 20.0 + advance;
1651 to.y = l->y * size / 100.0 / 20.0;
1652 draw->splineTo(draw, &mid, &to);
1656 swf_Shape2Free(shape2);
1657 advance += font->glyph[g].advance * size / 100.0 / 20.0;