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);
463 if (jobs & FEDTJ_PRINT) {
464 int code = f->glyph2ascii[glyph];
467 if (jobs & FEDTJ_MODIFY)
468 f->glyph[glyph].advance = adv * 20; //?
473 if ((id == fid) && (jobs & FEDTJ_PRINT))
475 if (jobs & FEDTJ_CALLBACK)
476 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
481 swf_RestoreTagPos(t);
485 int swf_ParseDefineText(TAG * tag,
486 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
488 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
491 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
493 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
496 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
501 if ((!swf) || (!font))
504 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
510 switch (swf_GetTagID(t)) {
512 nid = swf_FontExtract_DefineFont(id, f, t);
516 nid = swf_FontExtract_DefineFont2(id, f, t);
519 case ST_DEFINEFONTINFO:
520 case ST_DEFINEFONTINFO2:
521 nid = swf_FontExtract_DefineFontInfo(id, f, t);
526 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
530 nid = swf_FontExtract_GlyphNames(id, f, t);
545 int swf_FontSetID(SWFFONT * f, U16 id)
553 void swf_LayoutFree(SWFLAYOUT * l)
557 rfx_free(l->kerning);
567 static void font_freeglyphnames(SWFFONT*f)
572 for (t = 0; t < f->numchars; t++)
574 if (f->glyphnames[t])
576 rfx_free(f->glyphnames[t]);
577 f->glyphnames[t] = 0;
580 rfx_free(f->glyphnames);
584 static void font_freeusage(SWFFONT*f)
588 rfx_free(f->use->chars);f->use->chars = 0;
590 rfx_free(f->use); f->use = 0;
593 static void font_freelayout(SWFFONT*f)
596 swf_LayoutFree(f->layout);
600 static void font_freename(SWFFONT*f)
608 int swf_FontReduce_old(SWFFONT * f)
612 if ((!f) || (!f->use) || f->use->is_reduced)
617 for (i = 0; i < f->numchars; i++) {
618 if (f->glyph[i].shape && f->use->chars[i]) {
619 f->glyph2ascii[j] = f->glyph2ascii[i];
620 f->glyph[j] = f->glyph[i];
621 f->use->chars[i] = j;
624 f->glyph2ascii[i] = 0;
625 if(f->glyph[i].shape) {
626 swf_ShapeFree(f->glyph[i].shape);
627 f->glyph[i].shape = 0;
628 f->glyph[i].advance = 0;
630 f->use->chars[i] = -1;
634 for (i = 0; i < f->maxascii; i++) {
635 if(f->use->chars[f->ascii2glyph[i]]<0) {
636 f->ascii2glyph[i] = -1;
638 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
642 f->maxascii = max_unicode;
643 f->use->is_reduced = 1;
646 font_freeglyphnames(f);
651 int swf_FontReduce_swfc(SWFFONT * f)
655 if ((!f) || (!f->use) || f->use->is_reduced)
658 font_freeglyphnames(f);
661 for (i = 0; i < f->numchars; i++) {
662 if (f->glyph[i].shape && f->use->chars[i]) {
663 f->glyph2ascii[j] = f->glyph2ascii[i];
665 f->layout->bounds[j] = f->layout->bounds[i];
666 f->glyph[j] = f->glyph[i];
667 f->use->chars[i] = j;
670 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;
676 f->use->chars[i] = -1;
679 f->use->used_glyphs = j;
680 for (i = 0; i < f->maxascii; i++) {
681 if(f->ascii2glyph[i] > -1) {
682 if (f->use->chars[f->ascii2glyph[i]]<0) {
683 f->use->chars[f->ascii2glyph[i]] = 0;
684 f->ascii2glyph[i] = -1;
686 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
687 f->use->chars[f->ascii2glyph[i]] = 1;
692 f->maxascii = max_unicode;
693 f->use->is_reduced = 1;
699 int swf_FontReduce(SWFFONT * f)
704 if ((!f) || (!f->use) || f->use->is_reduced)
708 font_freeglyphnames(f);
710 f->use->used_glyphs= 0;
711 for (i = 0; i < f->numchars; i++) {
712 if(!f->use->chars[i]) {
714 f->glyph2ascii[i] = 0;
716 if(f->glyph[i].shape) {
717 swf_ShapeFree(f->glyph[i].shape);
718 f->glyph[i].shape = 0;
719 f->glyph[i].advance = 0;
721 // f->use->used_glyphs++;
723 f->use->used_glyphs++;
727 for (i = 0; i < f->maxascii; i++) {
728 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
730 f->ascii2glyph[i] = -1;
736 f->maxascii = max_unicode;
737 f->numchars = max_glyph;
742 void swf_FontSort(SWFFONT * font)
750 newplace = rfx_alloc(sizeof(int) * font->numchars);
752 for (i = 0; i < font->numchars; i++) {
755 for (i = 0; i < font->numchars; i++)
756 for (j = 0; j < i; j++) {
757 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
766 n1 = font->glyph2ascii[i];
767 n2 = font->glyph2ascii[j];
768 font->glyph2ascii[j] = n1;
769 font->glyph2ascii[i] = n2;
774 if (font->glyphnames) {
775 c1 = font->glyphnames[i];
776 c2 = font->glyphnames[j];
777 font->glyphnames[j] = c1;
778 font->glyphnames[i] = c2;
781 r1 = font->layout->bounds[i];
782 r2 = font->layout->bounds[j];
783 font->layout->bounds[j] = r1;
784 font->layout->bounds[i] = r2;
788 newpos = rfx_alloc(sizeof(int) * font->numchars);
789 for (i = 0; i < font->numchars; i++) {
790 newpos[newplace[i]] = i;
792 for (i = 0; i < font->maxascii; i++) {
793 if (font->ascii2glyph[i] >= 0)
794 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
801 void swf_FontPrepareForEditText(SWFFONT * font)
804 swf_FontCreateLayout(font);
808 int swf_FontInitUsage(SWFFONT * f)
813 fprintf(stderr, "Usage initialized twice");
816 f->use = rfx_alloc(sizeof(FONTUSAGE));
817 f->use->is_reduced = 0;
818 f->use->chars = rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
822 void swf_FontClearUsage(SWFFONT * f)
826 rfx_free(f->use->chars); f->use->chars = 0;
827 rfx_free(f->use); f->use = 0;
830 int swf_FontUse(SWFFONT * f, U8 * s)
835 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
836 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
842 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
849 ascii = readUTF8char(&s);
850 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
851 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
856 int swf_FontUseAll(SWFFONT* f)
861 swf_FontInitUsage(f);
862 for (i = 0; i < f->numchars; i++)
863 f->use->chars[i] = 1;
864 f->use->used_glyphs = f->numchars;
868 int swf_FontUseGlyph(SWFFONT * f, int glyph)
871 swf_FontInitUsage(f);
872 if(glyph < 0 || glyph >= f->numchars)
874 if(!f->use->chars[glyph])
875 f->use->used_glyphs++;
876 f->use->chars[glyph] = 1;
880 int swf_FontSetDefine(TAG * t, SWFFONT * f)
882 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
887 swf_ResetWriteBits(t);
888 swf_SetU16(t, f->id);
892 for (i = 0; i < f->numchars; i++)
893 if (f->glyph[i].shape) {
895 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
898 for (i = 0; i < j; i++)
899 swf_SetU16(t, ofs[i] + j * 2);
901 fprintf(stderr, "rfxswf: warning: Font is empty\n");
905 for (i = 0; i < f->numchars; i++)
906 if (f->glyph[i].shape)
907 swf_SetSimpleShape(t, f->glyph[i].shape);
909 swf_ResetWriteBits(t);
914 static inline int fontSize(SWFFONT * font)
918 for (t = 0; t < font->numchars; t++) {
920 if(font->glyph[t].shape)
921 l = (font->glyph[t].shape->bitlen + 7) / 8;
926 return size + (font->numchars + 1) * 2;
929 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
935 swf_SetU16(tag, f->id);
937 if (f->layout) flags |= 128; // haslayout
938 if (f->numchars > 256)
939 flags |= 4; // widecodes
940 if (f->style & FONT_STYLE_BOLD)
942 if (f->style & FONT_STYLE_ITALIC)
943 flags |= 2; // italic
944 if (f->maxascii >= 256)
945 flags |= 4; //wide codecs
946 if (fontSize(f) > 65535)
947 flags |= 8; //wide offsets
948 flags |= 8 | 4; //FIXME: the above check doesn't work
950 if (f->encoding & FONT_ENCODING_ANSI)
952 if (f->encoding & FONT_ENCODING_UNICODE)
953 flags |= 32; // unicode
954 if (f->encoding & FONT_ENCODING_SHIFTJIS)
955 flags |= 64; // shiftjis
957 swf_SetU8(tag, flags);
958 swf_SetU8(tag, 0); //reserved flags
961 swf_SetU8(tag, strlen(f->name));
962 swf_SetBlock(tag, f->name, strlen(f->name));
964 /* font name (="") */
967 /* number of glyphs */
968 swf_SetU16(tag, f->numchars);
969 /* font offset table */
971 for (t = 0; t <= f->numchars; t++) {
973 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
975 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
978 for (t = 0; t <= f->numchars; t++) {
980 tag->data[pos + t * 4] = (tag->len - pos);
981 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
982 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
983 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
985 if (tag->len - pos > 65535) {
986 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
989 tag->data[pos + t * 2] = (tag->len - pos);
990 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
992 if (t < f->numchars) {
993 if(f->glyph[t].shape) {
994 swf_SetSimpleShape(tag, f->glyph[t].shape);
996 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1002 /* font code table */
1003 for (t = 0; t < f->numchars; t++) {
1004 if (flags & 4) { /* wide codes */
1005 if(f->glyph2ascii[t]) {
1006 swf_SetU16(tag, f->glyph2ascii[t]);
1011 if(f->glyph2ascii[t]) {
1012 swf_SetU8(tag, f->glyph2ascii[t]);
1020 swf_SetU16(tag, f->layout->ascent);
1021 swf_SetU16(tag, f->layout->descent);
1022 swf_SetU16(tag, f->layout->leading);
1023 for (t = 0; t < f->numchars; t++)
1024 swf_SetU16(tag, f->glyph[t].advance);
1025 for (t = 0; t < f->numchars; t++) {
1026 swf_ResetWriteBits(tag);
1027 swf_SetRect(tag, &f->layout->bounds[t]);
1029 swf_SetU16(tag, f->layout->kerningcount);
1030 for (t = 0; t < f->layout->kerningcount; t++) {
1031 if (flags & 4) { /* wide codes */
1032 swf_SetU16(tag, f->layout->kerning[t].char1);
1033 swf_SetU16(tag, f->layout->kerning[t].char2);
1035 swf_SetU8(tag, f->layout->kerning[t].char1);
1036 swf_SetU8(tag, f->layout->kerning[t].char2);
1038 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1044 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1046 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1047 f->layout->ascent = ascent;
1048 f->layout->descent = descent;
1049 f->layout->leading = leading;
1050 f->layout->kerningcount = 0;
1051 f->layout->kerning = 0;
1052 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1055 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1062 swf_ResetWriteBits(t);
1063 swf_SetU16(t, f->id);
1064 l = f->name ? strlen(f->name) : 0;
1069 swf_SetBlock(t, f->name, l);
1070 if (f->numchars >= 256)
1073 if (f->style & FONT_STYLE_BOLD)
1075 if (f->style & FONT_STYLE_ITALIC)
1077 if (f->style & FONT_ENCODING_ANSI)
1079 if (f->style & FONT_ENCODING_SHIFTJIS)
1081 if (f->style & FONT_ENCODING_UNICODE)
1084 swf_SetU8(t, (flags & 0xfe) | wide);
1086 for (i = 0; i < f->numchars; i++) {
1087 if (f->glyph[i].shape) {
1088 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1089 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1096 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1098 int id = swf_GetTagID(t);
1099 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1100 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1106 void swf_FontFree(SWFFONT * f)
1114 for (i = 0; i < f->numchars; i++)
1115 if (f->glyph[i].shape)
1117 swf_ShapeFree(f->glyph[i].shape);
1118 f->glyph[i].shape = NULL;
1125 rfx_free(f->ascii2glyph);
1126 f->ascii2glyph = NULL;
1130 rfx_free(f->glyph2ascii);
1131 f->glyph2ascii = NULL;
1135 font_freeglyphnames(f);
1141 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1147 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1148 | (dy ? TF_HASYOFFSET : 0);
1150 swf_SetU8(t, flags);
1152 swf_SetU16(t, font->id);
1154 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1155 swf_SetRGBA(t, color);
1157 swf_SetRGB(t, color);
1160 if(dx != SET_TO_ZERO) {
1161 if(dx>32767 || dx<-32768)
1162 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1169 if(dy != SET_TO_ZERO) {
1170 if(dy>32767 || dy<-32768)
1171 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1178 swf_SetU16(t, size);
1183 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1187 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1191 if (!strcmp(encoding, "UTF8"))
1193 else if (!strcmp(encoding, "iso-8859-1"))
1196 fprintf(stderr, "Unknown encoding: %s", encoding);
1204 c = readUTF8char(&s);
1206 if (c < font->maxascii)
1207 glyph = font->ascii2glyph[c];
1209 g = swf_CountUBits(glyph, g);
1210 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1221 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1226 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1229 if (!strcmp(encoding, "UTF8"))
1231 else if (!strcmp(encoding, "iso-8859-1"))
1234 fprintf(stderr, "Unknown encoding: %s", encoding);
1237 swf_SetU8(t, l); //placeholder
1245 c = readUTF8char(&s);
1247 if (c < font->maxascii)
1248 g = font->ascii2glyph[c];
1250 swf_SetBits(t, g, gbits);
1251 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1253 /* We split into 127 characters per text field.
1254 We could do 255, by the (formerly wrong) flash specification,
1255 but some SWF parsing code out there still assumes that char blocks
1256 are at max 127 characters, and it would save only a few bits.
1263 PUT8(&t->data[pos], l);
1265 swf_ResetWriteBits(t);
1269 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1271 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1274 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1276 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1279 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1281 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1284 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1286 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1289 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1296 if (*s < font->maxascii)
1297 g = font->ascii2glyph[*s];
1299 res += font->glyph[g].advance / 20;
1303 res = (res * scale) / 100;
1308 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1315 int c = readUTF8char(&s);
1316 if(c==13 || c==10) {
1321 ypos+=font->layout->leading;
1324 if (c < font->maxascii) {
1325 int g = font->ascii2glyph[c];
1327 SRECT rn = font->layout->bounds[g];
1328 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1329 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1330 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1331 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1332 swf_ExpandRect2(&r, &rn);
1333 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1341 SWFFONT *swf_ReadFont(char *filename)
1347 f = open(filename, O_RDONLY|O_BINARY);
1349 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1350 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1356 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1363 void swf_WriteFont(SWFFONT * font, char *filename)
1370 int useDefineFont2 = 0;
1371 int storeGlyphNames = 1;
1374 useDefineFont2 = 1; /* the only thing new in definefont2
1375 is layout information. */
1377 font->id = WRITEFONTID; //"FN"
1379 memset(&swf, 0x00, sizeof(SWF));
1381 swf.fileVersion = 4;
1382 swf.frameRate = 0x4000;
1384 /* if we use DefineFont1 to store the characters,
1385 we have to build a textfield to store the
1386 advance values. While at it, we can also
1387 make the whole .swf viewable */
1389 /* we now always create viewable swfs, even if we
1390 did use definefont2 -mk */
1391 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1396 swf_SetRGB(t, &rgb);
1397 if (!useDefineFont2) {
1398 t = swf_InsertTag(t, ST_DEFINEFONT);
1399 swf_FontSetDefine(t, font);
1400 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1401 swf_FontSetInfo(t, font);
1403 t = swf_InsertTag(t, ST_DEFINEFONT2);
1404 swf_FontSetDefine2(t, font);
1407 if (storeGlyphNames && font->glyphnames) {
1409 t = swf_InsertTag(t, ST_GLYPHNAMES);
1410 swf_SetU16(t, WRITEFONTID);
1411 swf_SetU16(t, font->numchars);
1412 for (c = 0; c < font->numchars; c++) {
1413 if (font->glyphnames[c])
1414 swf_SetString(t, font->glyphnames[c]);
1416 swf_SetString(t, "");
1420 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1422 int textscale = 400;
1429 int range = font->maxascii;
1432 if (useDefineFont2 && range > 256) {
1436 for (s = 0; s < range; s++) {
1437 int g = font->ascii2glyph[s];
1439 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1440 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1444 if ((s & 15) == 0) {
1451 ymax = ypos * textscale * 2;
1453 swf.movieSize.xmax = xmax * 20;
1454 swf.movieSize.ymax = ymax;
1456 t = swf_InsertTag(t, ST_DEFINETEXT);
1458 swf_SetU16(t, font->id + 1); // ID
1462 r.xmax = swf.movieSize.xmax;
1463 r.ymax = swf.movieSize.ymax;
1467 swf_SetMatrix(t, NULL);
1469 abits = swf_CountBits(xmax * 16, 0);
1472 swf_SetU8(t, gbits);
1473 swf_SetU8(t, abits);
1479 for (y = 0; y < ((range + 15) / 16); y++) {
1480 int c = 0, lastx = -1;
1481 for (x = 0; x < 16; x++) {
1482 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1483 if (g >= 0 && font->glyph[g].shape) {
1490 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1491 for (x = 0; x < 16; x++) {
1492 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1493 if (g >= 0 && font->glyph[g].shape) {
1494 if (lastx != x * xmax) {
1495 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1498 swf_SetBits(t, g, gbits);
1499 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1500 lastx = x * xmax + (font->glyph[g].advance / 20);
1501 swf_ResetWriteBits(t);
1510 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1512 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1514 t = swf_InsertTag(t, ST_SHOWFRAME);
1518 t = swf_InsertTag(t, ST_END);
1520 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1522 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1529 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1531 swf_SetRect(tag, &r);
1532 swf_ResetWriteBits(tag);
1534 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1536 flags |= ET_HASTEXT;
1538 flags |= ET_HASTEXTCOLOR;
1540 flags |= ET_HASMAXLENGTH;
1542 flags |= ET_HASFONT;
1544 flags |= ET_HASLAYOUT;
1546 swf_SetBits(tag, flags, 16);
1548 if (flags & ET_HASFONT) {
1549 swf_SetU16(tag, font); //font
1550 swf_SetU16(tag, height); //fontheight
1552 if (flags & ET_HASTEXTCOLOR) {
1553 swf_SetRGBA(tag, color);
1555 if (flags & ET_HASMAXLENGTH) {
1556 swf_SetU16(tag, maxlength); //maxlength
1558 if (flags & ET_HASLAYOUT) {
1559 swf_SetU8(tag, layout->align); //align
1560 swf_SetU16(tag, layout->leftmargin); //left margin
1561 swf_SetU16(tag, layout->rightmargin); //right margin
1562 swf_SetU16(tag, layout->indent); //indent
1563 swf_SetU16(tag, layout->leading); //leading
1565 swf_SetString(tag, variable);
1566 if (flags & ET_HASTEXT)
1567 swf_SetString(tag, text);
1570 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1574 U8 *utext = (U8 *) strdup(text);
1580 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1581 ystep = font->layout->leading;
1583 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1584 /* Hm, without layout information, we can't compute a bounding
1585 box. We could call swf_FontCreateLayout to create a layout,
1586 but the caller probably doesn't want us to mess up his font
1589 r.xmin = r.ymin = 0;
1590 r.xmax = r.ymax = 1024 * 20;
1594 swf_SetRect(tag, &r);
1596 /* The text matrix is pretty boring, as it doesn't apply to
1597 individual characters, but rather whole text objects (or
1598 at least whole char records- haven't tested).
1599 So it can't do anything which we can't already do with
1600 the placeobject tag we use for placing the text on the scene.
1602 swf_SetMatrix(tag, 0);
1604 swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1605 swf_SetU8(tag, gbits);
1606 swf_SetU8(tag, abits);
1612 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1615 while(*next && *next!=13 && *next!=10 && count<127) {
1616 readUTF8char(&next);
1619 if(next[0] == 13 || next[0] == 10) {
1624 if(next[0] == 13 && next[1] == 10)
1627 if(next[0] == 13 || next[0] == 10) {
1632 /* now set the text params- notice that a font size of
1633 1024 means that the glyphs will be displayed exactly
1634 as they would be in/with a defineshape. (Try to find
1635 *that* in the flash specs)
1637 /* set the actual text- notice that we just pass our scale
1638 parameter over, as TextSetCharRecord calculates with
1640 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1650 void swf_FontCreateLayout(SWFFONT * f)
1659 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1660 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1661 f->layout->ascent = -32767;
1662 f->layout->descent = -32767;
1664 for (t = 0; t < f->numchars; t++) {
1668 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1670 fprintf(stderr, "Shape parse error\n");
1673 bbox = swf_GetShapeBoundingBox(shape2);
1674 swf_Shape2Free(shape2);
1675 f->layout->bounds[t] = bbox;
1677 width = (bbox.xmax);
1679 /* The following is a heuristic- it may be that extractfont_DefineText
1680 has already found out some widths for individual characters (from the way
1681 they are used)- we now have to guess whether that width might be possible,
1682 which is the case if it isn't either much too big or much too small */
1683 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1684 f->glyph[t].advance = width;
1686 if (-bbox.ymin > f->layout->ascent)
1687 f->layout->ascent = bbox.ymin;
1688 if (bbox.ymax > f->layout->descent)
1689 f->layout->descent = bbox.ymax;
1693 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1695 U8 *s = (U8 *) text;
1701 U32 c = readUTF8char(&s);
1702 int g = font->ascii2glyph[c];
1703 shape = font->glyph[g].shape;
1704 if (((int) g) < 0) {
1705 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1708 shape2 = swf_ShapeToShape2(shape);
1711 if (l->type == moveTo) {
1713 to.x = l->x * size / 100.0 / 20.0 + advance;
1714 to.y = l->y * size / 100.0 / 20.0;
1715 draw->moveTo(draw, &to);
1716 } else if (l->type == lineTo) {
1718 to.x = l->x * size / 100.0 / 20.0 + advance;
1719 to.y = l->y * size / 100.0 / 20.0;
1720 draw->lineTo(draw, &to);
1721 } else if (l->type == splineTo) {
1723 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1724 mid.y = l->sy * size / 100.0 / 20.0;
1725 to.x = l->x * size / 100.0 / 20.0 + advance;
1726 to.y = l->y * size / 100.0 / 20.0;
1727 draw->splineTo(draw, &mid, &to);
1731 swf_Shape2Free(shape2);
1732 advance += font->glyph[g].advance * size / 100.0 / 20.0;