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));
946 swf_SetBlock(tag, f->name, strlen((const char*)f->name));
948 /* font name (="") */
951 /* number of glyphs */
952 swf_SetU16(tag, f->numchars);
953 /* font offset table */
955 for (t = 0; t <= f->numchars; t++) {
957 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
959 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
962 for (t = 0; t <= f->numchars; t++) {
964 tag->data[pos + t * 4] = (tag->len - pos);
965 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
966 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
967 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
969 if (tag->len - pos > 65535) {
970 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
973 tag->data[pos + t * 2] = (tag->len - pos);
974 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
976 if (t < f->numchars) {
977 if(f->glyph[t].shape) {
978 swf_SetSimpleShape(tag, f->glyph[t].shape);
980 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
986 /* font code table */
987 for (t = 0; t < f->numchars; t++) {
988 if (flags & 4) { /* wide codes */
989 if(f->glyph2ascii[t]) {
990 swf_SetU16(tag, f->glyph2ascii[t]);
995 if(f->glyph2ascii[t]) {
996 swf_SetU8(tag, f->glyph2ascii[t]);
1004 swf_SetU16(tag, f->layout->ascent);
1005 swf_SetU16(tag, f->layout->descent);
1006 swf_SetU16(tag, f->layout->leading);
1007 for (t = 0; t < f->numchars; t++)
1008 swf_SetU16(tag, f->glyph[t].advance);
1009 for (t = 0; t < f->numchars; t++) {
1010 swf_ResetWriteBits(tag);
1011 swf_SetRect(tag, &f->layout->bounds[t]);
1013 swf_SetU16(tag, f->layout->kerningcount);
1014 for (t = 0; t < f->layout->kerningcount; t++) {
1015 if (flags & 4) { /* wide codes */
1016 swf_SetU16(tag, f->layout->kerning[t].char1);
1017 swf_SetU16(tag, f->layout->kerning[t].char2);
1019 swf_SetU8(tag, f->layout->kerning[t].char1);
1020 swf_SetU8(tag, f->layout->kerning[t].char2);
1022 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1028 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1030 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1031 f->layout->ascent = ascent;
1032 f->layout->descent = descent;
1033 f->layout->leading = leading;
1034 f->layout->kerningcount = 0;
1035 f->layout->kerning = 0;
1036 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1039 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1046 swf_ResetWriteBits(t);
1047 swf_SetU16(t, f->id);
1048 l = f->name ? strlen((const char *)f->name) : 0;
1053 swf_SetBlock(t, f->name, l);
1054 if (f->numchars >= 256)
1057 if (f->style & FONT_STYLE_BOLD)
1059 if (f->style & FONT_STYLE_ITALIC)
1061 if (f->style & FONT_ENCODING_ANSI)
1063 if (f->style & FONT_ENCODING_SHIFTJIS)
1065 if (f->style & FONT_ENCODING_UNICODE)
1068 swf_SetU8(t, (flags & 0xfe) | wide);
1070 for (i = 0; i < f->numchars; i++) {
1071 if (f->glyph[i].shape) {
1072 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1073 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1080 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1082 int id = swf_GetTagID(t);
1083 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1084 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1090 void swf_FontFree(SWFFONT * f)
1098 for (i = 0; i < f->numchars; i++)
1099 if (f->glyph[i].shape)
1101 swf_ShapeFree(f->glyph[i].shape);
1102 f->glyph[i].shape = NULL;
1109 rfx_free(f->ascii2glyph);
1110 f->ascii2glyph = NULL;
1114 rfx_free(f->glyph2ascii);
1115 f->glyph2ascii = NULL;
1119 font_freeglyphnames(f);
1125 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1131 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1132 | (y ? TF_HASYOFFSET : 0);
1134 swf_SetU8(t, flags);
1136 swf_SetU16(t, font->id);
1138 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1139 swf_SetRGBA(t, color);
1141 swf_SetRGB(t, color);
1144 if(x != SET_TO_ZERO) {
1145 if(x>32767 || x<-32768)
1146 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1153 if(y != SET_TO_ZERO) {
1154 if(y>32767 || y<-32768)
1155 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1162 swf_SetU16(t, size);
1167 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1171 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1175 if (!strcmp(encoding, "UTF8"))
1177 else if (!strcmp(encoding, "iso-8859-1"))
1180 fprintf(stderr, "Unknown encoding: %s", encoding);
1188 c = readUTF8char(&s);
1190 if (c < font->maxascii)
1191 glyph = font->ascii2glyph[c];
1193 g = swf_CountUBits(glyph, g);
1194 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1205 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1210 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1213 if (!strcmp(encoding, "UTF8"))
1215 else if (!strcmp(encoding, "iso-8859-1"))
1218 fprintf(stderr, "Unknown encoding: %s", encoding);
1221 swf_SetU8(t, l); //placeholder
1229 c = readUTF8char(&s);
1231 if (c < font->maxascii)
1232 g = font->ascii2glyph[c];
1234 swf_SetBits(t, g, gbits);
1235 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1237 /* We split into 127 characters per text field.
1238 We could do 255, by the (formerly wrong) flash specification,
1239 but some SWF parsing code out there still assumes that char blocks
1240 are at max 127 characters, and it would save only a few bits.
1247 PUT8(&t->data[pos], l);
1249 swf_ResetWriteBits(t);
1253 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1255 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1258 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1260 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1263 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1265 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1268 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1270 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1273 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1280 if (*s < font->maxascii)
1281 g = font->ascii2glyph[*s];
1283 res += font->glyph[g].advance / 20;
1287 res = (res * scale) / 100;
1292 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1299 int c = readUTF8char(&s);
1300 if(c==13 || c==10) {
1305 ypos+=font->layout->leading;
1308 if (c < font->maxascii) {
1309 int g = font->ascii2glyph[c];
1311 SRECT rn = font->layout->bounds[g];
1312 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1313 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1314 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1315 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1316 swf_ExpandRect2(&r, &rn);
1317 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1325 SWFFONT *swf_ReadFont(char *filename)
1331 f = open(filename, O_RDONLY|O_BINARY);
1333 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1334 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1340 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1347 void swf_WriteFont(SWFFONT * font, char *filename)
1354 int useDefineFont2 = 0;
1355 int storeGlyphNames = 1;
1358 useDefineFont2 = 1; /* the only thing new in definefont2
1359 is layout information. */
1361 font->id = WRITEFONTID; //"FN"
1363 memset(&swf, 0x00, sizeof(SWF));
1365 swf.fileVersion = 4;
1366 swf.frameRate = 0x4000;
1368 /* if we use DefineFont1 to store the characters,
1369 we have to build a textfield to store the
1370 advance values. While at it, we can also
1371 make the whole .swf viewable */
1373 /* we now always create viewable swfs, even if we
1374 did use definefont2 -mk */
1375 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1380 swf_SetRGB(t, &rgb);
1381 if (!useDefineFont2) {
1382 t = swf_InsertTag(t, ST_DEFINEFONT);
1383 swf_FontSetDefine(t, font);
1384 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1385 swf_FontSetInfo(t, font);
1387 t = swf_InsertTag(t, ST_DEFINEFONT2);
1388 swf_FontSetDefine2(t, font);
1391 if (storeGlyphNames && font->glyphnames) {
1393 t = swf_InsertTag(t, ST_GLYPHNAMES);
1394 swf_SetU16(t, WRITEFONTID);
1395 swf_SetU16(t, font->numchars);
1396 for (c = 0; c < font->numchars; c++) {
1397 if (font->glyphnames[c])
1398 swf_SetString(t, (U8*)font->glyphnames[c]);
1400 swf_SetString(t, (U8*)"");
1404 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1406 int textscale = 400;
1413 int range = font->maxascii;
1416 if (useDefineFont2 && range > 256) {
1420 for (s = 0; s < range; s++) {
1421 int g = font->ascii2glyph[s];
1423 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1424 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1428 if ((s & 15) == 0) {
1435 ymax = ypos * textscale * 2;
1437 swf.movieSize.xmax = xmax * 20;
1438 swf.movieSize.ymax = ymax;
1440 t = swf_InsertTag(t, ST_DEFINETEXT);
1442 swf_SetU16(t, font->id + 1); // ID
1446 r.xmax = swf.movieSize.xmax;
1447 r.ymax = swf.movieSize.ymax;
1451 swf_SetMatrix(t, NULL);
1453 abits = swf_CountBits(xmax * 16, 0);
1456 swf_SetU8(t, gbits);
1457 swf_SetU8(t, abits);
1463 for (y = 0; y < ((range + 15) / 16); y++) {
1464 int c = 0, lastx = -1;
1465 for (x = 0; x < 16; x++) {
1466 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1467 if (g >= 0 && font->glyph[g].shape) {
1474 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1475 for (x = 0; x < 16; x++) {
1476 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1477 if (g >= 0 && font->glyph[g].shape) {
1478 if (lastx != x * xmax) {
1479 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1482 swf_SetBits(t, g, gbits);
1483 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1484 lastx = x * xmax + (font->glyph[g].advance / 20);
1485 swf_ResetWriteBits(t);
1494 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1496 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1498 t = swf_InsertTag(t, ST_SHOWFRAME);
1502 t = swf_InsertTag(t, ST_END);
1504 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1506 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1513 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1515 swf_SetRect(tag, &r);
1516 swf_ResetWriteBits(tag);
1518 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1520 flags |= ET_HASTEXT;
1522 flags |= ET_HASTEXTCOLOR;
1524 flags |= ET_HASMAXLENGTH;
1526 flags |= ET_HASFONT;
1528 flags |= ET_HASLAYOUT;
1530 swf_SetBits(tag, flags, 16);
1532 if (flags & ET_HASFONT) {
1533 swf_SetU16(tag, font); //font
1534 swf_SetU16(tag, height); //fontheight
1536 if (flags & ET_HASTEXTCOLOR) {
1537 swf_SetRGBA(tag, color);
1539 if (flags & ET_HASMAXLENGTH) {
1540 swf_SetU16(tag, maxlength); //maxlength
1542 if (flags & ET_HASLAYOUT) {
1543 swf_SetU8(tag, layout->align); //align
1544 swf_SetU16(tag, layout->leftmargin); //left margin
1545 swf_SetU16(tag, layout->rightmargin); //right margin
1546 swf_SetU16(tag, layout->indent); //indent
1547 swf_SetU16(tag, layout->leading); //leading
1549 swf_SetString(tag, (U8*)variable);
1550 if (flags & ET_HASTEXT)
1551 swf_SetString(tag, (U8*)text);
1554 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1558 U8 *utext = (U8 *) strdup(text);
1564 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1565 ystep = font->layout->leading;
1567 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1568 /* Hm, without layout information, we can't compute a bounding
1569 box. We could call swf_FontCreateLayout to create a layout,
1570 but the caller probably doesn't want us to mess up his font
1573 r.xmin = r.ymin = 0;
1574 r.xmax = r.ymax = 1024 * 20;
1578 swf_SetRect(tag, &r);
1580 /* The text matrix is pretty boring, as it doesn't apply to
1581 individual characters, but rather whole text objects (or
1582 at least whole char records- haven't tested).
1583 So it can't do anything which we can't already do with
1584 the placeobject tag we use for placing the text on the scene.
1586 swf_SetMatrix(tag, 0);
1588 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1589 swf_SetU8(tag, gbits);
1590 swf_SetU8(tag, abits);
1596 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1599 while(*next && *next!=13 && *next!=10 && count<127) {
1600 readUTF8char(&next);
1603 if(next[0] == 13 || next[0] == 10) {
1608 if(next[0] == 13 && next[1] == 10)
1611 if(next[0] == 13 || next[0] == 10) {
1616 /* now set the text params- notice that a font size of
1617 1024 means that the glyphs will be displayed exactly
1618 as they would be in/with a defineshape. (Try to find
1619 *that* in the flash specs)
1621 /* set the actual text- notice that we just pass our scale
1622 parameter over, as TextSetCharRecord calculates with
1624 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1634 void swf_FontCreateLayout(SWFFONT * f)
1643 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1644 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1645 f->layout->ascent = -32767;
1646 f->layout->descent = -32767;
1648 for (t = 0; t < f->numchars; t++) {
1652 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1654 fprintf(stderr, "Shape parse error\n");
1657 bbox = swf_GetShapeBoundingBox(shape2);
1658 swf_Shape2Free(shape2);
1659 f->layout->bounds[t] = bbox;
1661 width = (bbox.xmax);
1663 /* The following is a heuristic- it may be that extractfont_DefineText
1664 has already found out some widths for individual characters (from the way
1665 they are used)- we now have to guess whether that width might be possible,
1666 which is the case if it isn't either much too big or much too small */
1667 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1668 f->glyph[t].advance = width;
1670 if (-bbox.ymin > f->layout->ascent)
1671 f->layout->ascent = bbox.ymin;
1672 if (bbox.ymax > f->layout->descent)
1673 f->layout->descent = bbox.ymax;
1677 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1679 U8 *s = (U8 *) text;
1685 U32 c = readUTF8char(&s);
1686 int g = font->ascii2glyph[c];
1687 shape = font->glyph[g].shape;
1688 if (((int) g) < 0) {
1689 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1692 shape2 = swf_ShapeToShape2(shape);
1695 if (l->type == moveTo) {
1697 to.x = l->x * size / 100.0 / 20.0 + advance;
1698 to.y = l->y * size / 100.0 / 20.0;
1699 draw->moveTo(draw, &to);
1700 } else if (l->type == lineTo) {
1702 to.x = l->x * size / 100.0 / 20.0 + advance;
1703 to.y = l->y * size / 100.0 / 20.0;
1704 draw->lineTo(draw, &to);
1705 } else if (l->type == splineTo) {
1707 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1708 mid.y = l->sy * size / 100.0 / 20.0;
1709 to.x = l->x * size / 100.0 / 20.0 + advance;
1710 to.y = l->y * size / 100.0 / 20.0;
1711 draw->splineTo(draw, &mid, &to);
1715 swf_Shape2Free(shape2);
1716 advance += font->glyph[g].advance * size / 100.0 / 20.0;