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 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)
578 for (t = 0; t < f->numchars; t++)
580 if (f->glyphnames[t])
582 rfx_free(f->glyphnames[t]);
583 f->glyphnames[t] = 0;
586 rfx_free(f->glyphnames);
590 static void font_freeusage(SWFFONT*f)
594 rfx_free(f->use->chars);f->use->chars = 0;
596 rfx_free(f->use); f->use = 0;
599 static void font_freelayout(SWFFONT*f)
602 swf_LayoutFree(f->layout);
606 static void font_freename(SWFFONT*f)
614 int swf_FontReduce_old(SWFFONT * f)
618 if ((!f) || (!f->use) || f->use->is_reduced)
623 for (i = 0; i < f->numchars; i++) {
624 if (f->glyph[i].shape && f->use->chars[i]) {
625 f->glyph2ascii[j] = f->glyph2ascii[i];
626 f->glyph[j] = f->glyph[i];
627 f->use->chars[i] = j;
630 f->glyph2ascii[i] = 0;
631 if(f->glyph[i].shape) {
632 swf_ShapeFree(f->glyph[i].shape);
633 f->glyph[i].shape = 0;
634 f->glyph[i].advance = 0;
636 f->use->chars[i] = -1;
640 for (i = 0; i < f->maxascii; i++) {
641 if(f->use->chars[f->ascii2glyph[i]]<0) {
642 f->ascii2glyph[i] = -1;
644 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
648 f->maxascii = max_unicode;
649 f->use->is_reduced = 1;
652 font_freeglyphnames(f);
657 int swf_FontReduce(SWFFONT * f)
662 if ((!f) || (!f->use) || f->use->is_reduced)
666 font_freeglyphnames(f);
668 f->use->used_glyphs= 0;
669 for (i = 0; i < f->numchars; i++) {
670 if(!f->use->chars[i]) {
672 f->glyph2ascii[i] = 0;
674 if(f->glyph[i].shape) {
675 swf_ShapeFree(f->glyph[i].shape);
676 f->glyph[i].shape = 0;
677 f->glyph[i].advance = 0;
679 f->use->used_glyphs++;
684 for (i = 0; i < f->maxascii; i++) {
685 if(!f->use->chars[f->ascii2glyph[i]]) {
687 f->ascii2glyph[i] = -1;
693 f->maxascii = max_unicode;
694 f->numchars = max_glyph;
699 void swf_FontSort(SWFFONT * font)
707 newplace = rfx_alloc(sizeof(int) * font->numchars);
709 for (i = 0; i < font->numchars; i++) {
712 for (i = 0; i < font->numchars; i++)
713 for (j = 0; j < i; j++) {
714 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
723 n1 = font->glyph2ascii[i];
724 n2 = font->glyph2ascii[j];
725 font->glyph2ascii[j] = n1;
726 font->glyph2ascii[i] = n2;
731 if (font->glyphnames) {
732 c1 = font->glyphnames[i];
733 c2 = font->glyphnames[j];
734 font->glyphnames[j] = c1;
735 font->glyphnames[i] = c2;
738 r1 = font->layout->bounds[i];
739 r2 = font->layout->bounds[j];
740 font->layout->bounds[j] = r1;
741 font->layout->bounds[i] = r2;
745 newpos = rfx_alloc(sizeof(int) * font->numchars);
746 for (i = 0; i < font->numchars; i++) {
747 newpos[newplace[i]] = i;
749 for (i = 0; i < font->maxascii; i++) {
750 if (font->ascii2glyph[i] >= 0)
751 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
758 void swf_FontPrepareForEditText(SWFFONT * font)
761 swf_FontCreateLayout(font);
765 int swf_FontInitUsage(SWFFONT * f)
770 fprintf(stderr, "Usage initialized twice");
773 f->use = rfx_alloc(sizeof(FONTUSAGE));
774 f->use->is_reduced = 0;
775 f->use->chars = rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
779 void swf_FontClearUsage(SWFFONT * f)
783 rfx_free(f->use->chars); f->use->chars = 0;
784 rfx_free(f->use); f->use = 0;
787 int swf_FontUse(SWFFONT * f, U8 * s)
792 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
793 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
799 int swf_FontUseGlyph(SWFFONT * f, int glyph)
802 swf_FontInitUsage(f);
803 if(glyph < 0 || glyph >= f->numchars)
805 if(!f->use->chars[glyph])
806 f->use->used_glyphs++;
807 f->use->chars[glyph] = 1;
811 int swf_FontSetDefine(TAG * t, SWFFONT * f)
813 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
818 swf_ResetWriteBits(t);
819 swf_SetU16(t, f->id);
823 for (i = 0; i < f->numchars; i++)
824 if (f->glyph[i].shape) {
826 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
829 for (i = 0; i < j; i++)
830 swf_SetU16(t, ofs[i] + j * 2);
832 fprintf(stderr, "rfxswf: warning: Font is empty\n");
836 for (i = 0; i < f->numchars; i++)
837 if (f->glyph[i].shape)
838 swf_SetSimpleShape(t, f->glyph[i].shape);
840 swf_ResetWriteBits(t);
845 static inline int fontSize(SWFFONT * font)
849 for (t = 0; t < font->numchars; t++) {
851 if(font->glyph[t].shape)
852 l = (font->glyph[t].shape->bitlen + 7) / 8;
857 return size + (font->numchars + 1) * 2;
860 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
866 swf_SetU16(tag, f->id);
868 if (f->layout) flags |= 128; // haslayout
869 if (f->numchars > 256)
870 flags |= 4; // widecodes
871 if (f->style & FONT_STYLE_BOLD)
873 if (f->style & FONT_STYLE_ITALIC)
874 flags |= 2; // italic
875 if (f->maxascii >= 256)
876 flags |= 4; //wide codecs
877 if (fontSize(f) > 65535)
878 flags |= 8; //wide offsets
879 flags |= 8 | 4; //FIXME: the above check doesn't work
881 if (f->encoding & FONT_ENCODING_ANSI)
883 if (f->encoding & FONT_ENCODING_UNICODE)
884 flags |= 32; // unicode
885 if (f->encoding & FONT_ENCODING_SHIFTJIS)
886 flags |= 64; // shiftjis
888 swf_SetU8(tag, flags);
889 swf_SetU8(tag, 0); //reserved flags
892 swf_SetU8(tag, strlen(f->name));
893 swf_SetBlock(tag, f->name, strlen(f->name));
895 /* font name (="") */
898 /* number of glyphs */
899 swf_SetU16(tag, f->numchars);
900 /* font offset table */
902 for (t = 0; t <= f->numchars; t++) {
904 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
906 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
909 for (t = 0; t <= f->numchars; t++) {
911 tag->data[pos + t * 4] = (tag->len - pos);
912 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
913 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
914 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
916 if (tag->len - pos > 65535) {
917 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
920 tag->data[pos + t * 2] = (tag->len - pos);
921 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
923 if (t < f->numchars) {
924 if(f->glyph[t].shape) {
925 swf_SetSimpleShape(tag, f->glyph[t].shape);
927 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
933 /* font code table */
934 for (t = 0; t < f->numchars; t++) {
935 if (flags & 4) { /* wide codes */
936 if(f->glyph2ascii[t]) {
937 swf_SetU16(tag, f->glyph2ascii[t]);
942 if(f->glyph2ascii[t]) {
943 swf_SetU8(tag, f->glyph2ascii[t]);
951 swf_SetU16(tag, f->layout->ascent);
952 swf_SetU16(tag, f->layout->descent);
953 swf_SetU16(tag, f->layout->leading);
954 for (t = 0; t < f->numchars; t++)
955 swf_SetU16(tag, f->glyph[t].advance);
956 for (t = 0; t < f->numchars; t++) {
957 swf_ResetWriteBits(tag);
958 swf_SetRect(tag, &f->layout->bounds[t]);
960 swf_SetU16(tag, f->layout->kerningcount);
961 for (t = 0; t < f->layout->kerningcount; t++) {
962 if (flags & 4) { /* wide codes */
963 swf_SetU16(tag, f->layout->kerning[t].char1);
964 swf_SetU16(tag, f->layout->kerning[t].char2);
966 swf_SetU8(tag, f->layout->kerning[t].char1);
967 swf_SetU8(tag, f->layout->kerning[t].char2);
969 swf_SetU16(tag, f->layout->kerning[t].adjustment);
975 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
977 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
978 f->layout->ascent = ascent;
979 f->layout->descent = descent;
980 f->layout->leading = leading;
981 f->layout->kerningcount = 0;
982 f->layout->kerning = 0;
983 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
986 int swf_FontSetInfo(TAG * t, SWFFONT * f)
993 swf_ResetWriteBits(t);
994 swf_SetU16(t, f->id);
995 l = f->name ? strlen(f->name) : 0;
1000 swf_SetBlock(t, f->name, l);
1001 if (f->numchars >= 256)
1004 if (f->style & FONT_STYLE_BOLD)
1006 if (f->style & FONT_STYLE_ITALIC)
1008 if (f->style & FONT_ENCODING_ANSI)
1010 if (f->style & FONT_ENCODING_SHIFTJIS)
1012 if (f->style & FONT_ENCODING_UNICODE)
1015 swf_SetU8(t, (flags & 0xfe) | wide);
1017 for (i = 0; i < f->numchars; i++) {
1018 if (f->glyph[i].shape) {
1019 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1020 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1027 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1029 int id = swf_GetTagID(t);
1030 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1031 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1037 void swf_FontFree(SWFFONT * f)
1045 for (i = 0; i < f->numchars; i++)
1046 if (f->glyph[i].shape)
1048 swf_ShapeFree(f->glyph[i].shape);
1049 f->glyph[i].shape = NULL;
1056 rfx_free(f->ascii2glyph);
1057 f->ascii2glyph = NULL;
1061 rfx_free(f->glyph2ascii);
1062 f->glyph2ascii = NULL;
1066 font_freeglyphnames(f);
1072 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1078 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1079 | (dy ? TF_HASYOFFSET : 0);
1081 swf_SetU8(t, flags);
1083 swf_SetU16(t, font->id);
1085 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1086 swf_SetRGBA(t, color);
1088 swf_SetRGB(t, color);
1091 if(dx != SET_TO_ZERO) {
1092 if(dx>32767 || dx<-32768)
1093 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1100 if(dy != SET_TO_ZERO) {
1101 if(dy>32767 || dy<-32768)
1102 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1109 swf_SetU16(t, size);
1114 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1118 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1122 if (!strcmp(encoding, "UTF8"))
1124 else if (!strcmp(encoding, "iso-8859-1"))
1127 fprintf(stderr, "Unknown encoding: %s", encoding);
1135 c = readUTF8char(&s);
1137 if (c < font->maxascii)
1138 glyph = font->ascii2glyph[c];
1140 g = swf_CountUBits(glyph, g);
1141 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1152 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1157 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1160 if (!strcmp(encoding, "UTF8"))
1162 else if (!strcmp(encoding, "iso-8859-1"))
1165 fprintf(stderr, "Unknown encoding: %s", encoding);
1168 swf_SetU8(t, l); //placeholder
1176 c = readUTF8char(&s);
1178 if (c < font->maxascii)
1179 g = font->ascii2glyph[c];
1181 swf_SetBits(t, g, gbits);
1182 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1184 /* We split into 127 characters per text field.
1185 We could do 255, by the (formerly wrong) flash specification,
1186 but some SWF parsing code out there still assumes that char blocks
1187 are at max 127 characters, and it would save only a few bits.
1194 PUT8(&t->data[pos], l);
1196 swf_ResetWriteBits(t);
1200 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1202 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1205 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1207 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1210 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1212 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1215 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1217 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1220 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1227 if (*s < font->maxascii)
1228 g = font->ascii2glyph[*s];
1230 res += font->glyph[g].advance / 20;
1234 res = (res * scale) / 100;
1239 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1246 int c = readUTF8char(&s);
1247 if(c==13 || c==10) {
1252 ypos+=font->layout->leading;
1255 if (c < font->maxascii) {
1256 int g = font->ascii2glyph[c];
1258 SRECT rn = font->layout->bounds[g];
1259 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1260 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1261 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1262 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1263 swf_ExpandRect2(&r, &rn);
1264 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1272 SWFFONT *swf_ReadFont(char *filename)
1278 f = open(filename, O_RDONLY|O_BINARY);
1280 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1281 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1287 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1294 void swf_WriteFont(SWFFONT * font, char *filename)
1301 int useDefineFont2 = 0;
1302 int storeGlyphNames = 1;
1305 useDefineFont2 = 1; /* the only thing new in definefont2
1306 is layout information. */
1308 font->id = WRITEFONTID; //"FN"
1310 memset(&swf, 0x00, sizeof(SWF));
1312 swf.fileVersion = 4;
1313 swf.frameRate = 0x4000;
1315 /* if we use DefineFont1 to store the characters,
1316 we have to build a textfield to store the
1317 advance values. While at it, we can also
1318 make the whole .swf viewable */
1320 /* we now always create viewable swfs, even if we
1321 did use definefont2 -mk */
1322 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1327 swf_SetRGB(t, &rgb);
1328 if (!useDefineFont2) {
1329 t = swf_InsertTag(t, ST_DEFINEFONT);
1330 swf_FontSetDefine(t, font);
1331 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1332 swf_FontSetInfo(t, font);
1334 t = swf_InsertTag(t, ST_DEFINEFONT2);
1335 swf_FontSetDefine2(t, font);
1338 if (storeGlyphNames && font->glyphnames) {
1340 t = swf_InsertTag(t, ST_GLYPHNAMES);
1341 swf_SetU16(t, WRITEFONTID);
1342 swf_SetU16(t, font->numchars);
1343 for (c = 0; c < font->numchars; c++) {
1344 if (font->glyphnames[c])
1345 swf_SetString(t, font->glyphnames[c]);
1347 swf_SetString(t, "");
1351 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1353 int textscale = 400;
1360 int range = font->maxascii;
1363 if (useDefineFont2 && range > 256) {
1367 for (s = 0; s < range; s++) {
1368 int g = font->ascii2glyph[s];
1370 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1371 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1375 if ((s & 15) == 0) {
1382 ymax = ypos * textscale * 2;
1384 swf.movieSize.xmax = xmax * 20;
1385 swf.movieSize.ymax = ymax;
1387 t = swf_InsertTag(t, ST_DEFINETEXT);
1389 swf_SetU16(t, font->id + 1); // ID
1393 r.xmax = swf.movieSize.xmax;
1394 r.ymax = swf.movieSize.ymax;
1398 swf_SetMatrix(t, NULL);
1400 abits = swf_CountBits(xmax * 16, 0);
1403 swf_SetU8(t, gbits);
1404 swf_SetU8(t, abits);
1410 for (y = 0; y < ((range + 15) / 16); y++) {
1411 int c = 0, lastx = -1;
1412 for (x = 0; x < 16; x++) {
1413 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1414 if (g >= 0 && font->glyph[g].shape) {
1421 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1422 for (x = 0; x < 16; x++) {
1423 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1424 if (g >= 0 && font->glyph[g].shape) {
1425 if (lastx != x * xmax) {
1426 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1429 swf_SetBits(t, g, gbits);
1430 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1431 lastx = x * xmax + (font->glyph[g].advance / 20);
1432 swf_ResetWriteBits(t);
1441 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1443 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1445 t = swf_InsertTag(t, ST_SHOWFRAME);
1449 t = swf_InsertTag(t, ST_END);
1451 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1453 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1460 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1462 swf_SetRect(tag, &r);
1463 swf_ResetWriteBits(tag);
1465 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1467 flags |= ET_HASTEXT;
1469 flags |= ET_HASTEXTCOLOR;
1471 flags |= ET_HASMAXLENGTH;
1473 flags |= ET_HASFONT;
1475 flags |= ET_HASLAYOUT;
1477 swf_SetBits(tag, flags, 16);
1479 if (flags & ET_HASFONT) {
1480 swf_SetU16(tag, font); //font
1481 swf_SetU16(tag, height); //fontheight
1483 if (flags & ET_HASTEXTCOLOR) {
1484 swf_SetRGBA(tag, color);
1486 if (flags & ET_HASMAXLENGTH) {
1487 swf_SetU16(tag, maxlength); //maxlength
1489 if (flags & ET_HASLAYOUT) {
1490 swf_SetU8(tag, layout->align); //align
1491 swf_SetU16(tag, layout->leftmargin); //left margin
1492 swf_SetU16(tag, layout->rightmargin); //right margin
1493 swf_SetU16(tag, layout->indent); //indent
1494 swf_SetU16(tag, layout->leading); //leading
1496 swf_SetString(tag, variable);
1497 if (flags & ET_HASTEXT)
1498 swf_SetString(tag, text);
1501 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1505 U8 *utext = (U8 *) strdup(text);
1511 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1512 ystep = font->layout->leading;
1514 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1515 /* Hm, without layout information, we can't compute a bounding
1516 box. We could call swf_FontCreateLayout to create a layout,
1517 but the caller probably doesn't want us to mess up his font
1520 r.xmin = r.ymin = 0;
1521 r.xmax = r.ymax = 1024 * 20;
1525 swf_SetRect(tag, &r);
1527 /* The text matrix is pretty boring, as it doesn't apply to
1528 individual characters, but rather whole text objects (or
1529 at least whole char records- haven't tested).
1530 So it can't do anything which we can't already do with
1531 the placeobject tag we use for placing the text on the scene.
1533 swf_SetMatrix(tag, 0);
1535 swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1536 swf_SetU8(tag, gbits);
1537 swf_SetU8(tag, abits);
1543 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1546 while(*next && *next!=13 && *next!=10 && count<127) {
1547 readUTF8char(&next);
1550 if(next[0] == 13 || next[0] == 10) {
1555 if(next[0] == 13 && next[1] == 10)
1558 if(next[0] == 13 || next[0] == 10) {
1563 /* now set the text params- notice that a font size of
1564 1024 means that the glyphs will be displayed exactly
1565 as they would be in/with a defineshape. (Try to find
1566 *that* in the flash specs)
1568 /* set the actual text- notice that we just pass our scale
1569 parameter over, as TextSetCharRecord calculates with
1571 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1581 void swf_FontCreateLayout(SWFFONT * f)
1590 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1591 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1592 f->layout->ascent = -32767;
1593 f->layout->descent = -32767;
1595 for (t = 0; t < f->numchars; t++) {
1599 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1601 fprintf(stderr, "Shape parse error\n");
1604 bbox = swf_GetShapeBoundingBox(shape2);
1605 swf_Shape2Free(shape2);
1606 f->layout->bounds[t] = bbox;
1608 width = (bbox.xmax);
1610 /* The following is a heuristic- it may be that extractfont_DefineText
1611 has already found out some widths for individual characters (from the way
1612 they are used)- we now have to guess whether that width might be possible,
1613 which is the case if it isn't either much too big or much too small */
1614 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1615 f->glyph[t].advance = width;
1617 if (-bbox.ymin > f->layout->ascent)
1618 f->layout->ascent = bbox.ymin;
1619 if (bbox.ymax > f->layout->descent)
1620 f->layout->descent = bbox.ymax;
1624 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1626 U8 *s = (U8 *) text;
1632 U32 c = readUTF8char(&s);
1633 int g = font->ascii2glyph[c];
1634 shape = font->glyph[g].shape;
1635 if (((int) g) < 0) {
1636 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1639 shape2 = swf_ShapeToShape2(shape);
1642 if (l->type == moveTo) {
1644 to.x = l->x * size / 100.0 / 20.0 + advance;
1645 to.y = l->y * size / 100.0 / 20.0;
1646 draw->moveTo(draw, &to);
1647 } else if (l->type == lineTo) {
1649 to.x = l->x * size / 100.0 / 20.0 + advance;
1650 to.y = l->y * size / 100.0 / 20.0;
1651 draw->lineTo(draw, &to);
1652 } else if (l->type == splineTo) {
1654 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1655 mid.y = l->sy * size / 100.0 / 20.0;
1656 to.x = l->x * size / 100.0 / 20.0 + advance;
1657 to.y = l->y * size / 100.0 / 20.0;
1658 draw->splineTo(draw, &mid, &to);
1662 swf_Shape2Free(shape2);
1663 advance += font->glyph[g].advance * size / 100.0 / 20.0;