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 = (SWFGLYPH*)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)
241 swf_SetTagPos(tag, 0);
243 fid = swf_GetU16(tag);
246 int num = swf_GetU16(tag);
248 f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num);
249 for (t = 0; t < num; t++) {
250 f->glyphnames[t] = strdup(swf_GetString(tag));
254 swf_RestoreTagPos(tag);
259 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
266 U8 flags1, flags2, namelen;
268 swf_SetTagPos(tag, 0);
270 fid = swf_GetU16(tag);
274 flags1 = swf_GetU8(tag);
275 flags2 = swf_GetU8(tag); //reserved flags
278 font->style |= FONT_STYLE_BOLD;
280 font->style |= FONT_STYLE_ITALIC;
282 font->encoding |= FONT_ENCODING_ANSI;
284 font->encoding |= FONT_ENCODING_UNICODE;
286 font->encoding |= FONT_ENCODING_SHIFTJIS;
288 namelen = swf_GetU8(tag);
289 font->name = (U8 *) rfx_alloc(namelen + 1);
290 font->name[namelen] = 0;
291 swf_GetBlock(tag, font->name, namelen);
293 glyphcount = swf_GetU16(tag);
294 font->numchars = glyphcount;
296 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
297 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
299 offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
300 offset_start = tag->pos;
302 if (flags1 & 8) { // wide offsets
303 for (t = 0; t < glyphcount; t++)
304 offset[t] = swf_GetU32(tag); //offset[t]
306 if (glyphcount) /* this _if_ is not in the specs */
307 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
309 offset[glyphcount] = tag->pos;
311 for (t = 0; t < glyphcount; t++)
312 offset[t] = swf_GetU16(tag); //offset[t]
314 if (glyphcount) /* this _if_ is not in the specs */
315 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
317 offset[glyphcount] = tag->pos;
319 for (t = 0; t < glyphcount; t++) {
320 swf_SetTagPos(tag, offset[t]+offset_start);
321 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
324 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
329 for (t = 0; t < glyphcount; t++) {
331 if (flags1 & 4) // wide codes
332 code = swf_GetU16(tag);
334 code = swf_GetU8(tag);
335 font->glyph2ascii[t] = code;
342 font->maxascii = maxcode;
343 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
344 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
345 for (t = 0; t < glyphcount; t++) {
346 font->ascii2glyph[font->glyph2ascii[t]] = t;
349 if (flags1 & 128) { // has layout
351 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
352 font->layout->ascent = swf_GetU16(tag);
353 font->layout->descent = swf_GetU16(tag);
354 font->layout->leading = swf_GetU16(tag);
355 for (t = 0; t < glyphcount; t++) {
356 S16 advance = swf_GetS16(tag);
357 font->glyph[t].advance = advance;
359 font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
360 for (t = 0; t < glyphcount; t++) {
361 swf_ResetReadBits(tag);
362 swf_GetRect(tag, &font->layout->bounds[t]);
365 kerningcount = swf_GetU16(tag);
366 font->layout->kerningcount = kerningcount;
368 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
370 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
371 for (t = 0; t < kerningcount; t++) {
372 if (flags1 & 4) { // wide codes
373 font->layout->kerning[t].char1 = swf_GetU16(tag);
374 font->layout->kerning[t].char2 = swf_GetU16(tag);
376 font->layout->kerning[t].char1 = swf_GetU8(tag);
377 font->layout->kerning[t].char2 = swf_GetU8(tag);
379 font->layout->kerning[t].adjustment = swf_GetS16(tag);
383 swf_RestoreTagPos(t);
388 #define FEDTJ_PRINT 0x01
389 #define FEDTJ_MODIFY 0x02
390 #define FEDTJ_CALLBACK 0x04
393 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
394 void (*callback) (void *self,
395 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
406 memset(&color, 0, sizeof(color));
413 swf_GetMatrix(t, &m);
414 gbits = swf_GetU8(t);
415 abits = swf_GetU8(t);
419 flags = swf_GetU8(t);
423 if (flags & TF_TEXTCONTROL) {
424 if (flags & TF_HASFONT)
426 if (flags & TF_HASCOLOR) {
427 color.r = swf_GetU8(t); // rgb
428 color.g = swf_GetU8(t);
429 color.b = swf_GetU8(t);
430 if (swf_GetTagID(t) == ST_DEFINETEXT2)
431 color.a = swf_GetU8(t);
435 if (flags & TF_HASXOFFSET)
437 if (flags & TF_HASYOFFSET)
439 if (flags & TF_HASFONT)
440 fontsize = swf_GetU16(t);
452 for (i = 0; i < num; i++) {
456 glyph = swf_GetBits(t, gbits);
457 adv = swf_GetBits(t, abits);
461 if (jobs & FEDTJ_PRINT) {
462 int code = f->glyph2ascii[glyph];
465 if (jobs & FEDTJ_MODIFY)
466 f->glyph[glyph].advance = adv * 20; //?
471 if ((id == fid) && (jobs & FEDTJ_PRINT))
473 if (jobs & FEDTJ_CALLBACK)
474 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
479 swf_RestoreTagPos(t);
483 int swf_ParseDefineText(TAG * tag,
484 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
486 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
489 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
491 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
494 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
499 if ((!swf) || (!font))
502 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
508 switch (swf_GetTagID(t)) {
510 nid = swf_FontExtract_DefineFont(id, f, t);
514 nid = swf_FontExtract_DefineFont2(id, f, t);
517 case ST_DEFINEFONTINFO:
518 case ST_DEFINEFONTINFO2:
519 nid = swf_FontExtract_DefineFontInfo(id, f, t);
524 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
528 nid = swf_FontExtract_GlyphNames(id, f, t);
543 int swf_FontSetID(SWFFONT * f, U16 id)
551 void swf_LayoutFree(SWFLAYOUT * l)
555 rfx_free(l->kerning);
565 static void font_freeglyphnames(SWFFONT*f)
570 for (t = 0; t < f->numchars; t++)
572 if (f->glyphnames[t])
574 rfx_free(f->glyphnames[t]);
575 f->glyphnames[t] = 0;
578 rfx_free(f->glyphnames);
582 static void font_freeusage(SWFFONT*f)
586 rfx_free(f->use->chars);f->use->chars = 0;
588 rfx_free(f->use); f->use = 0;
591 static void font_freelayout(SWFFONT*f)
594 swf_LayoutFree(f->layout);
598 static void font_freename(SWFFONT*f)
606 int swf_FontReduce_old(SWFFONT * f)
610 if ((!f) || (!f->use) || f->use->is_reduced)
615 for (i = 0; i < f->numchars; i++) {
616 if (f->glyph[i].shape && f->use->chars[i]) {
617 f->glyph2ascii[j] = f->glyph2ascii[i];
618 f->glyph[j] = f->glyph[i];
619 f->use->chars[i] = j;
622 f->glyph2ascii[i] = 0;
623 if(f->glyph[i].shape) {
624 swf_ShapeFree(f->glyph[i].shape);
625 f->glyph[i].shape = 0;
626 f->glyph[i].advance = 0;
628 f->use->chars[i] = -1;
632 for (i = 0; i < f->maxascii; i++) {
633 if(f->use->chars[f->ascii2glyph[i]]<0) {
634 f->ascii2glyph[i] = -1;
636 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
640 f->maxascii = max_unicode;
641 f->use->is_reduced = 1;
644 font_freeglyphnames(f);
649 int swf_FontReduce_swfc(SWFFONT * f)
653 if ((!f) || (!f->use) || f->use->is_reduced)
656 font_freeglyphnames(f);
659 for (i = 0; i < f->numchars; i++) {
660 if (f->glyph[i].shape && f->use->chars[i]) {
661 f->glyph2ascii[j] = f->glyph2ascii[i];
663 f->layout->bounds[j] = f->layout->bounds[i];
664 f->glyph[j] = f->glyph[i];
665 f->use->chars[i] = j;
668 f->glyph2ascii[i] = 0;
669 if(f->glyph[i].shape) {
670 swf_ShapeFree(f->glyph[i].shape);
671 f->glyph[i].shape = 0;
672 f->glyph[i].advance = 0;
674 f->use->chars[i] = -1;
677 f->use->used_glyphs = j;
678 for (i = 0; i < f->maxascii; i++) {
679 if(f->ascii2glyph[i] > -1) {
680 if (f->use->chars[f->ascii2glyph[i]]<0) {
681 f->use->chars[f->ascii2glyph[i]] = 0;
682 f->ascii2glyph[i] = -1;
684 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
685 f->use->chars[f->ascii2glyph[i]] = 1;
690 f->maxascii = max_unicode;
691 f->use->is_reduced = 1;
697 int swf_FontReduce(SWFFONT * f)
702 if ((!f) || (!f->use) || f->use->is_reduced)
706 font_freeglyphnames(f);
708 f->use->used_glyphs= 0;
709 for (i = 0; i < f->numchars; i++) {
710 if(!f->use->chars[i]) {
712 f->glyph2ascii[i] = 0;
714 if(f->glyph[i].shape) {
715 swf_ShapeFree(f->glyph[i].shape);
716 f->glyph[i].shape = 0;
717 f->glyph[i].advance = 0;
719 // f->use->used_glyphs++;
721 f->use->used_glyphs++;
725 for (i = 0; i < f->maxascii; i++) {
726 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
728 f->ascii2glyph[i] = -1;
734 f->maxascii = max_unicode;
735 f->numchars = max_glyph;
740 void swf_FontSort(SWFFONT * font)
748 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
750 for (i = 0; i < font->numchars; i++) {
753 for (i = 0; i < font->numchars; i++)
754 for (j = 0; j < i; j++) {
755 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
764 n1 = font->glyph2ascii[i];
765 n2 = font->glyph2ascii[j];
766 font->glyph2ascii[j] = n1;
767 font->glyph2ascii[i] = n2;
772 if (font->glyphnames) {
773 c1 = font->glyphnames[i];
774 c2 = font->glyphnames[j];
775 font->glyphnames[j] = c1;
776 font->glyphnames[i] = c2;
779 r1 = font->layout->bounds[i];
780 r2 = font->layout->bounds[j];
781 font->layout->bounds[j] = r1;
782 font->layout->bounds[i] = r2;
786 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
787 for (i = 0; i < font->numchars; i++) {
788 newpos[newplace[i]] = i;
790 for (i = 0; i < font->maxascii; i++) {
791 if (font->ascii2glyph[i] >= 0)
792 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
799 void swf_FontPrepareForEditText(SWFFONT * font)
802 swf_FontCreateLayout(font);
806 int swf_FontInitUsage(SWFFONT * f)
811 fprintf(stderr, "Usage initialized twice");
814 f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
815 f->use->is_reduced = 0;
816 f->use->used_glyphs = 0;
817 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
821 void swf_FontClearUsage(SWFFONT * f)
825 rfx_free(f->use->chars); f->use->chars = 0;
826 rfx_free(f->use); f->use = 0;
829 int swf_FontUse(SWFFONT * f, U8 * s)
834 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
835 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
841 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
848 ascii = readUTF8char(&s);
849 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
850 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
855 int swf_FontUseAll(SWFFONT* f)
860 swf_FontInitUsage(f);
861 for (i = 0; i < f->numchars; i++)
862 f->use->chars[i] = 1;
863 f->use->used_glyphs = f->numchars;
867 int swf_FontUseGlyph(SWFFONT * f, int glyph)
870 swf_FontInitUsage(f);
871 if(glyph < 0 || glyph >= f->numchars)
873 if(!f->use->chars[glyph])
874 f->use->used_glyphs++;
875 f->use->chars[glyph] = 1;
879 int swf_FontSetDefine(TAG * t, SWFFONT * f)
881 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
886 swf_ResetWriteBits(t);
887 swf_SetU16(t, f->id);
891 for (i = 0; i < f->numchars; i++)
892 if (f->glyph[i].shape) {
894 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
897 for (i = 0; i < j; i++)
898 swf_SetU16(t, ofs[i] + j * 2);
900 fprintf(stderr, "rfxswf: warning: Font is empty\n");
904 for (i = 0; i < f->numchars; i++)
905 if (f->glyph[i].shape)
906 swf_SetSimpleShape(t, f->glyph[i].shape);
908 swf_ResetWriteBits(t);
913 static inline int fontSize(SWFFONT * font)
917 for (t = 0; t < font->numchars; t++) {
919 if(font->glyph[t].shape)
920 l = (font->glyph[t].shape->bitlen + 7) / 8;
925 return size + (font->numchars + 1) * 2;
928 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
933 swf_SetU16(tag, f->id);
935 if (f->layout) flags |= 128; // haslayout
936 if (f->numchars > 256)
937 flags |= 4; // widecodes
938 if (f->style & FONT_STYLE_BOLD)
940 if (f->style & FONT_STYLE_ITALIC)
941 flags |= 2; // italic
942 if (f->maxascii >= 256)
943 flags |= 4; //wide codecs
944 if (fontSize(f) > 65535)
945 flags |= 8; //wide offsets
946 flags |= 8 | 4; //FIXME: the above check doesn't work
948 if (f->encoding & FONT_ENCODING_ANSI)
950 if (f->encoding & FONT_ENCODING_UNICODE)
951 flags |= 32; // unicode
952 if (f->encoding & FONT_ENCODING_SHIFTJIS)
953 flags |= 64; // shiftjis
955 swf_SetU8(tag, flags);
956 swf_SetU8(tag, 0); //reserved flags
959 swf_SetU8(tag, strlen((const char*)f->name));
960 swf_SetBlock(tag, f->name, strlen((const char*)f->name));
962 /* font name (="") */
965 /* number of glyphs */
966 swf_SetU16(tag, f->numchars);
967 /* font offset table */
969 for (t = 0; t <= f->numchars; t++) {
971 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
973 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
976 for (t = 0; t <= f->numchars; t++) {
978 tag->data[pos + t * 4] = (tag->len - pos);
979 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
980 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
981 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
983 if (tag->len - pos > 65535) {
984 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
987 tag->data[pos + t * 2] = (tag->len - pos);
988 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
990 if (t < f->numchars) {
991 if(f->glyph[t].shape) {
992 swf_SetSimpleShape(tag, f->glyph[t].shape);
994 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1000 /* font code table */
1001 for (t = 0; t < f->numchars; t++) {
1002 if (flags & 4) { /* wide codes */
1003 if(f->glyph2ascii[t]) {
1004 swf_SetU16(tag, f->glyph2ascii[t]);
1009 if(f->glyph2ascii[t]) {
1010 swf_SetU8(tag, f->glyph2ascii[t]);
1018 swf_SetU16(tag, f->layout->ascent);
1019 swf_SetU16(tag, f->layout->descent);
1020 swf_SetU16(tag, f->layout->leading);
1021 for (t = 0; t < f->numchars; t++)
1022 swf_SetU16(tag, f->glyph[t].advance);
1023 for (t = 0; t < f->numchars; t++) {
1024 swf_ResetWriteBits(tag);
1025 swf_SetRect(tag, &f->layout->bounds[t]);
1027 swf_SetU16(tag, f->layout->kerningcount);
1028 for (t = 0; t < f->layout->kerningcount; t++) {
1029 if (flags & 4) { /* wide codes */
1030 swf_SetU16(tag, f->layout->kerning[t].char1);
1031 swf_SetU16(tag, f->layout->kerning[t].char2);
1033 swf_SetU8(tag, f->layout->kerning[t].char1);
1034 swf_SetU8(tag, f->layout->kerning[t].char2);
1036 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1042 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1044 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1045 f->layout->ascent = ascent;
1046 f->layout->descent = descent;
1047 f->layout->leading = leading;
1048 f->layout->kerningcount = 0;
1049 f->layout->kerning = 0;
1050 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1053 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1060 swf_ResetWriteBits(t);
1061 swf_SetU16(t, f->id);
1062 l = f->name ? strlen((const char *)f->name) : 0;
1067 swf_SetBlock(t, f->name, l);
1068 if (f->numchars >= 256)
1071 if (f->style & FONT_STYLE_BOLD)
1073 if (f->style & FONT_STYLE_ITALIC)
1075 if (f->style & FONT_ENCODING_ANSI)
1077 if (f->style & FONT_ENCODING_SHIFTJIS)
1079 if (f->style & FONT_ENCODING_UNICODE)
1082 swf_SetU8(t, (flags & 0xfe) | wide);
1084 for (i = 0; i < f->numchars; i++) {
1085 if (f->glyph[i].shape) {
1086 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1087 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1094 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1096 int id = swf_GetTagID(t);
1097 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1098 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1104 void swf_FontFree(SWFFONT * f)
1112 for (i = 0; i < f->numchars; i++)
1113 if (f->glyph[i].shape)
1115 swf_ShapeFree(f->glyph[i].shape);
1116 f->glyph[i].shape = NULL;
1123 rfx_free(f->ascii2glyph);
1124 f->ascii2glyph = NULL;
1128 rfx_free(f->glyph2ascii);
1129 f->glyph2ascii = NULL;
1133 font_freeglyphnames(f);
1139 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1145 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1146 | (y ? TF_HASYOFFSET : 0);
1148 swf_SetU8(t, flags);
1150 swf_SetU16(t, font->id);
1152 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1153 swf_SetRGBA(t, color);
1155 swf_SetRGB(t, color);
1158 if(x != SET_TO_ZERO) {
1159 if(x>32767 || x<-32768)
1160 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1167 if(y != SET_TO_ZERO) {
1168 if(y>32767 || y<-32768)
1169 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1176 swf_SetU16(t, size);
1181 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1185 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1189 if (!strcmp(encoding, "UTF8"))
1191 else if (!strcmp(encoding, "iso-8859-1"))
1194 fprintf(stderr, "Unknown encoding: %s", encoding);
1202 c = readUTF8char(&s);
1204 if (c < font->maxascii)
1205 glyph = font->ascii2glyph[c];
1207 g = swf_CountUBits(glyph, g);
1208 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1219 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1224 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1227 if (!strcmp(encoding, "UTF8"))
1229 else if (!strcmp(encoding, "iso-8859-1"))
1232 fprintf(stderr, "Unknown encoding: %s", encoding);
1235 swf_SetU8(t, l); //placeholder
1243 c = readUTF8char(&s);
1245 if (c < font->maxascii)
1246 g = font->ascii2glyph[c];
1248 swf_SetBits(t, g, gbits);
1249 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1251 /* We split into 127 characters per text field.
1252 We could do 255, by the (formerly wrong) flash specification,
1253 but some SWF parsing code out there still assumes that char blocks
1254 are at max 127 characters, and it would save only a few bits.
1261 PUT8(&t->data[pos], l);
1263 swf_ResetWriteBits(t);
1267 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1269 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1272 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1274 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1277 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1279 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1282 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1284 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1287 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1294 if (*s < font->maxascii)
1295 g = font->ascii2glyph[*s];
1297 res += font->glyph[g].advance / 20;
1301 res = (res * scale) / 100;
1306 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1313 int c = readUTF8char(&s);
1314 if(c==13 || c==10) {
1319 ypos+=font->layout->leading;
1322 if (c < font->maxascii) {
1323 int g = font->ascii2glyph[c];
1325 SRECT rn = font->layout->bounds[g];
1326 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1327 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1328 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1329 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1330 swf_ExpandRect2(&r, &rn);
1331 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1339 SWFFONT *swf_ReadFont(char *filename)
1345 f = open(filename, O_RDONLY|O_BINARY);
1347 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1348 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1354 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1361 void swf_WriteFont(SWFFONT * font, char *filename)
1368 int useDefineFont2 = 0;
1369 int storeGlyphNames = 1;
1372 useDefineFont2 = 1; /* the only thing new in definefont2
1373 is layout information. */
1375 font->id = WRITEFONTID; //"FN"
1377 memset(&swf, 0x00, sizeof(SWF));
1379 swf.fileVersion = 4;
1380 swf.frameRate = 0x4000;
1382 /* if we use DefineFont1 to store the characters,
1383 we have to build a textfield to store the
1384 advance values. While at it, we can also
1385 make the whole .swf viewable */
1387 /* we now always create viewable swfs, even if we
1388 did use definefont2 -mk */
1389 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1394 swf_SetRGB(t, &rgb);
1395 if (!useDefineFont2) {
1396 t = swf_InsertTag(t, ST_DEFINEFONT);
1397 swf_FontSetDefine(t, font);
1398 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1399 swf_FontSetInfo(t, font);
1401 t = swf_InsertTag(t, ST_DEFINEFONT2);
1402 swf_FontSetDefine2(t, font);
1405 if (storeGlyphNames && font->glyphnames) {
1407 t = swf_InsertTag(t, ST_GLYPHNAMES);
1408 swf_SetU16(t, WRITEFONTID);
1409 swf_SetU16(t, font->numchars);
1410 for (c = 0; c < font->numchars; c++) {
1411 if (font->glyphnames[c])
1412 swf_SetString(t, (U8*)font->glyphnames[c]);
1414 swf_SetString(t, (U8*)"");
1418 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1420 int textscale = 400;
1427 int range = font->maxascii;
1430 if (useDefineFont2 && range > 256) {
1434 for (s = 0; s < range; s++) {
1435 int g = font->ascii2glyph[s];
1437 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1438 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1442 if ((s & 15) == 0) {
1449 ymax = ypos * textscale * 2;
1451 swf.movieSize.xmax = xmax * 20;
1452 swf.movieSize.ymax = ymax;
1454 t = swf_InsertTag(t, ST_DEFINETEXT);
1456 swf_SetU16(t, font->id + 1); // ID
1460 r.xmax = swf.movieSize.xmax;
1461 r.ymax = swf.movieSize.ymax;
1465 swf_SetMatrix(t, NULL);
1467 abits = swf_CountBits(xmax * 16, 0);
1470 swf_SetU8(t, gbits);
1471 swf_SetU8(t, abits);
1477 for (y = 0; y < ((range + 15) / 16); y++) {
1478 int c = 0, lastx = -1;
1479 for (x = 0; x < 16; x++) {
1480 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1481 if (g >= 0 && font->glyph[g].shape) {
1488 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1489 for (x = 0; x < 16; x++) {
1490 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1491 if (g >= 0 && font->glyph[g].shape) {
1492 if (lastx != x * xmax) {
1493 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1496 swf_SetBits(t, g, gbits);
1497 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1498 lastx = x * xmax + (font->glyph[g].advance / 20);
1499 swf_ResetWriteBits(t);
1508 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1510 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1512 t = swf_InsertTag(t, ST_SHOWFRAME);
1516 t = swf_InsertTag(t, ST_END);
1518 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1520 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1527 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1529 swf_SetRect(tag, &r);
1530 swf_ResetWriteBits(tag);
1532 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1534 flags |= ET_HASTEXT;
1536 flags |= ET_HASTEXTCOLOR;
1538 flags |= ET_HASMAXLENGTH;
1540 flags |= ET_HASFONT;
1542 flags |= ET_HASLAYOUT;
1544 swf_SetBits(tag, flags, 16);
1546 if (flags & ET_HASFONT) {
1547 swf_SetU16(tag, font); //font
1548 swf_SetU16(tag, height); //fontheight
1550 if (flags & ET_HASTEXTCOLOR) {
1551 swf_SetRGBA(tag, color);
1553 if (flags & ET_HASMAXLENGTH) {
1554 swf_SetU16(tag, maxlength); //maxlength
1556 if (flags & ET_HASLAYOUT) {
1557 swf_SetU8(tag, layout->align); //align
1558 swf_SetU16(tag, layout->leftmargin); //left margin
1559 swf_SetU16(tag, layout->rightmargin); //right margin
1560 swf_SetU16(tag, layout->indent); //indent
1561 swf_SetU16(tag, layout->leading); //leading
1563 swf_SetString(tag, (U8*)variable);
1564 if (flags & ET_HASTEXT)
1565 swf_SetString(tag, (U8*)text);
1568 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1572 U8 *utext = (U8 *) strdup(text);
1578 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1579 ystep = font->layout->leading;
1581 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1582 /* Hm, without layout information, we can't compute a bounding
1583 box. We could call swf_FontCreateLayout to create a layout,
1584 but the caller probably doesn't want us to mess up his font
1587 r.xmin = r.ymin = 0;
1588 r.xmax = r.ymax = 1024 * 20;
1592 swf_SetRect(tag, &r);
1594 /* The text matrix is pretty boring, as it doesn't apply to
1595 individual characters, but rather whole text objects (or
1596 at least whole char records- haven't tested).
1597 So it can't do anything which we can't already do with
1598 the placeobject tag we use for placing the text on the scene.
1600 swf_SetMatrix(tag, 0);
1602 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1603 swf_SetU8(tag, gbits);
1604 swf_SetU8(tag, abits);
1610 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1613 while(*next && *next!=13 && *next!=10 && count<127) {
1614 readUTF8char(&next);
1617 if(next[0] == 13 || next[0] == 10) {
1622 if(next[0] == 13 && next[1] == 10)
1625 if(next[0] == 13 || next[0] == 10) {
1630 /* now set the text params- notice that a font size of
1631 1024 means that the glyphs will be displayed exactly
1632 as they would be in/with a defineshape. (Try to find
1633 *that* in the flash specs)
1635 /* set the actual text- notice that we just pass our scale
1636 parameter over, as TextSetCharRecord calculates with
1638 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1648 void swf_FontCreateLayout(SWFFONT * f)
1657 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1658 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1659 f->layout->ascent = -32767;
1660 f->layout->descent = -32767;
1662 for (t = 0; t < f->numchars; t++) {
1666 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1668 fprintf(stderr, "Shape parse error\n");
1671 bbox = swf_GetShapeBoundingBox(shape2);
1672 swf_Shape2Free(shape2);
1673 f->layout->bounds[t] = bbox;
1675 width = (bbox.xmax);
1677 /* The following is a heuristic- it may be that extractfont_DefineText
1678 has already found out some widths for individual characters (from the way
1679 they are used)- we now have to guess whether that width might be possible,
1680 which is the case if it isn't either much too big or much too small */
1681 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1682 f->glyph[t].advance = width;
1684 if (-bbox.ymin > f->layout->ascent)
1685 f->layout->ascent = bbox.ymin;
1686 if (bbox.ymax > f->layout->descent)
1687 f->layout->descent = bbox.ymax;
1691 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1693 U8 *s = (U8 *) text;
1699 U32 c = readUTF8char(&s);
1700 int g = font->ascii2glyph[c];
1701 shape = font->glyph[g].shape;
1702 if (((int) g) < 0) {
1703 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1706 shape2 = swf_ShapeToShape2(shape);
1709 if (l->type == moveTo) {
1711 to.x = l->x * size / 100.0 / 20.0 + advance;
1712 to.y = l->y * size / 100.0 / 20.0;
1713 draw->moveTo(draw, &to);
1714 } else if (l->type == lineTo) {
1716 to.x = l->x * size / 100.0 / 20.0 + advance;
1717 to.y = l->y * size / 100.0 / 20.0;
1718 draw->lineTo(draw, &to);
1719 } else if (l->type == splineTo) {
1721 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1722 mid.y = l->sy * size / 100.0 / 20.0;
1723 to.x = l->x * size / 100.0 / 20.0 + advance;
1724 to.y = l->y * size / 100.0 / 20.0;
1725 draw->splineTo(draw, &mid, &to);
1729 swf_Shape2Free(shape2);
1730 advance += font->glyph[g].advance * size / 100.0 / 20.0;