5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9 Copyright (c) 2003,2004 Matthias Kramm
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 static U32 readUTF8char(U8 ** text)
28 if (!(*(*text) & 0x80))
31 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
32 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
33 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
37 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
38 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
39 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
43 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
44 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
46 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
50 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
51 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
54 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
58 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
59 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
61 && (*text)[4] && (*text)[5]) {
62 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
63 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
70 #define TF_TEXTCONTROL 0x80
71 #define TF_HASFONT 0x08
72 #define TF_HASCOLOR 0x04
73 #define TF_HASYOFFSET 0x02
74 #define TF_HASXOFFSET 0x01
76 #define FF_WIDECODES 0x01
78 #define FF_ITALIC 0x04
80 #define FF_SHIFTJIS 0x10
81 #define FF_UNICODE 0x20
84 #define FF2_ITALIC 0x02
85 #define FF2_WIDECODES 0x04
86 #define FF2_WIDEOFFSETS 0x08
88 #define FF2_UNICODE 0x20
89 #define FF2_SHIFTJIS 0x40
90 #define FF2_LAYOUT 0x80
92 int swf_FontIsItalic(SWFFONT * f)
94 return f->style & FONT_STYLE_ITALIC;
97 int swf_FontIsBold(SWFFONT * f)
99 return f->style & FONT_STYLE_BOLD;
102 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
104 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
114 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
125 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
128 swf_GetBlock(t, s, l);
132 (FontCallback) (self, id, s);
134 swf_RestoreTagPos(t);
142 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
149 if ((!id) || (id == fid)) {
160 f->glyph = rfx_calloc(sizeof(SWFGLYPH) * n);
162 for (i = 1; i < n; i++)
164 for (i = 0; i < n; i++)
165 swf_GetSimpleShape(t, &f->glyph[i].shape);
168 swf_RestoreTagPos(t);
172 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
185 if (f->version > 1) {
186 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
187 too. However, they only add little information to what's already
188 inside the DefineFont2 tag */
195 f->name = (U8 *) rfx_alloc(l + 1);
196 swf_GetBlock(t, f->name, l);
199 flags = swf_GetU8(t);
201 f->style |= FONT_STYLE_BOLD;
203 f->style |= FONT_STYLE_ITALIC;
205 f->encoding |= FONT_ENCODING_ANSI;
207 f->encoding |= FONT_ENCODING_SHIFTJIS;
209 f->encoding |= FONT_ENCODING_UNICODE;
211 if (t->id == ST_DEFINEFONTINFO2) {
212 f->language = swf_GetU8(t);
215 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
217 for (i = 0; i < f->numchars; i++) {
218 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
219 if (f->glyph2ascii[i] > maxcode)
220 maxcode = f->glyph2ascii[i];
225 f->maxascii = maxcode;
226 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
227 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
229 for (i = 0; i < f->numchars; i++)
230 f->ascii2glyph[f->glyph2ascii[i]] = i;
233 swf_RestoreTagPos(t);
237 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
243 swf_SetTagPos(tag, 0);
245 fid = swf_GetU16(tag);
248 int num = swf_GetU16(tag);
250 f->glyphnames = rfx_alloc(sizeof(char *) * num);
251 for (t = 0; t < num; t++) {
252 f->glyphnames[t] = strdup(swf_GetString(tag));
256 swf_RestoreTagPos(tag);
261 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
268 U8 flags1, flags2, namelen;
270 swf_SetTagPos(tag, 0);
272 fid = swf_GetU16(tag);
276 flags1 = swf_GetU8(tag);
277 flags2 = swf_GetU8(tag); //reserved flags
280 font->style |= FONT_STYLE_BOLD;
282 font->style |= FONT_STYLE_ITALIC;
284 font->encoding |= FONT_ENCODING_ANSI;
286 font->encoding |= FONT_ENCODING_UNICODE;
288 font->encoding |= FONT_ENCODING_SHIFTJIS;
290 namelen = swf_GetU8(tag);
291 font->name = (U8 *) rfx_alloc(namelen + 1);
292 font->name[namelen] = 0;
293 swf_GetBlock(tag, font->name, namelen);
295 glyphcount = swf_GetU16(tag);
296 font->numchars = glyphcount;
298 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
299 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
301 offset = rfx_calloc(sizeof(U32)*(glyphcount+1));
302 offset_start = tag->pos;
304 if (flags1 & 8) { // wide offsets
305 for (t = 0; t < glyphcount; t++)
306 offset[t] = swf_GetU32(tag); //offset[t]
308 if (glyphcount) /* this _if_ is not in the specs */
309 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
311 offset[glyphcount] = tag->pos;
313 for (t = 0; t < glyphcount; t++)
314 offset[t] = swf_GetU16(tag); //offset[t]
316 if (glyphcount) /* this _if_ is not in the specs */
317 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
319 offset[glyphcount] = tag->pos;
321 for (t = 0; t < glyphcount; t++) {
322 swf_SetTagPos(tag, offset[t]+offset_start);
323 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
326 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
331 for (t = 0; t < glyphcount; t++) {
333 if (flags1 & 4) // wide codes
334 code = swf_GetU16(tag);
336 code = swf_GetU8(tag);
337 font->glyph2ascii[t] = code;
344 font->maxascii = maxcode;
345 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
346 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
347 for (t = 0; t < glyphcount; t++) {
348 font->ascii2glyph[font->glyph2ascii[t]] = t;
351 if (flags1 & 128) { // has layout
353 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
354 font->layout->ascent = swf_GetU16(tag);
355 font->layout->descent = swf_GetU16(tag);
356 font->layout->leading = swf_GetU16(tag);
357 for (t = 0; t < glyphcount; t++) {
358 S16 advance = swf_GetS16(tag);
359 font->glyph[t].advance = advance;
361 font->layout->bounds = rfx_alloc(glyphcount * sizeof(SRECT));
362 for (t = 0; t < glyphcount; t++) {
363 swf_ResetReadBits(tag);
364 swf_GetRect(tag, &font->layout->bounds[t]);
367 kerningcount = swf_GetU16(tag);
368 font->layout->kerningcount = kerningcount;
370 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
372 font->layout->kerning = rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
373 for (t = 0; t < kerningcount; t++) {
374 if (flags1 & 4) { // wide codes
375 font->layout->kerning[t].char1 = swf_GetU16(tag);
376 font->layout->kerning[t].char2 = swf_GetU16(tag);
378 font->layout->kerning[t].char1 = swf_GetU8(tag);
379 font->layout->kerning[t].char2 = swf_GetU8(tag);
381 font->layout->kerning[t].adjustment = swf_GetS16(tag);
385 swf_RestoreTagPos(t);
390 #define FEDTJ_PRINT 0x01
391 #define FEDTJ_MODIFY 0x02
392 #define FEDTJ_CALLBACK 0x04
395 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
396 void (*callback) (void *self,
397 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
408 memset(&color, 0, sizeof(color));
415 swf_GetMatrix(t, &m);
416 gbits = swf_GetU8(t);
417 abits = swf_GetU8(t);
421 flags = swf_GetU8(t);
425 if (flags & TF_TEXTCONTROL) {
426 if (flags & TF_HASFONT)
428 if (flags & TF_HASCOLOR) {
429 color.r = swf_GetU8(t); // rgb
430 color.g = swf_GetU8(t);
431 color.b = swf_GetU8(t);
432 if (swf_GetTagID(t) == ST_DEFINETEXT2)
433 color.a = swf_GetU8(t);
437 if (flags & TF_HASXOFFSET)
439 if (flags & TF_HASYOFFSET)
441 if (flags & TF_HASFONT)
442 fontsize = swf_GetU16(t);
454 for (i = 0; i < num; i++) {
458 glyph = swf_GetBits(t, gbits);
459 adv = swf_GetBits(t, abits);
464 if (jobs & FEDTJ_PRINT) {
465 int code = f->glyph2ascii[glyph];
468 if (jobs & FEDTJ_MODIFY)
469 f->glyph[glyph].advance = adv * 20; //?
471 if (jobs & FEDTJ_PRINT) {
479 if ((id == fid) && (jobs & FEDTJ_PRINT))
481 if (jobs & FEDTJ_CALLBACK)
482 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
487 swf_RestoreTagPos(t);
491 int swf_ParseDefineText(TAG * tag,
492 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
494 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
497 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
499 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
502 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
507 if ((!swf) || (!font))
510 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
516 switch (swf_GetTagID(t)) {
518 nid = swf_FontExtract_DefineFont(id, f, t);
522 nid = swf_FontExtract_DefineFont2(id, f, t);
525 case ST_DEFINEFONTINFO:
526 case ST_DEFINEFONTINFO2:
527 nid = swf_FontExtract_DefineFontInfo(id, f, t);
532 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
536 nid = swf_FontExtract_GlyphNames(id, f, t);
551 int swf_FontSetID(SWFFONT * f, U16 id)
559 void swf_LayoutFree(SWFLAYOUT * l)
563 rfx_free(l->kerning);
573 static void font_freeglyphnames(SWFFONT*f)
577 for (t = 0; t < f->numchars; t++) {
578 if (f->glyphnames[t]) {
579 rfx_free(f->glyphnames[t]);
580 f->glyphnames[t] = 0;
583 rfx_free(f->glyphnames);
588 static void font_freeusage(SWFFONT*f)
592 rfx_free(f->use->chars);f->use->chars = 0;
594 rfx_free(f->use); f->use = 0;
597 static void font_freelayout(SWFFONT*f)
600 swf_LayoutFree(f->layout);
604 static void font_freename(SWFFONT*f)
612 int swf_FontReduce_old(SWFFONT * f)
616 if ((!f) || (!f->use) || f->use->is_reduced)
621 for (i = 0; i < f->numchars; i++) {
622 if (f->glyph[i].shape && f->use->chars[i]) {
623 f->glyph2ascii[j] = f->glyph2ascii[i];
624 f->glyph[j] = f->glyph[i];
625 f->use->chars[i] = j;
628 f->glyph2ascii[i] = 0;
629 if(f->glyph[i].shape) {
630 swf_ShapeFree(f->glyph[i].shape);
631 f->glyph[i].shape = 0;
632 f->glyph[i].advance = 0;
634 f->use->chars[i] = -1;
638 for (i = 0; i < f->maxascii; i++) {
639 if(f->use->chars[f->ascii2glyph[i]]<0) {
640 f->ascii2glyph[i] = -1;
642 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
646 f->maxascii = max_unicode;
647 f->use->is_reduced = 1;
650 font_freeglyphnames(f);
655 int swf_FontReduce(SWFFONT * f)
660 if ((!f) || (!f->use) || f->use->is_reduced)
664 font_freeglyphnames(f);
666 for (i = 0; i < f->numchars; i++) {
667 if(!f->use->chars[i]) {
669 f->glyph2ascii[i] = 0;
671 if(f->glyph[i].shape) {
672 swf_ShapeFree(f->glyph[i].shape);
673 f->glyph[i].shape = 0;
674 f->glyph[i].advance = 0;
680 for (i = 0; i < f->maxascii; i++) {
681 if(!f->use->chars[f->ascii2glyph[i]]) {
683 f->ascii2glyph[i] = -1;
689 f->maxascii = max_unicode;
690 f->numchars = max_glyph;
695 void swf_FontSort(SWFFONT * font)
703 newplace = rfx_alloc(sizeof(int) * font->numchars);
705 for (i = 0; i < font->numchars; i++) {
708 for (i = 0; i < font->numchars; i++)
709 for (j = 0; j < i; j++) {
710 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
719 n1 = font->glyph2ascii[i];
720 n2 = font->glyph2ascii[j];
721 font->glyph2ascii[j] = n1;
722 font->glyph2ascii[i] = n2;
727 if (font->glyphnames) {
728 c1 = font->glyphnames[i];
729 c2 = font->glyphnames[j];
730 font->glyphnames[j] = c1;
731 font->glyphnames[i] = c2;
734 r1 = font->layout->bounds[i];
735 r2 = font->layout->bounds[j];
736 font->layout->bounds[j] = r1;
737 font->layout->bounds[i] = r2;
741 newpos = rfx_alloc(sizeof(int) * font->numchars);
742 for (i = 0; i < font->numchars; i++) {
743 newpos[newplace[i]] = i;
745 for (i = 0; i < font->maxascii; i++) {
746 if (font->ascii2glyph[i] >= 0)
747 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
754 void swf_FontPrepareForEditText(SWFFONT * font)
757 swf_FontCreateLayout(font);
761 int swf_FontInitUsage(SWFFONT * f)
766 fprintf(stderr, "Usage initialized twice");
769 f->use = rfx_alloc(sizeof(FONTUSAGE));
770 f->use->is_reduced = 0;
771 f->use->chars = rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
775 void swf_FontClearUsage(SWFFONT * f)
779 rfx_free(f->use->chars); f->use->chars = 0;
780 rfx_free(f->use); f->use = 0;
783 int swf_FontUse(SWFFONT * f, U8 * s)
786 swf_FontInitUsage(f);
790 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
791 f->use->chars[f->ascii2glyph[*s]] = 1;
797 int swf_FontUseGlyph(SWFFONT * f, int glyph)
800 swf_FontInitUsage(f);
801 if(glyph < 0 || glyph >= f->numchars)
803 f->use->chars[glyph] = 1;
807 int swf_FontSetDefine(TAG * t, SWFFONT * f)
809 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
814 swf_ResetWriteBits(t);
815 swf_SetU16(t, f->id);
819 for (i = 0; i < f->numchars; i++)
820 if (f->glyph[i].shape) {
822 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
825 for (i = 0; i < j; i++)
826 swf_SetU16(t, ofs[i] + j * 2);
828 fprintf(stderr, "rfxswf: warning: Font is empty\n");
832 for (i = 0; i < f->numchars; i++)
833 if (f->glyph[i].shape)
834 swf_SetSimpleShape(t, f->glyph[i].shape);
836 swf_ResetWriteBits(t);
841 static inline int fontSize(SWFFONT * font)
845 for (t = 0; t < font->numchars; t++) {
847 if(font->glyph[t].shape)
848 l = (font->glyph[t].shape->bitlen + 7) / 8;
853 return size + (font->numchars + 1) * 2;
856 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
862 swf_SetU16(tag, f->id);
864 if (f->layout) flags |= 128; // haslayout
865 if (f->numchars > 256)
866 flags |= 4; // widecodes
867 if (f->style & FONT_STYLE_BOLD)
869 if (f->style & FONT_STYLE_ITALIC)
870 flags |= 2; // italic
871 if (f->maxascii >= 256)
872 flags |= 4; //wide codecs
873 if (fontSize(f) > 65535)
874 flags |= 8; //wide offsets
875 flags |= 8 | 4; //FIXME: the above check doesn't work
877 if (f->encoding & FONT_ENCODING_ANSI)
879 if (f->encoding & FONT_ENCODING_UNICODE)
880 flags |= 32; // unicode
881 if (f->encoding & FONT_ENCODING_SHIFTJIS)
882 flags |= 64; // shiftjis
884 swf_SetU8(tag, flags);
885 swf_SetU8(tag, 0); //reserved flags
888 swf_SetU8(tag, strlen(f->name));
889 swf_SetBlock(tag, f->name, strlen(f->name));
891 /* font name (="") */
894 /* number of glyphs */
895 swf_SetU16(tag, f->numchars);
896 /* font offset table */
898 for (t = 0; t <= f->numchars; t++) {
900 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
902 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
905 for (t = 0; t <= f->numchars; t++) {
907 tag->data[pos + t * 4] = (tag->len - pos);
908 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
909 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
910 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
912 if (tag->len - pos > 65535) {
913 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
916 tag->data[pos + t * 2] = (tag->len - pos);
917 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
919 if (t < f->numchars) {
920 if(f->glyph[t].shape) {
921 swf_SetSimpleShape(tag, f->glyph[t].shape);
923 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
929 /* font code table */
930 for (t = 0; t < f->numchars; t++) {
931 if (flags & 4) { /* wide codes */
932 if(f->glyph2ascii[t]) {
933 swf_SetU16(tag, f->glyph2ascii[t]);
938 if(f->glyph2ascii[t]) {
939 swf_SetU8(tag, f->glyph2ascii[t]);
947 swf_SetU16(tag, f->layout->ascent);
948 swf_SetU16(tag, f->layout->descent);
949 swf_SetU16(tag, f->layout->leading);
950 for (t = 0; t < f->numchars; t++)
951 swf_SetU16(tag, f->glyph[t].advance);
952 for (t = 0; t < f->numchars; t++) {
953 swf_ResetWriteBits(tag);
954 swf_SetRect(tag, &f->layout->bounds[t]);
956 swf_SetU16(tag, f->layout->kerningcount);
957 for (t = 0; t < f->layout->kerningcount; t++) {
958 if (flags & 4) { /* wide codes */
959 swf_SetU16(tag, f->layout->kerning[t].char1);
960 swf_SetU16(tag, f->layout->kerning[t].char2);
962 swf_SetU8(tag, f->layout->kerning[t].char1);
963 swf_SetU8(tag, f->layout->kerning[t].char2);
965 swf_SetU16(tag, f->layout->kerning[t].adjustment);
971 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
973 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
974 f->layout->ascent = ascent;
975 f->layout->descent = descent;
976 f->layout->leading = leading;
977 f->layout->kerningcount = 0;
978 f->layout->kerning = 0;
979 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
982 int swf_FontSetInfo(TAG * t, SWFFONT * f)
989 swf_ResetWriteBits(t);
990 swf_SetU16(t, f->id);
991 l = f->name ? strlen(f->name) : 0;
996 swf_SetBlock(t, f->name, l);
997 if (f->numchars >= 256)
1000 if (f->style & FONT_STYLE_BOLD)
1002 if (f->style & FONT_STYLE_ITALIC)
1004 if (f->style & FONT_ENCODING_ANSI)
1006 if (f->style & FONT_ENCODING_SHIFTJIS)
1008 if (f->style & FONT_ENCODING_UNICODE)
1011 swf_SetU8(t, (flags & 0xfe) | wide);
1013 for (i = 0; i < f->numchars; i++) {
1014 if (f->glyph[i].shape) {
1015 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1016 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1023 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1025 int id = swf_GetTagID(t);
1026 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1027 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1033 void swf_FontFree(SWFFONT * f)
1040 for (i = 0; i < f->numchars; i++)
1041 if (f->glyph[i].shape) {
1042 swf_ShapeFree(f->glyph[i].shape);
1043 f->glyph[i].shape = NULL;
1048 if (f->ascii2glyph) {
1049 rfx_free(f->ascii2glyph);
1050 f->ascii2glyph = NULL;
1052 if (f->glyph2ascii) {
1053 rfx_free(f->glyph2ascii);
1054 f->glyph2ascii = NULL;
1058 font_freeglyphnames(f);
1064 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1070 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1071 | (dy ? TF_HASYOFFSET : 0);
1073 swf_SetU8(t, flags);
1075 swf_SetU16(t, font->id);
1077 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1078 swf_SetRGBA(t, color);
1080 swf_SetRGB(t, color);
1083 if(dx != SET_TO_ZERO) {
1084 if(dx>32767 || dx<-32768)
1085 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1092 if(dy != SET_TO_ZERO) {
1093 if(dy>32767 || dy<-32768)
1094 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1101 swf_SetU16(t, size);
1106 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1110 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1114 if (!strcmp(encoding, "UTF8"))
1116 else if (!strcmp(encoding, "iso-8859-1"))
1119 fprintf(stderr, "Unknown encoding: %s", encoding);
1127 c = readUTF8char(&s);
1129 if (c < font->maxascii)
1130 glyph = font->ascii2glyph[c];
1132 g = swf_CountUBits(glyph, g);
1133 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1144 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1149 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1152 if (!strcmp(encoding, "UTF8"))
1154 else if (!strcmp(encoding, "iso-8859-1"))
1157 fprintf(stderr, "Unknown encoding: %s", encoding);
1160 swf_SetU8(t, l); //placeholder
1168 c = readUTF8char(&s);
1170 if (c < font->maxascii)
1171 g = font->ascii2glyph[c];
1173 swf_SetBits(t, g, gbits);
1174 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1176 /* We split into 127 characters per text field.
1177 We could do 255, by the (formerly wrong) flash specification,
1178 but some SWF parsing code out there still assumes that char blocks
1179 are at max 127 characters, and it would save only a few bits.
1186 PUT8(&t->data[pos], l);
1188 swf_ResetWriteBits(t);
1192 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1194 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1197 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1199 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1202 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1204 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1207 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1209 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1212 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1219 if (*s < font->maxascii)
1220 g = font->ascii2glyph[*s];
1222 res += font->glyph[g].advance / 20;
1226 res = (res * scale) / 100;
1231 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1238 int c = readUTF8char(&s);
1239 if(c==13 || c==10) {
1244 ypos+=font->layout->leading;
1247 if (c < font->maxascii) {
1248 int g = font->ascii2glyph[c];
1250 SRECT rn = font->layout->bounds[g];
1251 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1252 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1253 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1254 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1255 swf_ExpandRect2(&r, &rn);
1256 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1264 SWFFONT *swf_ReadFont(char *filename)
1270 f = open(filename, O_RDONLY|O_BINARY);
1272 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1273 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1279 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1286 void swf_WriteFont(SWFFONT * font, char *filename)
1293 int useDefineFont2 = 0;
1294 int storeGlyphNames = 1;
1297 useDefineFont2 = 1; /* the only thing new in definefont2
1298 is layout information. */
1300 font->id = WRITEFONTID; //"FN"
1302 memset(&swf, 0x00, sizeof(SWF));
1304 swf.fileVersion = 4;
1305 swf.frameRate = 0x4000;
1307 /* if we use DefineFont1 to store the characters,
1308 we have to build a textfield to store the
1309 advance values. While at it, we can also
1310 make the whole .swf viewable */
1312 /* we now always create viewable swfs, even if we
1313 did use definefont2 -mk */
1314 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1319 swf_SetRGB(t, &rgb);
1320 if (!useDefineFont2) {
1321 t = swf_InsertTag(t, ST_DEFINEFONT);
1322 swf_FontSetDefine(t, font);
1323 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1324 swf_FontSetInfo(t, font);
1326 t = swf_InsertTag(t, ST_DEFINEFONT2);
1327 swf_FontSetDefine2(t, font);
1330 if (storeGlyphNames && font->glyphnames) {
1332 t = swf_InsertTag(t, ST_GLYPHNAMES);
1333 swf_SetU16(t, WRITEFONTID);
1334 swf_SetU16(t, font->numchars);
1335 for (c = 0; c < font->numchars; c++) {
1336 if (font->glyphnames[c])
1337 swf_SetString(t, font->glyphnames[c]);
1339 swf_SetString(t, "");
1343 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1345 int textscale = 400;
1352 int range = font->maxascii;
1355 if (useDefineFont2 && range > 256) {
1359 for (s = 0; s < range; s++) {
1360 int g = font->ascii2glyph[s];
1362 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1363 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1367 if ((s & 15) == 0) {
1374 ymax = ypos * textscale * 2;
1376 swf.movieSize.xmax = xmax * 20;
1377 swf.movieSize.ymax = ymax;
1379 t = swf_InsertTag(t, ST_DEFINETEXT);
1381 swf_SetU16(t, font->id + 1); // ID
1385 r.xmax = swf.movieSize.xmax;
1386 r.ymax = swf.movieSize.ymax;
1390 swf_SetMatrix(t, NULL);
1392 abits = swf_CountBits(xmax * 16, 0);
1395 swf_SetU8(t, gbits);
1396 swf_SetU8(t, abits);
1402 for (y = 0; y < ((range + 15) / 16); y++) {
1403 int c = 0, lastx = -1;
1404 for (x = 0; x < 16; x++) {
1405 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1406 if (g >= 0 && font->glyph[g].shape) {
1413 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1414 for (x = 0; x < 16; x++) {
1415 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1416 if (g >= 0 && font->glyph[g].shape) {
1417 if (lastx != x * xmax) {
1418 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1421 swf_SetBits(t, g, gbits);
1422 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1423 lastx = x * xmax + (font->glyph[g].advance / 20);
1424 swf_ResetWriteBits(t);
1433 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1435 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1437 t = swf_InsertTag(t, ST_SHOWFRAME);
1441 t = swf_InsertTag(t, ST_END);
1443 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1445 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1452 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1454 swf_SetRect(tag, &r);
1455 swf_ResetWriteBits(tag);
1457 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1459 flags |= ET_HASTEXT;
1461 flags |= ET_HASTEXTCOLOR;
1463 flags |= ET_HASMAXLENGTH;
1465 flags |= ET_HASFONT;
1467 flags |= ET_HASLAYOUT;
1469 swf_SetBits(tag, flags, 16);
1471 if (flags & ET_HASFONT) {
1472 swf_SetU16(tag, font); //font
1473 swf_SetU16(tag, height); //fontheight
1475 if (flags & ET_HASTEXTCOLOR) {
1476 swf_SetRGBA(tag, color);
1478 if (flags & ET_HASMAXLENGTH) {
1479 swf_SetU16(tag, maxlength); //maxlength
1481 if (flags & ET_HASLAYOUT) {
1482 swf_SetU8(tag, layout->align); //align
1483 swf_SetU16(tag, layout->leftmargin); //left margin
1484 swf_SetU16(tag, layout->rightmargin); //right margin
1485 swf_SetU16(tag, layout->indent); //indent
1486 swf_SetU16(tag, layout->leading); //leading
1488 swf_SetString(tag, variable);
1489 if (flags & ET_HASTEXT)
1490 swf_SetString(tag, text);
1493 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1497 U8 *utext = (U8 *) strdup(text);
1503 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1504 ystep = font->layout->leading;
1506 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1507 /* Hm, without layout information, we can't compute a bounding
1508 box. We could call swf_FontCreateLayout to create a layout,
1509 but the caller probably doesn't want us to mess up his font
1512 r.xmin = r.ymin = 0;
1513 r.xmax = r.ymax = 1024 * 20;
1517 swf_SetRect(tag, &r);
1519 /* The text matrix is pretty boring, as it doesn't apply to
1520 individual characters, but rather whole text objects (or
1521 at least whole char records- haven't tested).
1522 So it can't do anything which we can't already do with
1523 the placeobject tag we use for placing the text on the scene.
1525 swf_SetMatrix(tag, 0);
1527 swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1528 swf_SetU8(tag, gbits);
1529 swf_SetU8(tag, abits);
1535 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1538 while(*next && *next!=13 && *next!=10 && count<127) {
1539 readUTF8char(&next);
1542 if(next[0] == 13 || next[0] == 10) {
1547 if(next[0] == 13 && next[1] == 10)
1550 if(next[0] == 13 || next[0] == 10) {
1555 /* now set the text params- notice that a font size of
1556 1024 means that the glyphs will be displayed exactly
1557 as they would be in/with a defineshape. (Try to find
1558 *that* in the flash specs)
1560 /* set the actual text- notice that we just pass our scale
1561 parameter over, as TextSetCharRecord calculates with
1563 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1567 printf("%s\n", upos);
1575 void swf_FontCreateLayout(SWFFONT * f)
1584 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1585 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1586 f->layout->ascent = -32767;
1587 f->layout->descent = -32767;
1589 for (t = 0; t < f->numchars; t++) {
1593 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1595 fprintf(stderr, "Shape parse error\n");
1598 bbox = swf_GetShapeBoundingBox(shape2);
1599 swf_Shape2Free(shape2);
1600 f->layout->bounds[t] = bbox;
1602 width = (bbox.xmax);
1604 /* The following is a heuristic- it may be that extractfont_DefineText
1605 has already found out some widths for individual characters (from the way
1606 they are used)- we now have to guess whether that width might be possible,
1607 which is the case if it isn't either much too big or much too small */
1608 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1609 f->glyph[t].advance = width;
1611 if (-bbox.ymin > f->layout->ascent)
1612 f->layout->ascent = bbox.ymin;
1613 if (bbox.ymax > f->layout->descent)
1614 f->layout->descent = bbox.ymax;
1618 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1620 U8 *s = (U8 *) text;
1626 U32 c = readUTF8char(&s);
1627 int g = font->ascii2glyph[c];
1628 shape = font->glyph[g].shape;
1629 if (((int) g) < 0) {
1630 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1633 shape2 = swf_ShapeToShape2(shape);
1636 if (l->type == moveTo) {
1638 to.x = l->x * size / 100.0 / 20.0 + advance;
1639 to.y = l->y * size / 100.0 / 20.0;
1640 draw->moveTo(draw, &to);
1641 } else if (l->type == lineTo) {
1643 to.x = l->x * size / 100.0 / 20.0 + advance;
1644 to.y = l->y * size / 100.0 / 20.0;
1645 draw->lineTo(draw, &to);
1646 } else if (l->type == splineTo) {
1648 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1649 mid.y = l->sy * size / 100.0 / 20.0;
1650 to.x = l->x * size / 100.0 / 20.0 + advance;
1651 to.y = l->y * size / 100.0 / 20.0;
1652 draw->splineTo(draw, &mid, &to);
1656 swf_Shape2Free(shape2);
1657 advance += font->glyph[g].advance * size / 100.0 / 20.0;