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 #include "../rfxswf.h"
27 U32 readUTF8char(U8 ** text)
30 if (!(*(*text) & 0x80))
33 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
34 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
35 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
39 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
40 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
41 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
45 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
46 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
48 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
52 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
53 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
56 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
60 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
61 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
63 && (*text)[4] && (*text)[5]) {
64 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
65 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
72 #define TF_TEXTCONTROL 0x80
73 #define TF_HASFONT 0x08
74 #define TF_HASCOLOR 0x04
75 #define TF_HASYOFFSET 0x02
76 #define TF_HASXOFFSET 0x01
78 #define FF_WIDECODES 0x01
80 #define FF_ITALIC 0x04
82 #define FF_SHIFTJIS 0x10
83 #define FF_UNICODE 0x20
86 #define FF2_ITALIC 0x02
87 #define FF2_WIDECODES 0x04
88 #define FF2_WIDEOFFSETS 0x08
90 #define FF2_UNICODE 0x20
91 #define FF2_SHIFTJIS 0x40
92 #define FF2_LAYOUT 0x80
94 int swf_FontIsItalic(SWFFONT * f)
96 return f->style & FONT_STYLE_ITALIC;
99 int swf_FontIsBold(SWFFONT * f)
101 return f->style & FONT_STYLE_BOLD;
104 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
106 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
116 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
126 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
129 swf_GetBlock(t, s, l);
133 (FontCallback) (self, id, s);
141 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
147 if ((!id) || (id == fid)) {
158 f->glyph = (SWFGLYPH*)rfx_calloc(sizeof(SWFGLYPH) * n);
160 for (i = 1; i < n; i++)
162 for (i = 0; i < n; i++)
163 swf_GetSimpleShape(t, &f->glyph[i].shape);
168 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
180 if (f->version > 1) {
181 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
182 too. However, they only add little information to what's already
183 inside the DefineFont2 tag */
190 f->name = (U8 *) rfx_alloc(l + 1);
191 swf_GetBlock(t, f->name, l);
194 flags = swf_GetU8(t);
196 f->style |= FONT_STYLE_BOLD;
198 f->style |= FONT_STYLE_ITALIC;
200 f->encoding |= FONT_ENCODING_ANSI;
202 f->encoding |= FONT_ENCODING_SHIFTJIS;
204 f->encoding |= FONT_ENCODING_UNICODE;
206 if (t->id == ST_DEFINEFONTINFO2) {
207 f->language = swf_GetU8(t);
210 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
212 for (i = 0; i < f->numchars; i++) {
213 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
214 if (f->glyph2ascii[i] > maxcode)
215 maxcode = f->glyph2ascii[i];
220 f->maxascii = maxcode;
221 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
222 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
224 for (i = 0; i < f->numchars; i++)
225 f->ascii2glyph[f->glyph2ascii[i]] = i;
230 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
233 swf_SetTagPos(tag, 0);
235 fid = swf_GetU16(tag);
238 int num = swf_GetU16(tag);
240 f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num);
241 for (t = 0; t < num; t++) {
242 f->glyphnames[t] = strdup(swf_GetString(tag));
249 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
256 U8 flags1, langcode, namelen;
257 swf_SetTagPos(tag, 0);
259 fid = swf_GetU16(tag);
263 flags1 = swf_GetU8(tag);
264 langcode = swf_GetU8(tag); //reserved flags
267 font->style |= FONT_STYLE_BOLD;
269 font->style |= FONT_STYLE_ITALIC;
271 font->encoding |= FONT_ENCODING_ANSI;
273 font->encoding |= FONT_ENCODING_UNICODE;
275 font->encoding |= FONT_ENCODING_SHIFTJIS;
277 namelen = swf_GetU8(tag);
278 font->name = (U8 *) rfx_alloc(namelen + 1);
279 font->name[namelen] = 0;
280 swf_GetBlock(tag, font->name, namelen);
282 glyphcount = swf_GetU16(tag);
283 font->numchars = glyphcount;
285 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
286 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
288 offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
289 offset_start = tag->pos;
291 if (flags1 & 8) { // wide offsets
292 for (t = 0; t < glyphcount; t++)
293 offset[t] = swf_GetU32(tag); //offset[t]
295 if (glyphcount) /* this _if_ is not in the specs */
296 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
298 offset[glyphcount] = tag->pos;
300 for (t = 0; t < glyphcount; t++)
301 offset[t] = swf_GetU16(tag); //offset[t]
303 if (glyphcount) /* this _if_ is not in the specs */
304 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
306 offset[glyphcount] = tag->pos;
308 for (t = 0; t < glyphcount; t++) {
309 swf_SetTagPos(tag, offset[t]+offset_start);
310 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
314 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
319 for (t = 0; t < glyphcount; t++) {
321 if (flags1 & 4) // wide codes (always on for definefont3)
322 code = swf_GetU16(tag);
324 code = swf_GetU8(tag);
325 font->glyph2ascii[t] = code;
332 font->maxascii = maxcode;
333 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
334 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
335 for (t = 0; t < glyphcount; t++) {
336 font->ascii2glyph[font->glyph2ascii[t]] = t;
339 if (flags1 & 128) { // has layout
341 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
342 font->layout->ascent = swf_GetU16(tag);
343 font->layout->descent = swf_GetU16(tag);
344 font->layout->leading = swf_GetU16(tag);
345 for (t = 0; t < glyphcount; t++) {
346 S16 advance = swf_GetS16(tag);
347 font->glyph[t].advance = advance;
349 font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
350 for (t = 0; t < glyphcount; t++) {
351 swf_ResetReadBits(tag);
352 swf_GetRect(tag, &font->layout->bounds[t]);
355 kerningcount = swf_GetU16(tag);
356 font->layout->kerningcount = kerningcount;
358 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
360 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
361 for (t = 0; t < kerningcount; t++) {
362 if (flags1 & 4) { // wide codes
363 font->layout->kerning[t].char1 = swf_GetU16(tag);
364 font->layout->kerning[t].char2 = swf_GetU16(tag);
366 font->layout->kerning[t].char1 = swf_GetU8(tag);
367 font->layout->kerning[t].char2 = swf_GetU8(tag);
369 font->layout->kerning[t].adjustment = swf_GetS16(tag);
377 #define FEDTJ_PRINT 0x01
378 #define FEDTJ_MODIFY 0x02
379 #define FEDTJ_CALLBACK 0x04
382 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
383 void (*callback) (void *self,
384 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
395 memset(&color, 0, sizeof(color));
401 swf_GetMatrix(t, &m);
402 gbits = swf_GetU8(t);
403 abits = swf_GetU8(t);
407 flags = swf_GetU8(t);
411 if (flags & TF_TEXTCONTROL) {
412 if (flags & TF_HASFONT)
414 if (flags & TF_HASCOLOR) {
415 color.r = swf_GetU8(t); // rgb
416 color.g = swf_GetU8(t);
417 color.b = swf_GetU8(t);
418 if (swf_GetTagID(t) == ST_DEFINETEXT2)
419 color.a = swf_GetU8(t);
423 if (flags & TF_HASXOFFSET)
425 if (flags & TF_HASYOFFSET)
427 if (flags & TF_HASFONT)
428 fontsize = swf_GetU16(t);
440 for (i = 0; i < num; i++) {
444 glyph = swf_GetBits(t, gbits);
445 adv = swf_GetBits(t, abits);
449 if (jobs & FEDTJ_PRINT) {
450 int code = f->glyph2ascii[glyph];
453 if (jobs & FEDTJ_MODIFY)
454 f->glyph[glyph].advance = adv * 20; //?
459 if ((id == fid) && (jobs & FEDTJ_PRINT))
461 if (jobs & FEDTJ_CALLBACK)
462 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
470 int swf_ParseDefineText(TAG * tag,
471 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
473 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
476 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
478 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
481 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
486 if ((!swf) || (!font))
489 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
495 switch (swf_GetTagID(t)) {
497 nid = swf_FontExtract_DefineFont(id, f, t);
502 nid = swf_FontExtract_DefineFont2(id, f, t);
505 case ST_DEFINEFONTINFO:
506 case ST_DEFINEFONTINFO2:
507 nid = swf_FontExtract_DefineFontInfo(id, f, t);
512 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
516 nid = swf_FontExtract_GlyphNames(id, f, t);
531 int swf_FontSetID(SWFFONT * f, U16 id)
539 void swf_LayoutFree(SWFLAYOUT * l)
543 rfx_free(l->kerning);
553 static void font_freeglyphnames(SWFFONT*f)
558 for (t = 0; t < f->numchars; t++)
560 if (f->glyphnames[t])
562 rfx_free(f->glyphnames[t]);
563 f->glyphnames[t] = 0;
566 rfx_free(f->glyphnames);
570 static void font_freeusage(SWFFONT*f)
574 rfx_free(f->use->chars);f->use->chars = 0;
576 rfx_free(f->use); f->use = 0;
579 static void font_freelayout(SWFFONT*f)
582 swf_LayoutFree(f->layout);
586 static void font_freename(SWFFONT*f)
594 int swf_FontReduce_old(SWFFONT * f)
598 if ((!f) || (!f->use) || f->use->is_reduced)
603 for (i = 0; i < f->numchars; i++) {
604 if (f->glyph[i].shape && f->use->chars[i]) {
605 f->glyph2ascii[j] = f->glyph2ascii[i];
606 f->glyph[j] = f->glyph[i];
607 f->use->chars[i] = j;
610 f->glyph2ascii[i] = 0;
611 if(f->glyph[i].shape) {
612 swf_ShapeFree(f->glyph[i].shape);
613 f->glyph[i].shape = 0;
614 f->glyph[i].advance = 0;
616 f->use->chars[i] = -1;
620 for (i = 0; i < f->maxascii; i++) {
621 if(f->use->chars[f->ascii2glyph[i]]<0) {
622 f->ascii2glyph[i] = -1;
624 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
628 f->maxascii = max_unicode;
629 f->use->is_reduced = 1;
632 font_freeglyphnames(f);
637 int swf_FontReduce_swfc(SWFFONT * f)
641 if ((!f) || (!f->use) || f->use->is_reduced)
644 font_freeglyphnames(f);
647 for (i = 0; i < f->numchars; i++) {
648 if (f->glyph[i].shape && f->use->chars[i]) {
649 f->glyph2ascii[j] = f->glyph2ascii[i];
651 f->layout->bounds[j] = f->layout->bounds[i];
652 f->glyph[j] = f->glyph[i];
653 f->use->chars[i] = j;
656 f->glyph2ascii[i] = 0;
657 if(f->glyph[i].shape) {
658 swf_ShapeFree(f->glyph[i].shape);
659 f->glyph[i].shape = 0;
660 f->glyph[i].advance = 0;
662 f->use->chars[i] = -1;
665 f->use->used_glyphs = j;
666 for (i = 0; i < f->maxascii; i++) {
667 if(f->ascii2glyph[i] > -1) {
668 if (f->use->chars[f->ascii2glyph[i]]<0) {
669 f->use->chars[f->ascii2glyph[i]] = 0;
670 f->ascii2glyph[i] = -1;
672 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
673 f->use->chars[f->ascii2glyph[i]] = 1;
678 f->maxascii = max_unicode;
679 f->use->is_reduced = 1;
685 int swf_FontReduce(SWFFONT * f)
690 if ((!f) || (!f->use) || f->use->is_reduced)
694 font_freeglyphnames(f);
696 f->use->used_glyphs= 0;
697 for (i = 0; i < f->numchars; i++) {
698 if(!f->use->chars[i]) {
700 f->glyph2ascii[i] = 0;
702 if(f->glyph[i].shape) {
703 swf_ShapeFree(f->glyph[i].shape);
704 f->glyph[i].shape = 0;
705 f->glyph[i].advance = 0;
707 // f->use->used_glyphs++;
709 f->use->used_glyphs++;
713 for (i = 0; i < f->maxascii; i++) {
714 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
716 f->ascii2glyph[i] = -1;
722 f->maxascii = max_unicode;
723 f->numchars = max_glyph;
728 void swf_FontSort(SWFFONT * font)
736 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
738 for (i = 0; i < font->numchars; i++) {
741 for (i = 0; i < font->numchars; i++)
742 for (j = 0; j < i; j++) {
743 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
752 n1 = font->glyph2ascii[i];
753 n2 = font->glyph2ascii[j];
754 font->glyph2ascii[j] = n1;
755 font->glyph2ascii[i] = n2;
760 if (font->glyphnames) {
761 c1 = font->glyphnames[i];
762 c2 = font->glyphnames[j];
763 font->glyphnames[j] = c1;
764 font->glyphnames[i] = c2;
767 r1 = font->layout->bounds[i];
768 r2 = font->layout->bounds[j];
769 font->layout->bounds[j] = r1;
770 font->layout->bounds[i] = r2;
774 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
775 for (i = 0; i < font->numchars; i++) {
776 newpos[newplace[i]] = i;
778 for (i = 0; i < font->maxascii; i++) {
779 if (font->ascii2glyph[i] >= 0)
780 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
787 void swf_FontPrepareForEditText(SWFFONT * font)
790 swf_FontCreateLayout(font);
794 int swf_FontInitUsage(SWFFONT * f)
799 fprintf(stderr, "Usage initialized twice");
802 f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
803 f->use->is_reduced = 0;
804 f->use->used_glyphs = 0;
805 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
806 f->use->glyphs_specified = 0;
810 void swf_FontClearUsage(SWFFONT * f)
814 rfx_free(f->use->chars); f->use->chars = 0;
815 rfx_free(f->use); f->use = 0;
818 int swf_FontUse(SWFFONT * f, U8 * s)
823 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
824 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
830 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
837 ascii = readUTF8char(&s);
838 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
839 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
844 int swf_FontUseAll(SWFFONT* f)
849 swf_FontInitUsage(f);
850 for (i = 0; i < f->numchars; i++)
851 f->use->chars[i] = 1;
852 f->use->used_glyphs = f->numchars;
856 int swf_FontUseGlyph(SWFFONT * f, int glyph)
859 swf_FontInitUsage(f);
860 if(glyph < 0 || glyph >= f->numchars)
862 if(!f->use->chars[glyph])
863 f->use->used_glyphs++;
864 f->use->chars[glyph] = 1;
868 int swf_FontSetDefine(TAG * t, SWFFONT * f)
870 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
875 swf_ResetWriteBits(t);
876 swf_SetU16(t, f->id);
880 for (i = 0; i < f->numchars; i++)
881 if (f->glyph[i].shape) {
883 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
886 for (i = 0; i < j; i++)
887 swf_SetU16(t, ofs[i] + j * 2);
889 fprintf(stderr, "rfxswf: warning: Font is empty\n");
893 for (i = 0; i < f->numchars; i++)
894 if (f->glyph[i].shape)
895 swf_SetSimpleShape(t, f->glyph[i].shape);
897 swf_ResetWriteBits(t);
902 static inline int fontSize(SWFFONT * font)
906 for (t = 0; t < font->numchars; t++) {
908 if(font->glyph[t].shape)
909 l = (font->glyph[t].shape->bitlen + 7) / 8;
914 return size + (font->numchars + 1) * 2;
917 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
922 swf_SetU16(tag, f->id);
924 if (f->layout) flags |= 128; // haslayout
925 if (f->numchars > 256)
926 flags |= 4; // widecodes
927 if (f->style & FONT_STYLE_BOLD)
929 if (f->style & FONT_STYLE_ITALIC)
930 flags |= 2; // italic
931 if (f->maxascii >= 256)
932 flags |= 4; //wide codecs
933 if (fontSize(f) > 65535)
934 flags |= 8; //wide offsets
935 flags |= 8 | 4; //FIXME: the above check doesn't work
937 if (f->encoding & FONT_ENCODING_ANSI)
939 if (f->encoding & FONT_ENCODING_UNICODE)
940 flags |= 32; // unicode
941 if (f->encoding & FONT_ENCODING_SHIFTJIS)
942 flags |= 64; // shiftjis
944 swf_SetU8(tag, flags);
945 swf_SetU8(tag, 0); //reserved flags
948 swf_SetU8(tag, strlen((const char*)f->name)+1);
949 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
951 /* font name (="") */
955 /* number of glyphs */
956 swf_SetU16(tag, f->numchars);
957 /* font offset table */
959 for (t = 0; t <= f->numchars; t++) {
961 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
963 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
966 for (t = 0; t <= f->numchars; t++) {
968 tag->data[pos + t * 4] = (tag->len - pos);
969 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
970 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
971 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
973 if (tag->len - pos > 65535) {
974 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
977 tag->data[pos + t * 2] = (tag->len - pos);
978 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
980 if (t < f->numchars) {
981 if(f->glyph[t].shape) {
982 swf_SetSimpleShape(tag, f->glyph[t].shape);
984 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
990 /* font code table */
991 for (t = 0; t < f->numchars; t++) {
992 if (flags & 4) { /* wide codes */
993 if(f->glyph2ascii[t]) {
994 swf_SetU16(tag, f->glyph2ascii[t]);
999 if(f->glyph2ascii[t]) {
1000 swf_SetU8(tag, f->glyph2ascii[t]);
1008 swf_SetU16(tag, f->layout->ascent);
1009 swf_SetU16(tag, f->layout->descent);
1010 swf_SetU16(tag, f->layout->leading);
1011 for (t = 0; t < f->numchars; t++)
1012 swf_SetU16(tag, f->glyph[t].advance);
1013 for (t = 0; t < f->numchars; t++) {
1014 swf_ResetWriteBits(tag);
1015 swf_SetRect(tag, &f->layout->bounds[t]);
1017 swf_SetU16(tag, f->layout->kerningcount);
1018 for (t = 0; t < f->layout->kerningcount; t++) {
1019 if (flags & 4) { /* wide codes */
1020 swf_SetU16(tag, f->layout->kerning[t].char1);
1021 swf_SetU16(tag, f->layout->kerning[t].char2);
1023 swf_SetU8(tag, f->layout->kerning[t].char1);
1024 swf_SetU8(tag, f->layout->kerning[t].char2);
1026 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1032 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1034 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1035 f->layout->ascent = ascent;
1036 f->layout->descent = descent;
1037 f->layout->leading = leading;
1038 f->layout->kerningcount = 0;
1039 f->layout->kerning = 0;
1040 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1043 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1050 swf_ResetWriteBits(t);
1051 swf_SetU16(t, f->id);
1052 l = f->name ? strlen((const char *)f->name) : 0;
1057 swf_SetBlock(t, f->name, l);
1058 if (f->numchars >= 256)
1061 if (f->style & FONT_STYLE_BOLD)
1063 if (f->style & FONT_STYLE_ITALIC)
1065 if (f->style & FONT_ENCODING_ANSI)
1067 if (f->style & FONT_ENCODING_SHIFTJIS)
1069 if (f->style & FONT_ENCODING_UNICODE)
1072 swf_SetU8(t, (flags & 0xfe) | wide);
1074 for (i = 0; i < f->numchars; i++) {
1075 if (f->glyph[i].shape) {
1076 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1077 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1084 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1086 int id = swf_GetTagID(t);
1087 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1088 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1094 void swf_FontFree(SWFFONT * f)
1102 for (i = 0; i < f->numchars; i++)
1103 if (f->glyph[i].shape)
1105 swf_ShapeFree(f->glyph[i].shape);
1106 f->glyph[i].shape = NULL;
1113 rfx_free(f->ascii2glyph);
1114 f->ascii2glyph = NULL;
1118 rfx_free(f->glyph2ascii);
1119 f->glyph2ascii = NULL;
1123 font_freeglyphnames(f);
1129 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1135 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1136 | (y ? TF_HASYOFFSET : 0);
1138 swf_SetU8(t, flags);
1140 swf_SetU16(t, font->id);
1142 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1143 swf_SetRGBA(t, color);
1145 swf_SetRGB(t, color);
1148 if(x != SET_TO_ZERO) {
1149 if(x>32767 || x<-32768)
1150 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1157 if(y != SET_TO_ZERO) {
1158 if(y>32767 || y<-32768)
1159 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1166 swf_SetU16(t, size);
1171 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1175 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1179 if (!strcmp(encoding, "UTF8"))
1181 else if (!strcmp(encoding, "iso-8859-1"))
1184 fprintf(stderr, "Unknown encoding: %s", encoding);
1192 c = readUTF8char(&s);
1194 if (c < font->maxascii)
1195 glyph = font->ascii2glyph[c];
1197 g = swf_CountUBits(glyph, g);
1198 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1209 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1214 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1217 if (!strcmp(encoding, "UTF8"))
1219 else if (!strcmp(encoding, "iso-8859-1"))
1222 fprintf(stderr, "Unknown encoding: %s", encoding);
1225 swf_SetU8(t, l); //placeholder
1233 c = readUTF8char(&s);
1235 if (c < font->maxascii)
1236 g = font->ascii2glyph[c];
1238 swf_SetBits(t, g, gbits);
1239 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1241 /* We split into 127 characters per text field.
1242 We could do 255, by the (formerly wrong) flash specification,
1243 but some SWF parsing code out there still assumes that char blocks
1244 are at max 127 characters, and it would save only a few bits.
1251 PUT8(&t->data[pos], l);
1253 swf_ResetWriteBits(t);
1257 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1259 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1262 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1264 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1267 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1269 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1272 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1274 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1277 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1284 if (*s < font->maxascii)
1285 g = font->ascii2glyph[*s];
1287 res += font->glyph[g].advance / 20;
1291 res = (res * scale) / 100;
1296 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1303 int c = readUTF8char(&s);
1304 if(c==13 || c==10) {
1309 ypos+=font->layout->leading;
1312 if (c < font->maxascii) {
1313 int g = font->ascii2glyph[c];
1315 SRECT rn = font->layout->bounds[g];
1316 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1317 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1318 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1319 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1320 swf_ExpandRect2(&r, &rn);
1321 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1329 SWFFONT *swf_ReadFont(const char *filename)
1335 f = open(filename, O_RDONLY|O_BINARY);
1337 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1338 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1344 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1351 void swf_WriteFont(SWFFONT * font, char *filename)
1358 int useDefineFont2 = 0;
1359 int storeGlyphNames = 1;
1362 useDefineFont2 = 1; /* the only thing new in definefont2
1363 is layout information. */
1365 font->id = WRITEFONTID; //"FN"
1367 memset(&swf, 0x00, sizeof(SWF));
1369 swf.fileVersion = 9;
1370 swf.frameRate = 0x4000;
1372 /* if we use DefineFont1 to store the characters,
1373 we have to build a textfield to store the
1374 advance values. While at it, we can also
1375 make the whole .swf viewable */
1377 /* we now always create viewable swfs, even if we
1378 did use definefont2 -mk */
1379 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1384 swf_SetRGB(t, &rgb);
1385 if (!useDefineFont2) {
1386 t = swf_InsertTag(t, ST_DEFINEFONT);
1387 swf_FontSetDefine(t, font);
1388 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1389 swf_FontSetInfo(t, font);
1391 t = swf_InsertTag(t, ST_DEFINEFONT2);
1392 swf_FontSetDefine2(t, font);
1395 t = swf_InsertTag(t, ST_NAMECHARACTER);
1396 swf_SetU16(t, WRITEFONTID);
1397 swf_SetString(t, (char*)font->name);
1398 t = swf_InsertTag(t, ST_EXPORTASSETS);
1400 swf_SetU16(t, WRITEFONTID);
1401 swf_SetString(t, (char*)font->name);
1403 t = swf_AddAS3FontDefine(t, WRITEFONTID, (char*)font->name);
1406 if (storeGlyphNames && font->glyphnames) {
1408 t = swf_InsertTag(t, ST_GLYPHNAMES);
1409 swf_SetU16(t, WRITEFONTID);
1410 swf_SetU16(t, font->numchars);
1411 for (c = 0; c < font->numchars; c++) {
1412 if (font->glyphnames[c])
1413 swf_SetString(t, font->glyphnames[c]);
1415 swf_SetString(t, "");
1419 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1421 int textscale = 400;
1428 int range = font->maxascii;
1431 if (useDefineFont2 && range > 256) {
1435 for (s = 0; s < range; s++) {
1436 int g = font->ascii2glyph[s];
1438 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1439 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1443 if ((s & 15) == 0) {
1450 ymax = ypos * textscale * 2;
1452 swf.movieSize.xmax = xmax * 20;
1453 swf.movieSize.ymax = ymax;
1455 t = swf_InsertTag(t, ST_DEFINETEXT);
1457 swf_SetU16(t, font->id + 1); // ID
1461 r.xmax = swf.movieSize.xmax;
1462 r.ymax = swf.movieSize.ymax;
1466 swf_SetMatrix(t, NULL);
1468 abits = swf_CountBits(xmax * 16, 0);
1471 swf_SetU8(t, gbits);
1472 swf_SetU8(t, abits);
1478 for (y = 0; y < ((range + 15) / 16); y++) {
1479 int c = 0, lastx = -1;
1480 for (x = 0; x < 16; x++) {
1481 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1482 if (g >= 0 && font->glyph[g].shape) {
1489 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1490 for (x = 0; x < 16; x++) {
1491 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1492 if (g >= 0 && font->glyph[g].shape) {
1493 if (lastx != x * xmax) {
1494 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1497 swf_SetBits(t, g, gbits);
1498 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1499 lastx = x * xmax + (font->glyph[g].advance / 20);
1500 swf_ResetWriteBits(t);
1509 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1511 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1513 t = swf_InsertTag(t, ST_SHOWFRAME);
1517 t = swf_InsertTag(t, ST_END);
1519 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1521 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1528 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, const char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, const char *variable)
1530 swf_SetRect(tag, &r);
1531 swf_ResetWriteBits(tag);
1533 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1535 flags |= ET_HASTEXT;
1537 flags |= ET_HASTEXTCOLOR;
1539 flags |= ET_HASMAXLENGTH;
1541 flags |= ET_HASFONT;
1543 flags |= ET_HASLAYOUT;
1545 swf_SetBits(tag, flags, 16);
1547 if (flags & ET_HASFONT) {
1548 swf_SetU16(tag, font); //font
1549 swf_SetU16(tag, height); //fontheight
1551 if (flags & ET_HASTEXTCOLOR) {
1552 swf_SetRGBA(tag, color);
1554 if (flags & ET_HASMAXLENGTH) {
1555 swf_SetU16(tag, maxlength); //maxlength
1557 if (flags & ET_HASLAYOUT) {
1558 swf_SetU8(tag, layout->align); //align
1559 swf_SetU16(tag, layout->leftmargin); //left margin
1560 swf_SetU16(tag, layout->rightmargin); //right margin
1561 swf_SetU16(tag, layout->indent); //indent
1562 swf_SetU16(tag, layout->leading); //leading
1564 swf_SetString(tag, variable);
1565 if (flags & ET_HASTEXT)
1566 swf_SetString(tag, text);
1569 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1573 U8 *utext = (U8 *) strdup(text);
1579 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1580 ystep = font->layout->leading;
1582 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1583 /* Hm, without layout information, we can't compute a bounding
1584 box. We could call swf_FontCreateLayout to create a layout,
1585 but the caller probably doesn't want us to mess up his font
1588 r.xmin = r.ymin = 0;
1589 r.xmax = r.ymax = 1024 * 20;
1593 swf_SetRect(tag, &r);
1595 /* The text matrix is pretty boring, as it doesn't apply to
1596 individual characters, but rather whole text objects (or
1597 at least whole char records- haven't tested).
1598 So it can't do anything which we can't already do with
1599 the placeobject tag we use for placing the text on the scene.
1601 swf_SetMatrix(tag, 0);
1603 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1604 swf_SetU8(tag, gbits);
1605 swf_SetU8(tag, abits);
1611 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1614 while(*next && *next!=13 && *next!=10 && count<127) {
1615 readUTF8char(&next);
1618 if(next[0] == 13 || next[0] == 10) {
1623 if(next[0] == 13 && next[1] == 10)
1626 if(next[0] == 13 || next[0] == 10) {
1631 /* now set the text params- notice that a font size of
1632 1024 means that the glyphs will be displayed exactly
1633 as they would be in/with a defineshape. (Try to find
1634 *that* in the flash specs)
1636 /* set the actual text- notice that we just pass our scale
1637 parameter over, as TextSetCharRecord calculates with
1639 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1649 void swf_FontCreateLayout(SWFFONT * f)
1658 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1659 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1660 f->layout->ascent = -32767;
1661 f->layout->descent = -32767;
1663 for (t = 0; t < f->numchars; t++) {
1667 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1669 fprintf(stderr, "Shape parse error\n");
1672 bbox = swf_GetShapeBoundingBox(shape2);
1673 swf_Shape2Free(shape2);
1674 f->layout->bounds[t] = bbox;
1676 width = (bbox.xmax);
1678 /* The following is a heuristic- it may be that extractfont_DefineText
1679 has already found out some widths for individual characters (from the way
1680 they are used)- we now have to guess whether that width might be possible,
1681 which is the case if it isn't either much too big or much too small */
1682 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1683 f->glyph[t].advance = width;
1685 if (-bbox.ymin > f->layout->ascent)
1686 f->layout->ascent = bbox.ymin;
1687 if (bbox.ymax > f->layout->descent)
1688 f->layout->descent = bbox.ymax;
1692 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1694 U8 *s = (U8 *) text;
1700 U32 c = readUTF8char(&s);
1701 int g = font->ascii2glyph[c];
1702 shape = font->glyph[g].shape;
1703 if (((int) g) < 0) {
1704 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1707 shape2 = swf_ShapeToShape2(shape);
1710 if (l->type == moveTo) {
1712 to.x = l->x * size / 100.0 / 20.0 + advance;
1713 to.y = l->y * size / 100.0 / 20.0;
1714 draw->moveTo(draw, &to);
1715 } else if (l->type == lineTo) {
1717 to.x = l->x * size / 100.0 / 20.0 + advance;
1718 to.y = l->y * size / 100.0 / 20.0;
1719 draw->lineTo(draw, &to);
1720 } else if (l->type == splineTo) {
1722 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1723 mid.y = l->sy * size / 100.0 / 20.0;
1724 to.x = l->x * size / 100.0 / 20.0 + advance;
1725 to.y = l->y * size / 100.0 / 20.0;
1726 draw->splineTo(draw, &mid, &to);
1730 swf_Shape2Free(shape2);
1731 advance += font->glyph[g].advance * size / 100.0 / 20.0;