5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9 Copyright (c) 2003,2004 Matthias Kramm
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 U32 readUTF8char(U8 ** text)
28 if (!(*(*text) & 0x80))
31 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
32 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
33 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
37 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
38 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
39 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
43 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
44 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
46 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
50 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
51 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
54 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
58 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
59 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
61 && (*text)[4] && (*text)[5]) {
62 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
63 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
70 #define TF_TEXTCONTROL 0x80
71 #define TF_HASFONT 0x08
72 #define TF_HASCOLOR 0x04
73 #define TF_HASYOFFSET 0x02
74 #define TF_HASXOFFSET 0x01
76 #define FF_WIDECODES 0x01
78 #define FF_ITALIC 0x04
80 #define FF_SHIFTJIS 0x10
81 #define FF_UNICODE 0x20
84 #define FF2_ITALIC 0x02
85 #define FF2_WIDECODES 0x04
86 #define FF2_WIDEOFFSETS 0x08
88 #define FF2_UNICODE 0x20
89 #define FF2_SHIFTJIS 0x40
90 #define FF2_LAYOUT 0x80
92 int swf_FontIsItalic(SWFFONT * f)
94 return f->style & FONT_STYLE_ITALIC;
97 int swf_FontIsBold(SWFFONT * f)
99 return f->style & FONT_STYLE_BOLD;
102 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
104 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
114 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
125 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
128 swf_GetBlock(t, s, l);
132 (FontCallback) (self, id, s);
134 swf_RestoreTagPos(t);
142 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
149 if ((!id) || (id == fid)) {
160 f->glyph = (SWFGLYPH*)rfx_calloc(sizeof(SWFGLYPH) * n);
162 for (i = 1; i < n; i++)
164 for (i = 0; i < n; i++)
165 swf_GetSimpleShape(t, &f->glyph[i].shape);
168 swf_RestoreTagPos(t);
172 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
185 if (f->version > 1) {
186 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
187 too. However, they only add little information to what's already
188 inside the DefineFont2 tag */
195 f->name = (U8 *) rfx_alloc(l + 1);
196 swf_GetBlock(t, f->name, l);
199 flags = swf_GetU8(t);
201 f->style |= FONT_STYLE_BOLD;
203 f->style |= FONT_STYLE_ITALIC;
205 f->encoding |= FONT_ENCODING_ANSI;
207 f->encoding |= FONT_ENCODING_SHIFTJIS;
209 f->encoding |= FONT_ENCODING_UNICODE;
211 if (t->id == ST_DEFINEFONTINFO2) {
212 f->language = swf_GetU8(t);
215 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
217 for (i = 0; i < f->numchars; i++) {
218 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
219 if (f->glyph2ascii[i] > maxcode)
220 maxcode = f->glyph2ascii[i];
225 f->maxascii = maxcode;
226 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
227 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
229 for (i = 0; i < f->numchars; i++)
230 f->ascii2glyph[f->glyph2ascii[i]] = i;
233 swf_RestoreTagPos(t);
237 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
243 swf_SetTagPos(tag, 0);
245 fid = swf_GetU16(tag);
248 int num = swf_GetU16(tag);
250 f->glyphnames = (char**)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 = (U32*)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 = (SRECT*)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 = (SWFKERNING*)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 = (int*)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 = (int*)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 = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
817 f->use->is_reduced = 0;
818 f->use->used_glyphs = 0;
819 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
823 void swf_FontClearUsage(SWFFONT * f)
827 rfx_free(f->use->chars); f->use->chars = 0;
828 rfx_free(f->use); f->use = 0;
831 int swf_FontUse(SWFFONT * f, U8 * s)
836 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
837 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
843 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
850 ascii = readUTF8char(&s);
851 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
852 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
857 int swf_FontUseAll(SWFFONT* f)
862 swf_FontInitUsage(f);
863 for (i = 0; i < f->numchars; i++)
864 f->use->chars[i] = 1;
865 f->use->used_glyphs = f->numchars;
869 int swf_FontUseGlyph(SWFFONT * f, int glyph)
872 swf_FontInitUsage(f);
873 if(glyph < 0 || glyph >= f->numchars)
875 if(!f->use->chars[glyph])
876 f->use->used_glyphs++;
877 f->use->chars[glyph] = 1;
881 int swf_FontSetDefine(TAG * t, SWFFONT * f)
883 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
888 swf_ResetWriteBits(t);
889 swf_SetU16(t, f->id);
893 for (i = 0; i < f->numchars; i++)
894 if (f->glyph[i].shape) {
896 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
899 for (i = 0; i < j; i++)
900 swf_SetU16(t, ofs[i] + j * 2);
902 fprintf(stderr, "rfxswf: warning: Font is empty\n");
906 for (i = 0; i < f->numchars; i++)
907 if (f->glyph[i].shape)
908 swf_SetSimpleShape(t, f->glyph[i].shape);
910 swf_ResetWriteBits(t);
915 static inline int fontSize(SWFFONT * font)
919 for (t = 0; t < font->numchars; t++) {
921 if(font->glyph[t].shape)
922 l = (font->glyph[t].shape->bitlen + 7) / 8;
927 return size + (font->numchars + 1) * 2;
930 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
936 swf_SetU16(tag, f->id);
938 if (f->layout) flags |= 128; // haslayout
939 if (f->numchars > 256)
940 flags |= 4; // widecodes
941 if (f->style & FONT_STYLE_BOLD)
943 if (f->style & FONT_STYLE_ITALIC)
944 flags |= 2; // italic
945 if (f->maxascii >= 256)
946 flags |= 4; //wide codecs
947 if (fontSize(f) > 65535)
948 flags |= 8; //wide offsets
949 flags |= 8 | 4; //FIXME: the above check doesn't work
951 if (f->encoding & FONT_ENCODING_ANSI)
953 if (f->encoding & FONT_ENCODING_UNICODE)
954 flags |= 32; // unicode
955 if (f->encoding & FONT_ENCODING_SHIFTJIS)
956 flags |= 64; // shiftjis
958 swf_SetU8(tag, flags);
959 swf_SetU8(tag, 0); //reserved flags
962 swf_SetU8(tag, strlen((const char*)f->name));
963 swf_SetBlock(tag, f->name, strlen((const char*)f->name));
965 /* font name (="") */
968 /* number of glyphs */
969 swf_SetU16(tag, f->numchars);
970 /* font offset table */
972 for (t = 0; t <= f->numchars; t++) {
974 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
976 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
979 for (t = 0; t <= f->numchars; t++) {
981 tag->data[pos + t * 4] = (tag->len - pos);
982 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
983 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
984 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
986 if (tag->len - pos > 65535) {
987 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
990 tag->data[pos + t * 2] = (tag->len - pos);
991 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
993 if (t < f->numchars) {
994 if(f->glyph[t].shape) {
995 swf_SetSimpleShape(tag, f->glyph[t].shape);
997 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1003 /* font code table */
1004 for (t = 0; t < f->numchars; t++) {
1005 if (flags & 4) { /* wide codes */
1006 if(f->glyph2ascii[t]) {
1007 swf_SetU16(tag, f->glyph2ascii[t]);
1012 if(f->glyph2ascii[t]) {
1013 swf_SetU8(tag, f->glyph2ascii[t]);
1021 swf_SetU16(tag, f->layout->ascent);
1022 swf_SetU16(tag, f->layout->descent);
1023 swf_SetU16(tag, f->layout->leading);
1024 for (t = 0; t < f->numchars; t++)
1025 swf_SetU16(tag, f->glyph[t].advance);
1026 for (t = 0; t < f->numchars; t++) {
1027 swf_ResetWriteBits(tag);
1028 swf_SetRect(tag, &f->layout->bounds[t]);
1030 swf_SetU16(tag, f->layout->kerningcount);
1031 for (t = 0; t < f->layout->kerningcount; t++) {
1032 if (flags & 4) { /* wide codes */
1033 swf_SetU16(tag, f->layout->kerning[t].char1);
1034 swf_SetU16(tag, f->layout->kerning[t].char2);
1036 swf_SetU8(tag, f->layout->kerning[t].char1);
1037 swf_SetU8(tag, f->layout->kerning[t].char2);
1039 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1045 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1047 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1048 f->layout->ascent = ascent;
1049 f->layout->descent = descent;
1050 f->layout->leading = leading;
1051 f->layout->kerningcount = 0;
1052 f->layout->kerning = 0;
1053 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1056 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1063 swf_ResetWriteBits(t);
1064 swf_SetU16(t, f->id);
1065 l = f->name ? strlen((const char *)f->name) : 0;
1070 swf_SetBlock(t, f->name, l);
1071 if (f->numchars >= 256)
1074 if (f->style & FONT_STYLE_BOLD)
1076 if (f->style & FONT_STYLE_ITALIC)
1078 if (f->style & FONT_ENCODING_ANSI)
1080 if (f->style & FONT_ENCODING_SHIFTJIS)
1082 if (f->style & FONT_ENCODING_UNICODE)
1085 swf_SetU8(t, (flags & 0xfe) | wide);
1087 for (i = 0; i < f->numchars; i++) {
1088 if (f->glyph[i].shape) {
1089 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1090 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1097 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1099 int id = swf_GetTagID(t);
1100 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1101 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1107 void swf_FontFree(SWFFONT * f)
1115 for (i = 0; i < f->numchars; i++)
1116 if (f->glyph[i].shape)
1118 swf_ShapeFree(f->glyph[i].shape);
1119 f->glyph[i].shape = NULL;
1126 rfx_free(f->ascii2glyph);
1127 f->ascii2glyph = NULL;
1131 rfx_free(f->glyph2ascii);
1132 f->glyph2ascii = NULL;
1136 font_freeglyphnames(f);
1142 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1148 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1149 | (dy ? TF_HASYOFFSET : 0);
1151 swf_SetU8(t, flags);
1153 swf_SetU16(t, font->id);
1155 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1156 swf_SetRGBA(t, color);
1158 swf_SetRGB(t, color);
1161 if(dx != SET_TO_ZERO) {
1162 if(dx>32767 || dx<-32768)
1163 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1170 if(dy != SET_TO_ZERO) {
1171 if(dy>32767 || dy<-32768)
1172 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1179 swf_SetU16(t, size);
1184 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1188 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1192 if (!strcmp(encoding, "UTF8"))
1194 else if (!strcmp(encoding, "iso-8859-1"))
1197 fprintf(stderr, "Unknown encoding: %s", encoding);
1205 c = readUTF8char(&s);
1207 if (c < font->maxascii)
1208 glyph = font->ascii2glyph[c];
1210 g = swf_CountUBits(glyph, g);
1211 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1222 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1227 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1230 if (!strcmp(encoding, "UTF8"))
1232 else if (!strcmp(encoding, "iso-8859-1"))
1235 fprintf(stderr, "Unknown encoding: %s", encoding);
1238 swf_SetU8(t, l); //placeholder
1246 c = readUTF8char(&s);
1248 if (c < font->maxascii)
1249 g = font->ascii2glyph[c];
1251 swf_SetBits(t, g, gbits);
1252 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1254 /* We split into 127 characters per text field.
1255 We could do 255, by the (formerly wrong) flash specification,
1256 but some SWF parsing code out there still assumes that char blocks
1257 are at max 127 characters, and it would save only a few bits.
1264 PUT8(&t->data[pos], l);
1266 swf_ResetWriteBits(t);
1270 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1272 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1275 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1277 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1280 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1282 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1285 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1287 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1290 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1297 if (*s < font->maxascii)
1298 g = font->ascii2glyph[*s];
1300 res += font->glyph[g].advance / 20;
1304 res = (res * scale) / 100;
1309 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1316 int c = readUTF8char(&s);
1317 if(c==13 || c==10) {
1322 ypos+=font->layout->leading;
1325 if (c < font->maxascii) {
1326 int g = font->ascii2glyph[c];
1328 SRECT rn = font->layout->bounds[g];
1329 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1330 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1331 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1332 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1333 swf_ExpandRect2(&r, &rn);
1334 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1342 SWFFONT *swf_ReadFont(char *filename)
1348 f = open(filename, O_RDONLY|O_BINARY);
1350 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1351 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1357 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1364 void swf_WriteFont(SWFFONT * font, char *filename)
1371 int useDefineFont2 = 0;
1372 int storeGlyphNames = 1;
1375 useDefineFont2 = 1; /* the only thing new in definefont2
1376 is layout information. */
1378 font->id = WRITEFONTID; //"FN"
1380 memset(&swf, 0x00, sizeof(SWF));
1382 swf.fileVersion = 4;
1383 swf.frameRate = 0x4000;
1385 /* if we use DefineFont1 to store the characters,
1386 we have to build a textfield to store the
1387 advance values. While at it, we can also
1388 make the whole .swf viewable */
1390 /* we now always create viewable swfs, even if we
1391 did use definefont2 -mk */
1392 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1397 swf_SetRGB(t, &rgb);
1398 if (!useDefineFont2) {
1399 t = swf_InsertTag(t, ST_DEFINEFONT);
1400 swf_FontSetDefine(t, font);
1401 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1402 swf_FontSetInfo(t, font);
1404 t = swf_InsertTag(t, ST_DEFINEFONT2);
1405 swf_FontSetDefine2(t, font);
1408 if (storeGlyphNames && font->glyphnames) {
1410 t = swf_InsertTag(t, ST_GLYPHNAMES);
1411 swf_SetU16(t, WRITEFONTID);
1412 swf_SetU16(t, font->numchars);
1413 for (c = 0; c < font->numchars; c++) {
1414 if (font->glyphnames[c])
1415 swf_SetString(t, (U8*)font->glyphnames[c]);
1417 swf_SetString(t, (U8*)"");
1421 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1423 int textscale = 400;
1430 int range = font->maxascii;
1433 if (useDefineFont2 && range > 256) {
1437 for (s = 0; s < range; s++) {
1438 int g = font->ascii2glyph[s];
1440 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1441 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1445 if ((s & 15) == 0) {
1452 ymax = ypos * textscale * 2;
1454 swf.movieSize.xmax = xmax * 20;
1455 swf.movieSize.ymax = ymax;
1457 t = swf_InsertTag(t, ST_DEFINETEXT);
1459 swf_SetU16(t, font->id + 1); // ID
1463 r.xmax = swf.movieSize.xmax;
1464 r.ymax = swf.movieSize.ymax;
1468 swf_SetMatrix(t, NULL);
1470 abits = swf_CountBits(xmax * 16, 0);
1473 swf_SetU8(t, gbits);
1474 swf_SetU8(t, abits);
1480 for (y = 0; y < ((range + 15) / 16); y++) {
1481 int c = 0, lastx = -1;
1482 for (x = 0; x < 16; x++) {
1483 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1484 if (g >= 0 && font->glyph[g].shape) {
1491 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1492 for (x = 0; x < 16; x++) {
1493 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1494 if (g >= 0 && font->glyph[g].shape) {
1495 if (lastx != x * xmax) {
1496 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1499 swf_SetBits(t, g, gbits);
1500 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1501 lastx = x * xmax + (font->glyph[g].advance / 20);
1502 swf_ResetWriteBits(t);
1511 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1513 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1515 t = swf_InsertTag(t, ST_SHOWFRAME);
1519 t = swf_InsertTag(t, ST_END);
1521 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1523 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1530 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1532 swf_SetRect(tag, &r);
1533 swf_ResetWriteBits(tag);
1535 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1537 flags |= ET_HASTEXT;
1539 flags |= ET_HASTEXTCOLOR;
1541 flags |= ET_HASMAXLENGTH;
1543 flags |= ET_HASFONT;
1545 flags |= ET_HASLAYOUT;
1547 swf_SetBits(tag, flags, 16);
1549 if (flags & ET_HASFONT) {
1550 swf_SetU16(tag, font); //font
1551 swf_SetU16(tag, height); //fontheight
1553 if (flags & ET_HASTEXTCOLOR) {
1554 swf_SetRGBA(tag, color);
1556 if (flags & ET_HASMAXLENGTH) {
1557 swf_SetU16(tag, maxlength); //maxlength
1559 if (flags & ET_HASLAYOUT) {
1560 swf_SetU8(tag, layout->align); //align
1561 swf_SetU16(tag, layout->leftmargin); //left margin
1562 swf_SetU16(tag, layout->rightmargin); //right margin
1563 swf_SetU16(tag, layout->indent); //indent
1564 swf_SetU16(tag, layout->leading); //leading
1566 swf_SetString(tag, (U8*)variable);
1567 if (flags & ET_HASTEXT)
1568 swf_SetString(tag, (U8*)text);
1571 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1575 U8 *utext = (U8 *) strdup(text);
1581 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1582 ystep = font->layout->leading;
1584 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1585 /* Hm, without layout information, we can't compute a bounding
1586 box. We could call swf_FontCreateLayout to create a layout,
1587 but the caller probably doesn't want us to mess up his font
1590 r.xmin = r.ymin = 0;
1591 r.xmax = r.ymax = 1024 * 20;
1595 swf_SetRect(tag, &r);
1597 /* The text matrix is pretty boring, as it doesn't apply to
1598 individual characters, but rather whole text objects (or
1599 at least whole char records- haven't tested).
1600 So it can't do anything which we can't already do with
1601 the placeobject tag we use for placing the text on the scene.
1603 swf_SetMatrix(tag, 0);
1605 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1606 swf_SetU8(tag, gbits);
1607 swf_SetU8(tag, abits);
1613 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1616 while(*next && *next!=13 && *next!=10 && count<127) {
1617 readUTF8char(&next);
1620 if(next[0] == 13 || next[0] == 10) {
1625 if(next[0] == 13 && next[1] == 10)
1628 if(next[0] == 13 || next[0] == 10) {
1633 /* now set the text params- notice that a font size of
1634 1024 means that the glyphs will be displayed exactly
1635 as they would be in/with a defineshape. (Try to find
1636 *that* in the flash specs)
1638 /* set the actual text- notice that we just pass our scale
1639 parameter over, as TextSetCharRecord calculates with
1641 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1651 void swf_FontCreateLayout(SWFFONT * f)
1660 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1661 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1662 f->layout->ascent = -32767;
1663 f->layout->descent = -32767;
1665 for (t = 0; t < f->numchars; t++) {
1669 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1671 fprintf(stderr, "Shape parse error\n");
1674 bbox = swf_GetShapeBoundingBox(shape2);
1675 swf_Shape2Free(shape2);
1676 f->layout->bounds[t] = bbox;
1678 width = (bbox.xmax);
1680 /* The following is a heuristic- it may be that extractfont_DefineText
1681 has already found out some widths for individual characters (from the way
1682 they are used)- we now have to guess whether that width might be possible,
1683 which is the case if it isn't either much too big or much too small */
1684 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1685 f->glyph[t].advance = width;
1687 if (-bbox.ymin > f->layout->ascent)
1688 f->layout->ascent = bbox.ymin;
1689 if (bbox.ymax > f->layout->descent)
1690 f->layout->descent = bbox.ymax;
1694 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1696 U8 *s = (U8 *) text;
1702 U32 c = readUTF8char(&s);
1703 int g = font->ascii2glyph[c];
1704 shape = font->glyph[g].shape;
1705 if (((int) g) < 0) {
1706 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1709 shape2 = swf_ShapeToShape2(shape);
1712 if (l->type == moveTo) {
1714 to.x = l->x * size / 100.0 / 20.0 + advance;
1715 to.y = l->y * size / 100.0 / 20.0;
1716 draw->moveTo(draw, &to);
1717 } else if (l->type == lineTo) {
1719 to.x = l->x * size / 100.0 / 20.0 + advance;
1720 to.y = l->y * size / 100.0 / 20.0;
1721 draw->lineTo(draw, &to);
1722 } else if (l->type == splineTo) {
1724 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1725 mid.y = l->sy * size / 100.0 / 20.0;
1726 to.x = l->x * size / 100.0 / 20.0 + advance;
1727 to.y = l->y * size / 100.0 / 20.0;
1728 draw->splineTo(draw, &mid, &to);
1732 swf_Shape2Free(shape2);
1733 advance += font->glyph[g].advance * size / 100.0 / 20.0;