5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9 Copyright (c) 2003,2004 Matthias Kramm
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../rfxswf.h"
27 U32 readUTF8char(U8 ** text)
30 if (!(*(*text) & 0x80))
33 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
34 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
35 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
39 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
40 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
41 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
45 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
46 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
48 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
52 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
53 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
56 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
60 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
61 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
63 && (*text)[4] && (*text)[5]) {
64 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
65 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
72 #define TF_TEXTCONTROL 0x80
73 #define TF_HASFONT 0x08
74 #define TF_HASCOLOR 0x04
75 #define TF_HASYOFFSET 0x02
76 #define TF_HASXOFFSET 0x01
78 #define FF_WIDECODES 0x01
80 #define FF_ITALIC 0x04
82 #define FF_SHIFTJIS 0x10
83 #define FF_UNICODE 0x20
86 #define FF2_ITALIC 0x02
87 #define FF2_WIDECODES 0x04
88 #define FF2_WIDEOFFSETS 0x08
90 #define FF2_UNICODE 0x20
91 #define FF2_SHIFTJIS 0x40
92 #define FF2_LAYOUT 0x80
94 int swf_FontIsItalic(SWFFONT * f)
96 return f->style & FONT_STYLE_ITALIC;
99 int swf_FontIsBold(SWFFONT * f)
101 return f->style & FONT_STYLE_BOLD;
104 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
106 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
116 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
126 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
129 swf_GetBlock(t, s, l);
133 (FontCallback) (self, id, s);
141 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
147 if ((!id) || (id == fid)) {
158 f->glyph = (SWFGLYPH*)rfx_calloc(sizeof(SWFGLYPH) * n);
160 for (i = 1; i < n; i++)
162 for (i = 0; i < n; i++)
163 swf_GetSimpleShape(t, &f->glyph[i].shape);
168 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
180 if (f->version > 1) {
181 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
182 too. However, they only add little information to what's already
183 inside the DefineFont2 tag */
190 f->name = (U8 *) rfx_alloc(l + 1);
191 swf_GetBlock(t, f->name, l);
194 flags = swf_GetU8(t);
196 f->style |= FONT_STYLE_BOLD;
198 f->style |= FONT_STYLE_ITALIC;
200 f->encoding |= FONT_ENCODING_ANSI;
202 f->encoding |= FONT_ENCODING_SHIFTJIS;
204 f->encoding |= FONT_ENCODING_UNICODE;
206 if (t->id == ST_DEFINEFONTINFO2) {
207 f->language = swf_GetU8(t);
210 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
212 for (i = 0; i < f->numchars; i++) {
213 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
214 if (f->glyph2ascii[i] > maxcode)
215 maxcode = f->glyph2ascii[i];
220 f->maxascii = maxcode;
221 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
222 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
224 for (i = 0; i < f->numchars; i++)
225 f->ascii2glyph[f->glyph2ascii[i]] = i;
230 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
233 swf_SetTagPos(tag, 0);
235 fid = swf_GetU16(tag);
238 int num = swf_GetU16(tag);
240 f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num);
241 for (t = 0; t < num; t++) {
242 f->glyphnames[t] = strdup(swf_GetString(tag));
249 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
256 U8 flags1, flags2, namelen;
257 swf_SetTagPos(tag, 0);
259 fid = swf_GetU16(tag);
263 flags1 = swf_GetU8(tag);
264 flags2 = swf_GetU8(tag); //reserved flags
267 font->style |= FONT_STYLE_BOLD;
269 font->style |= FONT_STYLE_ITALIC;
271 font->encoding |= FONT_ENCODING_ANSI;
273 font->encoding |= FONT_ENCODING_UNICODE;
275 font->encoding |= FONT_ENCODING_SHIFTJIS;
277 namelen = swf_GetU8(tag);
278 font->name = (U8 *) rfx_alloc(namelen + 1);
279 font->name[namelen] = 0;
280 swf_GetBlock(tag, font->name, namelen);
282 glyphcount = swf_GetU16(tag);
283 font->numchars = glyphcount;
285 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
286 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
288 offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
289 offset_start = tag->pos;
291 if (flags1 & 8) { // wide offsets
292 for (t = 0; t < glyphcount; t++)
293 offset[t] = swf_GetU32(tag); //offset[t]
295 if (glyphcount) /* this _if_ is not in the specs */
296 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
298 offset[glyphcount] = tag->pos;
300 for (t = 0; t < glyphcount; t++)
301 offset[t] = swf_GetU16(tag); //offset[t]
303 if (glyphcount) /* this _if_ is not in the specs */
304 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
306 offset[glyphcount] = tag->pos;
308 for (t = 0; t < glyphcount; t++) {
309 swf_SetTagPos(tag, offset[t]+offset_start);
310 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
313 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
318 for (t = 0; t < glyphcount; t++) {
320 if (flags1 & 4) // wide codes
321 code = swf_GetU16(tag);
323 code = swf_GetU8(tag);
324 font->glyph2ascii[t] = code;
331 font->maxascii = maxcode;
332 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
333 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
334 for (t = 0; t < glyphcount; t++) {
335 font->ascii2glyph[font->glyph2ascii[t]] = t;
338 if (flags1 & 128) { // has layout
340 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
341 font->layout->ascent = swf_GetU16(tag);
342 font->layout->descent = swf_GetU16(tag);
343 font->layout->leading = swf_GetU16(tag);
344 for (t = 0; t < glyphcount; t++) {
345 S16 advance = swf_GetS16(tag);
346 font->glyph[t].advance = advance;
348 font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
349 for (t = 0; t < glyphcount; t++) {
350 swf_ResetReadBits(tag);
351 swf_GetRect(tag, &font->layout->bounds[t]);
354 kerningcount = swf_GetU16(tag);
355 font->layout->kerningcount = kerningcount;
357 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
359 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
360 for (t = 0; t < kerningcount; t++) {
361 if (flags1 & 4) { // wide codes
362 font->layout->kerning[t].char1 = swf_GetU16(tag);
363 font->layout->kerning[t].char2 = swf_GetU16(tag);
365 font->layout->kerning[t].char1 = swf_GetU8(tag);
366 font->layout->kerning[t].char2 = swf_GetU8(tag);
368 font->layout->kerning[t].adjustment = swf_GetS16(tag);
376 #define FEDTJ_PRINT 0x01
377 #define FEDTJ_MODIFY 0x02
378 #define FEDTJ_CALLBACK 0x04
381 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
382 void (*callback) (void *self,
383 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
394 memset(&color, 0, sizeof(color));
400 swf_GetMatrix(t, &m);
401 gbits = swf_GetU8(t);
402 abits = swf_GetU8(t);
406 flags = swf_GetU8(t);
410 if (flags & TF_TEXTCONTROL) {
411 if (flags & TF_HASFONT)
413 if (flags & TF_HASCOLOR) {
414 color.r = swf_GetU8(t); // rgb
415 color.g = swf_GetU8(t);
416 color.b = swf_GetU8(t);
417 if (swf_GetTagID(t) == ST_DEFINETEXT2)
418 color.a = swf_GetU8(t);
422 if (flags & TF_HASXOFFSET)
424 if (flags & TF_HASYOFFSET)
426 if (flags & TF_HASFONT)
427 fontsize = swf_GetU16(t);
439 for (i = 0; i < num; i++) {
443 glyph = swf_GetBits(t, gbits);
444 adv = swf_GetBits(t, abits);
448 if (jobs & FEDTJ_PRINT) {
449 int code = f->glyph2ascii[glyph];
452 if (jobs & FEDTJ_MODIFY)
453 f->glyph[glyph].advance = adv * 20; //?
458 if ((id == fid) && (jobs & FEDTJ_PRINT))
460 if (jobs & FEDTJ_CALLBACK)
461 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
469 int swf_ParseDefineText(TAG * tag,
470 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
472 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
475 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
477 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
480 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
485 if ((!swf) || (!font))
488 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
494 switch (swf_GetTagID(t)) {
496 nid = swf_FontExtract_DefineFont(id, f, t);
500 nid = swf_FontExtract_DefineFont2(id, f, t);
503 case ST_DEFINEFONTINFO:
504 case ST_DEFINEFONTINFO2:
505 nid = swf_FontExtract_DefineFontInfo(id, f, t);
510 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
514 nid = swf_FontExtract_GlyphNames(id, f, t);
529 int swf_FontSetID(SWFFONT * f, U16 id)
537 void swf_LayoutFree(SWFLAYOUT * l)
541 rfx_free(l->kerning);
551 static void font_freeglyphnames(SWFFONT*f)
556 for (t = 0; t < f->numchars; t++)
558 if (f->glyphnames[t])
560 rfx_free(f->glyphnames[t]);
561 f->glyphnames[t] = 0;
564 rfx_free(f->glyphnames);
568 static void font_freeusage(SWFFONT*f)
572 rfx_free(f->use->chars);f->use->chars = 0;
574 rfx_free(f->use); f->use = 0;
577 static void font_freelayout(SWFFONT*f)
580 swf_LayoutFree(f->layout);
584 static void font_freename(SWFFONT*f)
592 int swf_FontReduce_old(SWFFONT * f)
596 if ((!f) || (!f->use) || f->use->is_reduced)
601 for (i = 0; i < f->numchars; i++) {
602 if (f->glyph[i].shape && f->use->chars[i]) {
603 f->glyph2ascii[j] = f->glyph2ascii[i];
604 f->glyph[j] = f->glyph[i];
605 f->use->chars[i] = j;
608 f->glyph2ascii[i] = 0;
609 if(f->glyph[i].shape) {
610 swf_ShapeFree(f->glyph[i].shape);
611 f->glyph[i].shape = 0;
612 f->glyph[i].advance = 0;
614 f->use->chars[i] = -1;
618 for (i = 0; i < f->maxascii; i++) {
619 if(f->use->chars[f->ascii2glyph[i]]<0) {
620 f->ascii2glyph[i] = -1;
622 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
626 f->maxascii = max_unicode;
627 f->use->is_reduced = 1;
630 font_freeglyphnames(f);
635 int swf_FontReduce_swfc(SWFFONT * f)
639 if ((!f) || (!f->use) || f->use->is_reduced)
642 font_freeglyphnames(f);
645 for (i = 0; i < f->numchars; i++) {
646 if (f->glyph[i].shape && f->use->chars[i]) {
647 f->glyph2ascii[j] = f->glyph2ascii[i];
649 f->layout->bounds[j] = f->layout->bounds[i];
650 f->glyph[j] = f->glyph[i];
651 f->use->chars[i] = j;
654 f->glyph2ascii[i] = 0;
655 if(f->glyph[i].shape) {
656 swf_ShapeFree(f->glyph[i].shape);
657 f->glyph[i].shape = 0;
658 f->glyph[i].advance = 0;
660 f->use->chars[i] = -1;
663 f->use->used_glyphs = j;
664 for (i = 0; i < f->maxascii; i++) {
665 if(f->ascii2glyph[i] > -1) {
666 if (f->use->chars[f->ascii2glyph[i]]<0) {
667 f->use->chars[f->ascii2glyph[i]] = 0;
668 f->ascii2glyph[i] = -1;
670 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
671 f->use->chars[f->ascii2glyph[i]] = 1;
676 f->maxascii = max_unicode;
677 f->use->is_reduced = 1;
683 int swf_FontReduce(SWFFONT * f)
688 if ((!f) || (!f->use) || f->use->is_reduced)
692 font_freeglyphnames(f);
694 f->use->used_glyphs= 0;
695 for (i = 0; i < f->numchars; i++) {
696 if(!f->use->chars[i]) {
698 f->glyph2ascii[i] = 0;
700 if(f->glyph[i].shape) {
701 swf_ShapeFree(f->glyph[i].shape);
702 f->glyph[i].shape = 0;
703 f->glyph[i].advance = 0;
705 // f->use->used_glyphs++;
707 f->use->used_glyphs++;
711 for (i = 0; i < f->maxascii; i++) {
712 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
714 f->ascii2glyph[i] = -1;
720 f->maxascii = max_unicode;
721 f->numchars = max_glyph;
726 void swf_FontSort(SWFFONT * font)
734 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
736 for (i = 0; i < font->numchars; i++) {
739 for (i = 0; i < font->numchars; i++)
740 for (j = 0; j < i; j++) {
741 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
750 n1 = font->glyph2ascii[i];
751 n2 = font->glyph2ascii[j];
752 font->glyph2ascii[j] = n1;
753 font->glyph2ascii[i] = n2;
758 if (font->glyphnames) {
759 c1 = font->glyphnames[i];
760 c2 = font->glyphnames[j];
761 font->glyphnames[j] = c1;
762 font->glyphnames[i] = c2;
765 r1 = font->layout->bounds[i];
766 r2 = font->layout->bounds[j];
767 font->layout->bounds[j] = r1;
768 font->layout->bounds[i] = r2;
772 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
773 for (i = 0; i < font->numchars; i++) {
774 newpos[newplace[i]] = i;
776 for (i = 0; i < font->maxascii; i++) {
777 if (font->ascii2glyph[i] >= 0)
778 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
785 void swf_FontPrepareForEditText(SWFFONT * font)
788 swf_FontCreateLayout(font);
792 int swf_FontInitUsage(SWFFONT * f)
797 fprintf(stderr, "Usage initialized twice");
800 f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
801 f->use->is_reduced = 0;
802 f->use->used_glyphs = 0;
803 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
804 f->use->glyphs_specified = 0;
808 void swf_FontClearUsage(SWFFONT * f)
812 rfx_free(f->use->chars); f->use->chars = 0;
813 rfx_free(f->use); f->use = 0;
816 int swf_FontUse(SWFFONT * f, U8 * s)
821 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
822 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
828 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
835 ascii = readUTF8char(&s);
836 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
837 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
842 int swf_FontUseAll(SWFFONT* f)
847 swf_FontInitUsage(f);
848 for (i = 0; i < f->numchars; i++)
849 f->use->chars[i] = 1;
850 f->use->used_glyphs = f->numchars;
854 int swf_FontUseGlyph(SWFFONT * f, int glyph)
857 swf_FontInitUsage(f);
858 if(glyph < 0 || glyph >= f->numchars)
860 if(!f->use->chars[glyph])
861 f->use->used_glyphs++;
862 f->use->chars[glyph] = 1;
866 int swf_FontSetDefine(TAG * t, SWFFONT * f)
868 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
873 swf_ResetWriteBits(t);
874 swf_SetU16(t, f->id);
878 for (i = 0; i < f->numchars; i++)
879 if (f->glyph[i].shape) {
881 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
884 for (i = 0; i < j; i++)
885 swf_SetU16(t, ofs[i] + j * 2);
887 fprintf(stderr, "rfxswf: warning: Font is empty\n");
891 for (i = 0; i < f->numchars; i++)
892 if (f->glyph[i].shape)
893 swf_SetSimpleShape(t, f->glyph[i].shape);
895 swf_ResetWriteBits(t);
900 static inline int fontSize(SWFFONT * font)
904 for (t = 0; t < font->numchars; t++) {
906 if(font->glyph[t].shape)
907 l = (font->glyph[t].shape->bitlen + 7) / 8;
912 return size + (font->numchars + 1) * 2;
915 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
920 swf_SetU16(tag, f->id);
922 if (f->layout) flags |= 128; // haslayout
923 if (f->numchars > 256)
924 flags |= 4; // widecodes
925 if (f->style & FONT_STYLE_BOLD)
927 if (f->style & FONT_STYLE_ITALIC)
928 flags |= 2; // italic
929 if (f->maxascii >= 256)
930 flags |= 4; //wide codecs
931 if (fontSize(f) > 65535)
932 flags |= 8; //wide offsets
933 flags |= 8 | 4; //FIXME: the above check doesn't work
935 if (f->encoding & FONT_ENCODING_ANSI)
937 if (f->encoding & FONT_ENCODING_UNICODE)
938 flags |= 32; // unicode
939 if (f->encoding & FONT_ENCODING_SHIFTJIS)
940 flags |= 64; // shiftjis
942 swf_SetU8(tag, flags);
943 swf_SetU8(tag, 0); //reserved flags
946 swf_SetU8(tag, strlen((const char*)f->name)+1);
947 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
949 /* font name (="") */
953 /* number of glyphs */
954 swf_SetU16(tag, f->numchars);
955 /* font offset table */
957 for (t = 0; t <= f->numchars; t++) {
959 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
961 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
964 for (t = 0; t <= f->numchars; t++) {
966 tag->data[pos + t * 4] = (tag->len - pos);
967 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
968 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
969 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
971 if (tag->len - pos > 65535) {
972 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
975 tag->data[pos + t * 2] = (tag->len - pos);
976 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
978 if (t < f->numchars) {
979 if(f->glyph[t].shape) {
980 swf_SetSimpleShape(tag, f->glyph[t].shape);
982 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
988 /* font code table */
989 for (t = 0; t < f->numchars; t++) {
990 if (flags & 4) { /* wide codes */
991 if(f->glyph2ascii[t]) {
992 swf_SetU16(tag, f->glyph2ascii[t]);
997 if(f->glyph2ascii[t]) {
998 swf_SetU8(tag, f->glyph2ascii[t]);
1006 swf_SetU16(tag, f->layout->ascent);
1007 swf_SetU16(tag, f->layout->descent);
1008 swf_SetU16(tag, f->layout->leading);
1009 for (t = 0; t < f->numchars; t++)
1010 swf_SetU16(tag, f->glyph[t].advance);
1011 for (t = 0; t < f->numchars; t++) {
1012 swf_ResetWriteBits(tag);
1013 swf_SetRect(tag, &f->layout->bounds[t]);
1015 swf_SetU16(tag, f->layout->kerningcount);
1016 for (t = 0; t < f->layout->kerningcount; t++) {
1017 if (flags & 4) { /* wide codes */
1018 swf_SetU16(tag, f->layout->kerning[t].char1);
1019 swf_SetU16(tag, f->layout->kerning[t].char2);
1021 swf_SetU8(tag, f->layout->kerning[t].char1);
1022 swf_SetU8(tag, f->layout->kerning[t].char2);
1024 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1030 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1032 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1033 f->layout->ascent = ascent;
1034 f->layout->descent = descent;
1035 f->layout->leading = leading;
1036 f->layout->kerningcount = 0;
1037 f->layout->kerning = 0;
1038 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1041 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1048 swf_ResetWriteBits(t);
1049 swf_SetU16(t, f->id);
1050 l = f->name ? strlen((const char *)f->name) : 0;
1055 swf_SetBlock(t, f->name, l);
1056 if (f->numchars >= 256)
1059 if (f->style & FONT_STYLE_BOLD)
1061 if (f->style & FONT_STYLE_ITALIC)
1063 if (f->style & FONT_ENCODING_ANSI)
1065 if (f->style & FONT_ENCODING_SHIFTJIS)
1067 if (f->style & FONT_ENCODING_UNICODE)
1070 swf_SetU8(t, (flags & 0xfe) | wide);
1072 for (i = 0; i < f->numchars; i++) {
1073 if (f->glyph[i].shape) {
1074 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1075 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1082 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1084 int id = swf_GetTagID(t);
1085 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1086 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1092 void swf_FontFree(SWFFONT * f)
1100 for (i = 0; i < f->numchars; i++)
1101 if (f->glyph[i].shape)
1103 swf_ShapeFree(f->glyph[i].shape);
1104 f->glyph[i].shape = NULL;
1111 rfx_free(f->ascii2glyph);
1112 f->ascii2glyph = NULL;
1116 rfx_free(f->glyph2ascii);
1117 f->glyph2ascii = NULL;
1121 font_freeglyphnames(f);
1127 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1133 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1134 | (y ? TF_HASYOFFSET : 0);
1136 swf_SetU8(t, flags);
1138 swf_SetU16(t, font->id);
1140 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1141 swf_SetRGBA(t, color);
1143 swf_SetRGB(t, color);
1146 if(x != SET_TO_ZERO) {
1147 if(x>32767 || x<-32768)
1148 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1155 if(y != SET_TO_ZERO) {
1156 if(y>32767 || y<-32768)
1157 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1164 swf_SetU16(t, size);
1169 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1173 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1177 if (!strcmp(encoding, "UTF8"))
1179 else if (!strcmp(encoding, "iso-8859-1"))
1182 fprintf(stderr, "Unknown encoding: %s", encoding);
1190 c = readUTF8char(&s);
1192 if (c < font->maxascii)
1193 glyph = font->ascii2glyph[c];
1195 g = swf_CountUBits(glyph, g);
1196 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1207 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1212 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1215 if (!strcmp(encoding, "UTF8"))
1217 else if (!strcmp(encoding, "iso-8859-1"))
1220 fprintf(stderr, "Unknown encoding: %s", encoding);
1223 swf_SetU8(t, l); //placeholder
1231 c = readUTF8char(&s);
1233 if (c < font->maxascii)
1234 g = font->ascii2glyph[c];
1236 swf_SetBits(t, g, gbits);
1237 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1239 /* We split into 127 characters per text field.
1240 We could do 255, by the (formerly wrong) flash specification,
1241 but some SWF parsing code out there still assumes that char blocks
1242 are at max 127 characters, and it would save only a few bits.
1249 PUT8(&t->data[pos], l);
1251 swf_ResetWriteBits(t);
1255 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1257 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1260 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1262 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1265 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1267 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1270 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1272 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1275 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1282 if (*s < font->maxascii)
1283 g = font->ascii2glyph[*s];
1285 res += font->glyph[g].advance / 20;
1289 res = (res * scale) / 100;
1294 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1301 int c = readUTF8char(&s);
1302 if(c==13 || c==10) {
1307 ypos+=font->layout->leading;
1310 if (c < font->maxascii) {
1311 int g = font->ascii2glyph[c];
1313 SRECT rn = font->layout->bounds[g];
1314 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1315 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1316 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1317 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1318 swf_ExpandRect2(&r, &rn);
1319 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1327 SWFFONT *swf_ReadFont(char *filename)
1333 f = open(filename, O_RDONLY|O_BINARY);
1335 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1336 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1342 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1349 void swf_WriteFont(SWFFONT * font, char *filename)
1356 int useDefineFont2 = 0;
1357 int storeGlyphNames = 1;
1360 useDefineFont2 = 1; /* the only thing new in definefont2
1361 is layout information. */
1363 font->id = WRITEFONTID; //"FN"
1365 memset(&swf, 0x00, sizeof(SWF));
1367 swf.fileVersion = 4;
1368 swf.frameRate = 0x4000;
1370 /* if we use DefineFont1 to store the characters,
1371 we have to build a textfield to store the
1372 advance values. While at it, we can also
1373 make the whole .swf viewable */
1375 /* we now always create viewable swfs, even if we
1376 did use definefont2 -mk */
1377 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1382 swf_SetRGB(t, &rgb);
1383 if (!useDefineFont2) {
1384 t = swf_InsertTag(t, ST_DEFINEFONT);
1385 swf_FontSetDefine(t, font);
1386 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1387 swf_FontSetInfo(t, font);
1389 t = swf_InsertTag(t, ST_DEFINEFONT2);
1390 swf_FontSetDefine2(t, font);
1393 if (storeGlyphNames && font->glyphnames) {
1395 t = swf_InsertTag(t, ST_GLYPHNAMES);
1396 swf_SetU16(t, WRITEFONTID);
1397 swf_SetU16(t, font->numchars);
1398 for (c = 0; c < font->numchars; c++) {
1399 if (font->glyphnames[c])
1400 swf_SetString(t, (U8*)font->glyphnames[c]);
1402 swf_SetString(t, (U8*)"");
1406 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1408 int textscale = 400;
1415 int range = font->maxascii;
1418 if (useDefineFont2 && range > 256) {
1422 for (s = 0; s < range; s++) {
1423 int g = font->ascii2glyph[s];
1425 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1426 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1430 if ((s & 15) == 0) {
1437 ymax = ypos * textscale * 2;
1439 swf.movieSize.xmax = xmax * 20;
1440 swf.movieSize.ymax = ymax;
1442 t = swf_InsertTag(t, ST_DEFINETEXT);
1444 swf_SetU16(t, font->id + 1); // ID
1448 r.xmax = swf.movieSize.xmax;
1449 r.ymax = swf.movieSize.ymax;
1453 swf_SetMatrix(t, NULL);
1455 abits = swf_CountBits(xmax * 16, 0);
1458 swf_SetU8(t, gbits);
1459 swf_SetU8(t, abits);
1465 for (y = 0; y < ((range + 15) / 16); y++) {
1466 int c = 0, lastx = -1;
1467 for (x = 0; x < 16; x++) {
1468 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1469 if (g >= 0 && font->glyph[g].shape) {
1476 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1477 for (x = 0; x < 16; x++) {
1478 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1479 if (g >= 0 && font->glyph[g].shape) {
1480 if (lastx != x * xmax) {
1481 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1484 swf_SetBits(t, g, gbits);
1485 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1486 lastx = x * xmax + (font->glyph[g].advance / 20);
1487 swf_ResetWriteBits(t);
1496 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1498 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1500 t = swf_InsertTag(t, ST_SHOWFRAME);
1504 t = swf_InsertTag(t, ST_END);
1506 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1508 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1515 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1517 swf_SetRect(tag, &r);
1518 swf_ResetWriteBits(tag);
1520 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1522 flags |= ET_HASTEXT;
1524 flags |= ET_HASTEXTCOLOR;
1526 flags |= ET_HASMAXLENGTH;
1528 flags |= ET_HASFONT;
1530 flags |= ET_HASLAYOUT;
1532 swf_SetBits(tag, flags, 16);
1534 if (flags & ET_HASFONT) {
1535 swf_SetU16(tag, font); //font
1536 swf_SetU16(tag, height); //fontheight
1538 if (flags & ET_HASTEXTCOLOR) {
1539 swf_SetRGBA(tag, color);
1541 if (flags & ET_HASMAXLENGTH) {
1542 swf_SetU16(tag, maxlength); //maxlength
1544 if (flags & ET_HASLAYOUT) {
1545 swf_SetU8(tag, layout->align); //align
1546 swf_SetU16(tag, layout->leftmargin); //left margin
1547 swf_SetU16(tag, layout->rightmargin); //right margin
1548 swf_SetU16(tag, layout->indent); //indent
1549 swf_SetU16(tag, layout->leading); //leading
1551 swf_SetString(tag, (U8*)variable);
1552 if (flags & ET_HASTEXT)
1553 swf_SetString(tag, (U8*)text);
1556 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1560 U8 *utext = (U8 *) strdup(text);
1566 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1567 ystep = font->layout->leading;
1569 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1570 /* Hm, without layout information, we can't compute a bounding
1571 box. We could call swf_FontCreateLayout to create a layout,
1572 but the caller probably doesn't want us to mess up his font
1575 r.xmin = r.ymin = 0;
1576 r.xmax = r.ymax = 1024 * 20;
1580 swf_SetRect(tag, &r);
1582 /* The text matrix is pretty boring, as it doesn't apply to
1583 individual characters, but rather whole text objects (or
1584 at least whole char records- haven't tested).
1585 So it can't do anything which we can't already do with
1586 the placeobject tag we use for placing the text on the scene.
1588 swf_SetMatrix(tag, 0);
1590 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1591 swf_SetU8(tag, gbits);
1592 swf_SetU8(tag, abits);
1598 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1601 while(*next && *next!=13 && *next!=10 && count<127) {
1602 readUTF8char(&next);
1605 if(next[0] == 13 || next[0] == 10) {
1610 if(next[0] == 13 && next[1] == 10)
1613 if(next[0] == 13 || next[0] == 10) {
1618 /* now set the text params- notice that a font size of
1619 1024 means that the glyphs will be displayed exactly
1620 as they would be in/with a defineshape. (Try to find
1621 *that* in the flash specs)
1623 /* set the actual text- notice that we just pass our scale
1624 parameter over, as TextSetCharRecord calculates with
1626 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1636 void swf_FontCreateLayout(SWFFONT * f)
1645 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1646 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1647 f->layout->ascent = -32767;
1648 f->layout->descent = -32767;
1650 for (t = 0; t < f->numchars; t++) {
1654 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1656 fprintf(stderr, "Shape parse error\n");
1659 bbox = swf_GetShapeBoundingBox(shape2);
1660 swf_Shape2Free(shape2);
1661 f->layout->bounds[t] = bbox;
1663 width = (bbox.xmax);
1665 /* The following is a heuristic- it may be that extractfont_DefineText
1666 has already found out some widths for individual characters (from the way
1667 they are used)- we now have to guess whether that width might be possible,
1668 which is the case if it isn't either much too big or much too small */
1669 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1670 f->glyph[t].advance = width;
1672 if (-bbox.ymin > f->layout->ascent)
1673 f->layout->ascent = bbox.ymin;
1674 if (bbox.ymax > f->layout->descent)
1675 f->layout->descent = bbox.ymax;
1679 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1681 U8 *s = (U8 *) text;
1687 U32 c = readUTF8char(&s);
1688 int g = font->ascii2glyph[c];
1689 shape = font->glyph[g].shape;
1690 if (((int) g) < 0) {
1691 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1694 shape2 = swf_ShapeToShape2(shape);
1697 if (l->type == moveTo) {
1699 to.x = l->x * size / 100.0 / 20.0 + advance;
1700 to.y = l->y * size / 100.0 / 20.0;
1701 draw->moveTo(draw, &to);
1702 } else if (l->type == lineTo) {
1704 to.x = l->x * size / 100.0 / 20.0 + advance;
1705 to.y = l->y * size / 100.0 / 20.0;
1706 draw->lineTo(draw, &to);
1707 } else if (l->type == splineTo) {
1709 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1710 mid.y = l->sy * size / 100.0 / 20.0;
1711 to.x = l->x * size / 100.0 / 20.0 + advance;
1712 to.y = l->y * size / 100.0 / 20.0;
1713 draw->splineTo(draw, &mid, &to);
1717 swf_Shape2Free(shape2);
1718 advance += font->glyph[g].advance * size / 100.0 / 20.0;