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);
807 void swf_FontClearUsage(SWFFONT * f)
811 rfx_free(f->use->chars); f->use->chars = 0;
812 rfx_free(f->use); f->use = 0;
815 int swf_FontUse(SWFFONT * f, U8 * s)
820 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
821 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
827 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
834 ascii = readUTF8char(&s);
835 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
836 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
841 int swf_FontUseAll(SWFFONT* f)
846 swf_FontInitUsage(f);
847 for (i = 0; i < f->numchars; i++)
848 f->use->chars[i] = 1;
849 f->use->used_glyphs = f->numchars;
853 int swf_FontUseGlyph(SWFFONT * f, int glyph)
856 swf_FontInitUsage(f);
857 if(glyph < 0 || glyph >= f->numchars)
859 if(!f->use->chars[glyph])
860 f->use->used_glyphs++;
861 f->use->chars[glyph] = 1;
865 int swf_FontSetDefine(TAG * t, SWFFONT * f)
867 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
872 swf_ResetWriteBits(t);
873 swf_SetU16(t, f->id);
877 for (i = 0; i < f->numchars; i++)
878 if (f->glyph[i].shape) {
880 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
883 for (i = 0; i < j; i++)
884 swf_SetU16(t, ofs[i] + j * 2);
886 fprintf(stderr, "rfxswf: warning: Font is empty\n");
890 for (i = 0; i < f->numchars; i++)
891 if (f->glyph[i].shape)
892 swf_SetSimpleShape(t, f->glyph[i].shape);
894 swf_ResetWriteBits(t);
899 static inline int fontSize(SWFFONT * font)
903 for (t = 0; t < font->numchars; t++) {
905 if(font->glyph[t].shape)
906 l = (font->glyph[t].shape->bitlen + 7) / 8;
911 return size + (font->numchars + 1) * 2;
914 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
919 swf_SetU16(tag, f->id);
921 if (f->layout) flags |= 128; // haslayout
922 if (f->numchars > 256)
923 flags |= 4; // widecodes
924 if (f->style & FONT_STYLE_BOLD)
926 if (f->style & FONT_STYLE_ITALIC)
927 flags |= 2; // italic
928 if (f->maxascii >= 256)
929 flags |= 4; //wide codecs
930 if (fontSize(f) > 65535)
931 flags |= 8; //wide offsets
932 flags |= 8 | 4; //FIXME: the above check doesn't work
934 if (f->encoding & FONT_ENCODING_ANSI)
936 if (f->encoding & FONT_ENCODING_UNICODE)
937 flags |= 32; // unicode
938 if (f->encoding & FONT_ENCODING_SHIFTJIS)
939 flags |= 64; // shiftjis
941 swf_SetU8(tag, flags);
942 swf_SetU8(tag, 0); //reserved flags
945 swf_SetU8(tag, strlen((const char*)f->name)+1);
946 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
948 /* font name (="") */
952 /* number of glyphs */
953 swf_SetU16(tag, f->numchars);
954 /* font offset table */
956 for (t = 0; t <= f->numchars; t++) {
958 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
960 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
963 for (t = 0; t <= f->numchars; t++) {
965 tag->data[pos + t * 4] = (tag->len - pos);
966 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
967 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
968 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
970 if (tag->len - pos > 65535) {
971 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
974 tag->data[pos + t * 2] = (tag->len - pos);
975 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
977 if (t < f->numchars) {
978 if(f->glyph[t].shape) {
979 swf_SetSimpleShape(tag, f->glyph[t].shape);
981 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
987 /* font code table */
988 for (t = 0; t < f->numchars; t++) {
989 if (flags & 4) { /* wide codes */
990 if(f->glyph2ascii[t]) {
991 swf_SetU16(tag, f->glyph2ascii[t]);
996 if(f->glyph2ascii[t]) {
997 swf_SetU8(tag, f->glyph2ascii[t]);
1005 swf_SetU16(tag, f->layout->ascent);
1006 swf_SetU16(tag, f->layout->descent);
1007 swf_SetU16(tag, f->layout->leading);
1008 for (t = 0; t < f->numchars; t++)
1009 swf_SetU16(tag, f->glyph[t].advance);
1010 for (t = 0; t < f->numchars; t++) {
1011 swf_ResetWriteBits(tag);
1012 swf_SetRect(tag, &f->layout->bounds[t]);
1014 swf_SetU16(tag, f->layout->kerningcount);
1015 for (t = 0; t < f->layout->kerningcount; t++) {
1016 if (flags & 4) { /* wide codes */
1017 swf_SetU16(tag, f->layout->kerning[t].char1);
1018 swf_SetU16(tag, f->layout->kerning[t].char2);
1020 swf_SetU8(tag, f->layout->kerning[t].char1);
1021 swf_SetU8(tag, f->layout->kerning[t].char2);
1023 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1029 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1031 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1032 f->layout->ascent = ascent;
1033 f->layout->descent = descent;
1034 f->layout->leading = leading;
1035 f->layout->kerningcount = 0;
1036 f->layout->kerning = 0;
1037 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1040 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1047 swf_ResetWriteBits(t);
1048 swf_SetU16(t, f->id);
1049 l = f->name ? strlen((const char *)f->name) : 0;
1054 swf_SetBlock(t, f->name, l);
1055 if (f->numchars >= 256)
1058 if (f->style & FONT_STYLE_BOLD)
1060 if (f->style & FONT_STYLE_ITALIC)
1062 if (f->style & FONT_ENCODING_ANSI)
1064 if (f->style & FONT_ENCODING_SHIFTJIS)
1066 if (f->style & FONT_ENCODING_UNICODE)
1069 swf_SetU8(t, (flags & 0xfe) | wide);
1071 for (i = 0; i < f->numchars; i++) {
1072 if (f->glyph[i].shape) {
1073 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1074 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1081 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1083 int id = swf_GetTagID(t);
1084 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1085 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1091 void swf_FontFree(SWFFONT * f)
1099 for (i = 0; i < f->numchars; i++)
1100 if (f->glyph[i].shape)
1102 swf_ShapeFree(f->glyph[i].shape);
1103 f->glyph[i].shape = NULL;
1110 rfx_free(f->ascii2glyph);
1111 f->ascii2glyph = NULL;
1115 rfx_free(f->glyph2ascii);
1116 f->glyph2ascii = NULL;
1120 font_freeglyphnames(f);
1126 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1132 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1133 | (y ? TF_HASYOFFSET : 0);
1135 swf_SetU8(t, flags);
1137 swf_SetU16(t, font->id);
1139 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1140 swf_SetRGBA(t, color);
1142 swf_SetRGB(t, color);
1145 if(x != SET_TO_ZERO) {
1146 if(x>32767 || x<-32768)
1147 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1154 if(y != SET_TO_ZERO) {
1155 if(y>32767 || y<-32768)
1156 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1163 swf_SetU16(t, size);
1168 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1172 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1176 if (!strcmp(encoding, "UTF8"))
1178 else if (!strcmp(encoding, "iso-8859-1"))
1181 fprintf(stderr, "Unknown encoding: %s", encoding);
1189 c = readUTF8char(&s);
1191 if (c < font->maxascii)
1192 glyph = font->ascii2glyph[c];
1194 g = swf_CountUBits(glyph, g);
1195 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1206 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1211 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1214 if (!strcmp(encoding, "UTF8"))
1216 else if (!strcmp(encoding, "iso-8859-1"))
1219 fprintf(stderr, "Unknown encoding: %s", encoding);
1222 swf_SetU8(t, l); //placeholder
1230 c = readUTF8char(&s);
1232 if (c < font->maxascii)
1233 g = font->ascii2glyph[c];
1235 swf_SetBits(t, g, gbits);
1236 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1238 /* We split into 127 characters per text field.
1239 We could do 255, by the (formerly wrong) flash specification,
1240 but some SWF parsing code out there still assumes that char blocks
1241 are at max 127 characters, and it would save only a few bits.
1248 PUT8(&t->data[pos], l);
1250 swf_ResetWriteBits(t);
1254 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1256 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1259 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1261 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1264 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1266 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1269 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1271 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1274 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1281 if (*s < font->maxascii)
1282 g = font->ascii2glyph[*s];
1284 res += font->glyph[g].advance / 20;
1288 res = (res * scale) / 100;
1293 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1300 int c = readUTF8char(&s);
1301 if(c==13 || c==10) {
1306 ypos+=font->layout->leading;
1309 if (c < font->maxascii) {
1310 int g = font->ascii2glyph[c];
1312 SRECT rn = font->layout->bounds[g];
1313 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1314 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1315 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1316 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1317 swf_ExpandRect2(&r, &rn);
1318 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1326 SWFFONT *swf_ReadFont(char *filename)
1332 f = open(filename, O_RDONLY|O_BINARY);
1334 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1335 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1341 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1348 void swf_WriteFont(SWFFONT * font, char *filename)
1355 int useDefineFont2 = 0;
1356 int storeGlyphNames = 1;
1359 useDefineFont2 = 1; /* the only thing new in definefont2
1360 is layout information. */
1362 font->id = WRITEFONTID; //"FN"
1364 memset(&swf, 0x00, sizeof(SWF));
1366 swf.fileVersion = 4;
1367 swf.frameRate = 0x4000;
1369 /* if we use DefineFont1 to store the characters,
1370 we have to build a textfield to store the
1371 advance values. While at it, we can also
1372 make the whole .swf viewable */
1374 /* we now always create viewable swfs, even if we
1375 did use definefont2 -mk */
1376 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1381 swf_SetRGB(t, &rgb);
1382 if (!useDefineFont2) {
1383 t = swf_InsertTag(t, ST_DEFINEFONT);
1384 swf_FontSetDefine(t, font);
1385 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1386 swf_FontSetInfo(t, font);
1388 t = swf_InsertTag(t, ST_DEFINEFONT2);
1389 swf_FontSetDefine2(t, font);
1392 if (storeGlyphNames && font->glyphnames) {
1394 t = swf_InsertTag(t, ST_GLYPHNAMES);
1395 swf_SetU16(t, WRITEFONTID);
1396 swf_SetU16(t, font->numchars);
1397 for (c = 0; c < font->numchars; c++) {
1398 if (font->glyphnames[c])
1399 swf_SetString(t, (U8*)font->glyphnames[c]);
1401 swf_SetString(t, (U8*)"");
1405 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1407 int textscale = 400;
1414 int range = font->maxascii;
1417 if (useDefineFont2 && range > 256) {
1421 for (s = 0; s < range; s++) {
1422 int g = font->ascii2glyph[s];
1424 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1425 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1429 if ((s & 15) == 0) {
1436 ymax = ypos * textscale * 2;
1438 swf.movieSize.xmax = xmax * 20;
1439 swf.movieSize.ymax = ymax;
1441 t = swf_InsertTag(t, ST_DEFINETEXT);
1443 swf_SetU16(t, font->id + 1); // ID
1447 r.xmax = swf.movieSize.xmax;
1448 r.ymax = swf.movieSize.ymax;
1452 swf_SetMatrix(t, NULL);
1454 abits = swf_CountBits(xmax * 16, 0);
1457 swf_SetU8(t, gbits);
1458 swf_SetU8(t, abits);
1464 for (y = 0; y < ((range + 15) / 16); y++) {
1465 int c = 0, lastx = -1;
1466 for (x = 0; x < 16; x++) {
1467 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1468 if (g >= 0 && font->glyph[g].shape) {
1475 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1476 for (x = 0; x < 16; x++) {
1477 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1478 if (g >= 0 && font->glyph[g].shape) {
1479 if (lastx != x * xmax) {
1480 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1483 swf_SetBits(t, g, gbits);
1484 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1485 lastx = x * xmax + (font->glyph[g].advance / 20);
1486 swf_ResetWriteBits(t);
1495 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1497 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1499 t = swf_InsertTag(t, ST_SHOWFRAME);
1503 t = swf_InsertTag(t, ST_END);
1505 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1507 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1514 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1516 swf_SetRect(tag, &r);
1517 swf_ResetWriteBits(tag);
1519 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1521 flags |= ET_HASTEXT;
1523 flags |= ET_HASTEXTCOLOR;
1525 flags |= ET_HASMAXLENGTH;
1527 flags |= ET_HASFONT;
1529 flags |= ET_HASLAYOUT;
1531 swf_SetBits(tag, flags, 16);
1533 if (flags & ET_HASFONT) {
1534 swf_SetU16(tag, font); //font
1535 swf_SetU16(tag, height); //fontheight
1537 if (flags & ET_HASTEXTCOLOR) {
1538 swf_SetRGBA(tag, color);
1540 if (flags & ET_HASMAXLENGTH) {
1541 swf_SetU16(tag, maxlength); //maxlength
1543 if (flags & ET_HASLAYOUT) {
1544 swf_SetU8(tag, layout->align); //align
1545 swf_SetU16(tag, layout->leftmargin); //left margin
1546 swf_SetU16(tag, layout->rightmargin); //right margin
1547 swf_SetU16(tag, layout->indent); //indent
1548 swf_SetU16(tag, layout->leading); //leading
1550 swf_SetString(tag, (U8*)variable);
1551 if (flags & ET_HASTEXT)
1552 swf_SetString(tag, (U8*)text);
1555 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1559 U8 *utext = (U8 *) strdup(text);
1565 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1566 ystep = font->layout->leading;
1568 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1569 /* Hm, without layout information, we can't compute a bounding
1570 box. We could call swf_FontCreateLayout to create a layout,
1571 but the caller probably doesn't want us to mess up his font
1574 r.xmin = r.ymin = 0;
1575 r.xmax = r.ymax = 1024 * 20;
1579 swf_SetRect(tag, &r);
1581 /* The text matrix is pretty boring, as it doesn't apply to
1582 individual characters, but rather whole text objects (or
1583 at least whole char records- haven't tested).
1584 So it can't do anything which we can't already do with
1585 the placeobject tag we use for placing the text on the scene.
1587 swf_SetMatrix(tag, 0);
1589 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1590 swf_SetU8(tag, gbits);
1591 swf_SetU8(tag, abits);
1597 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1600 while(*next && *next!=13 && *next!=10 && count<127) {
1601 readUTF8char(&next);
1604 if(next[0] == 13 || next[0] == 10) {
1609 if(next[0] == 13 && next[1] == 10)
1612 if(next[0] == 13 || next[0] == 10) {
1617 /* now set the text params- notice that a font size of
1618 1024 means that the glyphs will be displayed exactly
1619 as they would be in/with a defineshape. (Try to find
1620 *that* in the flash specs)
1622 /* set the actual text- notice that we just pass our scale
1623 parameter over, as TextSetCharRecord calculates with
1625 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1635 void swf_FontCreateLayout(SWFFONT * f)
1644 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1645 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1646 f->layout->ascent = -32767;
1647 f->layout->descent = -32767;
1649 for (t = 0; t < f->numchars; t++) {
1653 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1655 fprintf(stderr, "Shape parse error\n");
1658 bbox = swf_GetShapeBoundingBox(shape2);
1659 swf_Shape2Free(shape2);
1660 f->layout->bounds[t] = bbox;
1662 width = (bbox.xmax);
1664 /* The following is a heuristic- it may be that extractfont_DefineText
1665 has already found out some widths for individual characters (from the way
1666 they are used)- we now have to guess whether that width might be possible,
1667 which is the case if it isn't either much too big or much too small */
1668 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1669 f->glyph[t].advance = width;
1671 if (-bbox.ymin > f->layout->ascent)
1672 f->layout->ascent = bbox.ymin;
1673 if (bbox.ymax > f->layout->descent)
1674 f->layout->descent = bbox.ymax;
1678 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1680 U8 *s = (U8 *) text;
1686 U32 c = readUTF8char(&s);
1687 int g = font->ascii2glyph[c];
1688 shape = font->glyph[g].shape;
1689 if (((int) g) < 0) {
1690 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1693 shape2 = swf_ShapeToShape2(shape);
1696 if (l->type == moveTo) {
1698 to.x = l->x * size / 100.0 / 20.0 + advance;
1699 to.y = l->y * size / 100.0 / 20.0;
1700 draw->moveTo(draw, &to);
1701 } else if (l->type == lineTo) {
1703 to.x = l->x * size / 100.0 / 20.0 + advance;
1704 to.y = l->y * size / 100.0 / 20.0;
1705 draw->lineTo(draw, &to);
1706 } else if (l->type == splineTo) {
1708 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1709 mid.y = l->sy * size / 100.0 / 20.0;
1710 to.x = l->x * size / 100.0 / 20.0 + advance;
1711 to.y = l->y * size / 100.0 / 20.0;
1712 draw->splineTo(draw, &mid, &to);
1716 swf_Shape2Free(shape2);
1717 advance += font->glyph[g].advance * size / 100.0 / 20.0;