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_swfc(SWFFONT * f)
661 if ((!f) || (!f->use) || f->use->is_reduced)
664 font_freeglyphnames(f);
667 for (i = 0; i < f->numchars; i++) {
668 if (f->glyph[i].shape && f->use->chars[i]) {
669 f->glyph2ascii[j] = f->glyph2ascii[i];
671 f->layout->bounds[j] = f->layout->bounds[i];
672 f->glyph[j] = f->glyph[i];
673 f->use->chars[i] = j;
676 f->glyph2ascii[i] = 0;
677 if(f->glyph[i].shape) {
678 swf_ShapeFree(f->glyph[i].shape);
679 f->glyph[i].shape = 0;
680 f->glyph[i].advance = 0;
682 f->use->chars[i] = -1;
685 f->use->used_glyphs = j;
686 for (i = 0; i < f->maxascii; i++) {
687 if(f->ascii2glyph[i] > -1) {
688 if (f->use->chars[f->ascii2glyph[i]]<0) {
689 f->use->chars[f->ascii2glyph[i]] = 0;
690 f->ascii2glyph[i] = -1;
692 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
693 f->use->chars[f->ascii2glyph[i]] = 1;
698 f->maxascii = max_unicode;
699 f->use->is_reduced = 1;
705 int swf_FontReduce(SWFFONT * f)
710 if ((!f) || (!f->use) || f->use->is_reduced)
714 font_freeglyphnames(f);
716 f->use->used_glyphs= 0;
717 for (i = 0; i < f->numchars; i++) {
718 if(!f->use->chars[i]) {
720 f->glyph2ascii[i] = 0;
722 if(f->glyph[i].shape) {
723 swf_ShapeFree(f->glyph[i].shape);
724 f->glyph[i].shape = 0;
725 f->glyph[i].advance = 0;
727 // f->use->used_glyphs++;
729 f->use->used_glyphs++;
733 for (i = 0; i < f->maxascii; i++) {
734 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
736 f->ascii2glyph[i] = -1;
742 f->maxascii = max_unicode;
743 f->numchars = max_glyph;
748 void swf_FontSort(SWFFONT * font)
756 newplace = rfx_alloc(sizeof(int) * font->numchars);
758 for (i = 0; i < font->numchars; i++) {
761 for (i = 0; i < font->numchars; i++)
762 for (j = 0; j < i; j++) {
763 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
772 n1 = font->glyph2ascii[i];
773 n2 = font->glyph2ascii[j];
774 font->glyph2ascii[j] = n1;
775 font->glyph2ascii[i] = n2;
780 if (font->glyphnames) {
781 c1 = font->glyphnames[i];
782 c2 = font->glyphnames[j];
783 font->glyphnames[j] = c1;
784 font->glyphnames[i] = c2;
787 r1 = font->layout->bounds[i];
788 r2 = font->layout->bounds[j];
789 font->layout->bounds[j] = r1;
790 font->layout->bounds[i] = r2;
794 newpos = rfx_alloc(sizeof(int) * font->numchars);
795 for (i = 0; i < font->numchars; i++) {
796 newpos[newplace[i]] = i;
798 for (i = 0; i < font->maxascii; i++) {
799 if (font->ascii2glyph[i] >= 0)
800 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
807 void swf_FontPrepareForEditText(SWFFONT * font)
810 swf_FontCreateLayout(font);
814 int swf_FontInitUsage(SWFFONT * f)
819 fprintf(stderr, "Usage initialized twice");
822 f->use = rfx_alloc(sizeof(FONTUSAGE));
823 f->use->is_reduced = 0;
824 f->use->chars = rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
828 void swf_FontClearUsage(SWFFONT * f)
832 rfx_free(f->use->chars); f->use->chars = 0;
833 rfx_free(f->use); f->use = 0;
836 int swf_FontUse(SWFFONT * f, U8 * s)
841 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
842 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
848 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
855 ascii = readUTF8char(&s);
856 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
857 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
862 int swf_FontUseAll(SWFFONT* f)
867 swf_FontInitUsage(f);
868 for (i = 0; i < f->numchars; i++)
869 f->use->chars[i] = 1;
870 f->use->used_glyphs = f->numchars;
874 int swf_FontUseGlyph(SWFFONT * f, int glyph)
877 swf_FontInitUsage(f);
878 if(glyph < 0 || glyph >= f->numchars)
880 if(!f->use->chars[glyph])
881 f->use->used_glyphs++;
882 f->use->chars[glyph] = 1;
886 int swf_FontSetDefine(TAG * t, SWFFONT * f)
888 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
893 swf_ResetWriteBits(t);
894 swf_SetU16(t, f->id);
898 for (i = 0; i < f->numchars; i++)
899 if (f->glyph[i].shape) {
901 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
904 for (i = 0; i < j; i++)
905 swf_SetU16(t, ofs[i] + j * 2);
907 fprintf(stderr, "rfxswf: warning: Font is empty\n");
911 for (i = 0; i < f->numchars; i++)
912 if (f->glyph[i].shape)
913 swf_SetSimpleShape(t, f->glyph[i].shape);
915 swf_ResetWriteBits(t);
920 static inline int fontSize(SWFFONT * font)
924 for (t = 0; t < font->numchars; t++) {
926 if(font->glyph[t].shape)
927 l = (font->glyph[t].shape->bitlen + 7) / 8;
932 return size + (font->numchars + 1) * 2;
935 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
941 swf_SetU16(tag, f->id);
943 if (f->layout) flags |= 128; // haslayout
944 if (f->numchars > 256)
945 flags |= 4; // widecodes
946 if (f->style & FONT_STYLE_BOLD)
948 if (f->style & FONT_STYLE_ITALIC)
949 flags |= 2; // italic
950 if (f->maxascii >= 256)
951 flags |= 4; //wide codecs
952 if (fontSize(f) > 65535)
953 flags |= 8; //wide offsets
954 flags |= 8 | 4; //FIXME: the above check doesn't work
956 if (f->encoding & FONT_ENCODING_ANSI)
958 if (f->encoding & FONT_ENCODING_UNICODE)
959 flags |= 32; // unicode
960 if (f->encoding & FONT_ENCODING_SHIFTJIS)
961 flags |= 64; // shiftjis
963 swf_SetU8(tag, flags);
964 swf_SetU8(tag, 0); //reserved flags
967 swf_SetU8(tag, strlen(f->name));
968 swf_SetBlock(tag, f->name, strlen(f->name));
970 /* font name (="") */
973 /* number of glyphs */
974 swf_SetU16(tag, f->numchars);
975 /* font offset table */
977 for (t = 0; t <= f->numchars; t++) {
979 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
981 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
984 for (t = 0; t <= f->numchars; t++) {
986 tag->data[pos + t * 4] = (tag->len - pos);
987 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
988 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
989 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
991 if (tag->len - pos > 65535) {
992 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
995 tag->data[pos + t * 2] = (tag->len - pos);
996 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
998 if (t < f->numchars) {
999 if(f->glyph[t].shape) {
1000 swf_SetSimpleShape(tag, f->glyph[t].shape);
1002 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1008 /* font code table */
1009 for (t = 0; t < f->numchars; t++) {
1010 if (flags & 4) { /* wide codes */
1011 if(f->glyph2ascii[t]) {
1012 swf_SetU16(tag, f->glyph2ascii[t]);
1017 if(f->glyph2ascii[t]) {
1018 swf_SetU8(tag, f->glyph2ascii[t]);
1026 swf_SetU16(tag, f->layout->ascent);
1027 swf_SetU16(tag, f->layout->descent);
1028 swf_SetU16(tag, f->layout->leading);
1029 for (t = 0; t < f->numchars; t++)
1030 swf_SetU16(tag, f->glyph[t].advance);
1031 for (t = 0; t < f->numchars; t++) {
1032 swf_ResetWriteBits(tag);
1033 swf_SetRect(tag, &f->layout->bounds[t]);
1035 swf_SetU16(tag, f->layout->kerningcount);
1036 for (t = 0; t < f->layout->kerningcount; t++) {
1037 if (flags & 4) { /* wide codes */
1038 swf_SetU16(tag, f->layout->kerning[t].char1);
1039 swf_SetU16(tag, f->layout->kerning[t].char2);
1041 swf_SetU8(tag, f->layout->kerning[t].char1);
1042 swf_SetU8(tag, f->layout->kerning[t].char2);
1044 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1050 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1052 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1053 f->layout->ascent = ascent;
1054 f->layout->descent = descent;
1055 f->layout->leading = leading;
1056 f->layout->kerningcount = 0;
1057 f->layout->kerning = 0;
1058 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1061 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1068 swf_ResetWriteBits(t);
1069 swf_SetU16(t, f->id);
1070 l = f->name ? strlen(f->name) : 0;
1075 swf_SetBlock(t, f->name, l);
1076 if (f->numchars >= 256)
1079 if (f->style & FONT_STYLE_BOLD)
1081 if (f->style & FONT_STYLE_ITALIC)
1083 if (f->style & FONT_ENCODING_ANSI)
1085 if (f->style & FONT_ENCODING_SHIFTJIS)
1087 if (f->style & FONT_ENCODING_UNICODE)
1090 swf_SetU8(t, (flags & 0xfe) | wide);
1092 for (i = 0; i < f->numchars; i++) {
1093 if (f->glyph[i].shape) {
1094 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1095 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1102 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1104 int id = swf_GetTagID(t);
1105 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1106 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1112 void swf_FontFree(SWFFONT * f)
1120 for (i = 0; i < f->numchars; i++)
1121 if (f->glyph[i].shape)
1123 swf_ShapeFree(f->glyph[i].shape);
1124 f->glyph[i].shape = NULL;
1131 rfx_free(f->ascii2glyph);
1132 f->ascii2glyph = NULL;
1136 rfx_free(f->glyph2ascii);
1137 f->glyph2ascii = NULL;
1141 font_freeglyphnames(f);
1147 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1153 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1154 | (dy ? TF_HASYOFFSET : 0);
1156 swf_SetU8(t, flags);
1158 swf_SetU16(t, font->id);
1160 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1161 swf_SetRGBA(t, color);
1163 swf_SetRGB(t, color);
1166 if(dx != SET_TO_ZERO) {
1167 if(dx>32767 || dx<-32768)
1168 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1175 if(dy != SET_TO_ZERO) {
1176 if(dy>32767 || dy<-32768)
1177 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1184 swf_SetU16(t, size);
1189 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1193 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1197 if (!strcmp(encoding, "UTF8"))
1199 else if (!strcmp(encoding, "iso-8859-1"))
1202 fprintf(stderr, "Unknown encoding: %s", encoding);
1210 c = readUTF8char(&s);
1212 if (c < font->maxascii)
1213 glyph = font->ascii2glyph[c];
1215 g = swf_CountUBits(glyph, g);
1216 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1227 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1232 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1235 if (!strcmp(encoding, "UTF8"))
1237 else if (!strcmp(encoding, "iso-8859-1"))
1240 fprintf(stderr, "Unknown encoding: %s", encoding);
1243 swf_SetU8(t, l); //placeholder
1251 c = readUTF8char(&s);
1253 if (c < font->maxascii)
1254 g = font->ascii2glyph[c];
1256 swf_SetBits(t, g, gbits);
1257 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1259 /* We split into 127 characters per text field.
1260 We could do 255, by the (formerly wrong) flash specification,
1261 but some SWF parsing code out there still assumes that char blocks
1262 are at max 127 characters, and it would save only a few bits.
1269 PUT8(&t->data[pos], l);
1271 swf_ResetWriteBits(t);
1275 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1277 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1280 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1282 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1285 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1287 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1290 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1292 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1295 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1302 if (*s < font->maxascii)
1303 g = font->ascii2glyph[*s];
1305 res += font->glyph[g].advance / 20;
1309 res = (res * scale) / 100;
1314 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1321 int c = readUTF8char(&s);
1322 if(c==13 || c==10) {
1327 ypos+=font->layout->leading;
1330 if (c < font->maxascii) {
1331 int g = font->ascii2glyph[c];
1333 SRECT rn = font->layout->bounds[g];
1334 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1335 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1336 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1337 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1338 swf_ExpandRect2(&r, &rn);
1339 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1347 SWFFONT *swf_ReadFont(char *filename)
1353 f = open(filename, O_RDONLY|O_BINARY);
1355 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1356 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1362 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1369 void swf_WriteFont(SWFFONT * font, char *filename)
1376 int useDefineFont2 = 0;
1377 int storeGlyphNames = 1;
1380 useDefineFont2 = 1; /* the only thing new in definefont2
1381 is layout information. */
1383 font->id = WRITEFONTID; //"FN"
1385 memset(&swf, 0x00, sizeof(SWF));
1387 swf.fileVersion = 4;
1388 swf.frameRate = 0x4000;
1390 /* if we use DefineFont1 to store the characters,
1391 we have to build a textfield to store the
1392 advance values. While at it, we can also
1393 make the whole .swf viewable */
1395 /* we now always create viewable swfs, even if we
1396 did use definefont2 -mk */
1397 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1402 swf_SetRGB(t, &rgb);
1403 if (!useDefineFont2) {
1404 t = swf_InsertTag(t, ST_DEFINEFONT);
1405 swf_FontSetDefine(t, font);
1406 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1407 swf_FontSetInfo(t, font);
1409 t = swf_InsertTag(t, ST_DEFINEFONT2);
1410 swf_FontSetDefine2(t, font);
1413 if (storeGlyphNames && font->glyphnames) {
1415 t = swf_InsertTag(t, ST_GLYPHNAMES);
1416 swf_SetU16(t, WRITEFONTID);
1417 swf_SetU16(t, font->numchars);
1418 for (c = 0; c < font->numchars; c++) {
1419 if (font->glyphnames[c])
1420 swf_SetString(t, font->glyphnames[c]);
1422 swf_SetString(t, "");
1426 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1428 int textscale = 400;
1435 int range = font->maxascii;
1438 if (useDefineFont2 && range > 256) {
1442 for (s = 0; s < range; s++) {
1443 int g = font->ascii2glyph[s];
1445 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1446 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1450 if ((s & 15) == 0) {
1457 ymax = ypos * textscale * 2;
1459 swf.movieSize.xmax = xmax * 20;
1460 swf.movieSize.ymax = ymax;
1462 t = swf_InsertTag(t, ST_DEFINETEXT);
1464 swf_SetU16(t, font->id + 1); // ID
1468 r.xmax = swf.movieSize.xmax;
1469 r.ymax = swf.movieSize.ymax;
1473 swf_SetMatrix(t, NULL);
1475 abits = swf_CountBits(xmax * 16, 0);
1478 swf_SetU8(t, gbits);
1479 swf_SetU8(t, abits);
1485 for (y = 0; y < ((range + 15) / 16); y++) {
1486 int c = 0, lastx = -1;
1487 for (x = 0; x < 16; x++) {
1488 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1489 if (g >= 0 && font->glyph[g].shape) {
1496 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1497 for (x = 0; x < 16; x++) {
1498 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1499 if (g >= 0 && font->glyph[g].shape) {
1500 if (lastx != x * xmax) {
1501 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1504 swf_SetBits(t, g, gbits);
1505 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1506 lastx = x * xmax + (font->glyph[g].advance / 20);
1507 swf_ResetWriteBits(t);
1516 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1518 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1520 t = swf_InsertTag(t, ST_SHOWFRAME);
1524 t = swf_InsertTag(t, ST_END);
1526 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1528 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1535 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1537 swf_SetRect(tag, &r);
1538 swf_ResetWriteBits(tag);
1540 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1542 flags |= ET_HASTEXT;
1544 flags |= ET_HASTEXTCOLOR;
1546 flags |= ET_HASMAXLENGTH;
1548 flags |= ET_HASFONT;
1550 flags |= ET_HASLAYOUT;
1552 swf_SetBits(tag, flags, 16);
1554 if (flags & ET_HASFONT) {
1555 swf_SetU16(tag, font); //font
1556 swf_SetU16(tag, height); //fontheight
1558 if (flags & ET_HASTEXTCOLOR) {
1559 swf_SetRGBA(tag, color);
1561 if (flags & ET_HASMAXLENGTH) {
1562 swf_SetU16(tag, maxlength); //maxlength
1564 if (flags & ET_HASLAYOUT) {
1565 swf_SetU8(tag, layout->align); //align
1566 swf_SetU16(tag, layout->leftmargin); //left margin
1567 swf_SetU16(tag, layout->rightmargin); //right margin
1568 swf_SetU16(tag, layout->indent); //indent
1569 swf_SetU16(tag, layout->leading); //leading
1571 swf_SetString(tag, variable);
1572 if (flags & ET_HASTEXT)
1573 swf_SetString(tag, text);
1576 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1580 U8 *utext = (U8 *) strdup(text);
1586 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1587 ystep = font->layout->leading;
1589 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1590 /* Hm, without layout information, we can't compute a bounding
1591 box. We could call swf_FontCreateLayout to create a layout,
1592 but the caller probably doesn't want us to mess up his font
1595 r.xmin = r.ymin = 0;
1596 r.xmax = r.ymax = 1024 * 20;
1600 swf_SetRect(tag, &r);
1602 /* The text matrix is pretty boring, as it doesn't apply to
1603 individual characters, but rather whole text objects (or
1604 at least whole char records- haven't tested).
1605 So it can't do anything which we can't already do with
1606 the placeobject tag we use for placing the text on the scene.
1608 swf_SetMatrix(tag, 0);
1610 swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1611 swf_SetU8(tag, gbits);
1612 swf_SetU8(tag, abits);
1618 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1621 while(*next && *next!=13 && *next!=10 && count<127) {
1622 readUTF8char(&next);
1625 if(next[0] == 13 || next[0] == 10) {
1630 if(next[0] == 13 && next[1] == 10)
1633 if(next[0] == 13 || next[0] == 10) {
1638 /* now set the text params- notice that a font size of
1639 1024 means that the glyphs will be displayed exactly
1640 as they would be in/with a defineshape. (Try to find
1641 *that* in the flash specs)
1643 /* set the actual text- notice that we just pass our scale
1644 parameter over, as TextSetCharRecord calculates with
1646 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1656 void swf_FontCreateLayout(SWFFONT * f)
1665 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1666 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1667 f->layout->ascent = -32767;
1668 f->layout->descent = -32767;
1670 for (t = 0; t < f->numchars; t++) {
1674 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1676 fprintf(stderr, "Shape parse error\n");
1679 bbox = swf_GetShapeBoundingBox(shape2);
1680 swf_Shape2Free(shape2);
1681 f->layout->bounds[t] = bbox;
1683 width = (bbox.xmax);
1685 /* The following is a heuristic- it may be that extractfont_DefineText
1686 has already found out some widths for individual characters (from the way
1687 they are used)- we now have to guess whether that width might be possible,
1688 which is the case if it isn't either much too big or much too small */
1689 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1690 f->glyph[t].advance = width;
1692 if (-bbox.ymin > f->layout->ascent)
1693 f->layout->ascent = bbox.ymin;
1694 if (bbox.ymax > f->layout->descent)
1695 f->layout->descent = bbox.ymax;
1699 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1701 U8 *s = (U8 *) text;
1707 U32 c = readUTF8char(&s);
1708 int g = font->ascii2glyph[c];
1709 shape = font->glyph[g].shape;
1710 if (((int) g) < 0) {
1711 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1714 shape2 = swf_ShapeToShape2(shape);
1717 if (l->type == moveTo) {
1719 to.x = l->x * size / 100.0 / 20.0 + advance;
1720 to.y = l->y * size / 100.0 / 20.0;
1721 draw->moveTo(draw, &to);
1722 } else if (l->type == lineTo) {
1724 to.x = l->x * size / 100.0 / 20.0 + advance;
1725 to.y = l->y * size / 100.0 / 20.0;
1726 draw->lineTo(draw, &to);
1727 } else if (l->type == splineTo) {
1729 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1730 mid.y = l->sy * size / 100.0 / 20.0;
1731 to.x = l->x * size / 100.0 / 20.0 + advance;
1732 to.y = l->y * size / 100.0 / 20.0;
1733 draw->splineTo(draw, &mid, &to);
1737 swf_Shape2Free(shape2);
1738 advance += font->glyph[g].advance * size / 100.0 / 20.0;