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));
314 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
319 for (t = 0; t < glyphcount; t++) {
321 if (flags1 & 4) // wide codes
322 code = swf_GetU16(tag);
324 code = swf_GetU8(tag);
325 font->glyph2ascii[t] = code;
332 font->maxascii = maxcode;
333 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
334 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
335 for (t = 0; t < glyphcount; t++) {
336 font->ascii2glyph[font->glyph2ascii[t]] = t;
339 if (flags1 & 128) { // has layout
341 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
342 font->layout->ascent = swf_GetU16(tag);
343 font->layout->descent = swf_GetU16(tag);
344 font->layout->leading = swf_GetU16(tag);
345 for (t = 0; t < glyphcount; t++) {
346 S16 advance = swf_GetS16(tag);
347 font->glyph[t].advance = advance;
349 font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
350 for (t = 0; t < glyphcount; t++) {
351 swf_ResetReadBits(tag);
352 swf_GetRect(tag, &font->layout->bounds[t]);
355 kerningcount = swf_GetU16(tag);
356 font->layout->kerningcount = kerningcount;
358 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
360 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
361 for (t = 0; t < kerningcount; t++) {
362 if (flags1 & 4) { // wide codes
363 font->layout->kerning[t].char1 = swf_GetU16(tag);
364 font->layout->kerning[t].char2 = swf_GetU16(tag);
366 font->layout->kerning[t].char1 = swf_GetU8(tag);
367 font->layout->kerning[t].char2 = swf_GetU8(tag);
369 font->layout->kerning[t].adjustment = swf_GetS16(tag);
377 #define FEDTJ_PRINT 0x01
378 #define FEDTJ_MODIFY 0x02
379 #define FEDTJ_CALLBACK 0x04
382 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
383 void (*callback) (void *self,
384 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
395 memset(&color, 0, sizeof(color));
401 swf_GetMatrix(t, &m);
402 gbits = swf_GetU8(t);
403 abits = swf_GetU8(t);
407 flags = swf_GetU8(t);
411 if (flags & TF_TEXTCONTROL) {
412 if (flags & TF_HASFONT)
414 if (flags & TF_HASCOLOR) {
415 color.r = swf_GetU8(t); // rgb
416 color.g = swf_GetU8(t);
417 color.b = swf_GetU8(t);
418 if (swf_GetTagID(t) == ST_DEFINETEXT2)
419 color.a = swf_GetU8(t);
423 if (flags & TF_HASXOFFSET)
425 if (flags & TF_HASYOFFSET)
427 if (flags & TF_HASFONT)
428 fontsize = swf_GetU16(t);
440 for (i = 0; i < num; i++) {
444 glyph = swf_GetBits(t, gbits);
445 adv = swf_GetBits(t, abits);
449 if (jobs & FEDTJ_PRINT) {
450 int code = f->glyph2ascii[glyph];
453 if (jobs & FEDTJ_MODIFY)
454 f->glyph[glyph].advance = adv * 20; //?
459 if ((id == fid) && (jobs & FEDTJ_PRINT))
461 if (jobs & FEDTJ_CALLBACK)
462 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
470 int swf_ParseDefineText(TAG * tag,
471 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
473 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
476 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
478 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
481 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
486 if ((!swf) || (!font))
489 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
495 switch (swf_GetTagID(t)) {
497 nid = swf_FontExtract_DefineFont(id, f, t);
501 nid = swf_FontExtract_DefineFont2(id, f, t);
504 case ST_DEFINEFONTINFO:
505 case ST_DEFINEFONTINFO2:
506 nid = swf_FontExtract_DefineFontInfo(id, f, t);
511 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
515 nid = swf_FontExtract_GlyphNames(id, f, t);
530 int swf_FontSetID(SWFFONT * f, U16 id)
538 void swf_LayoutFree(SWFLAYOUT * l)
542 rfx_free(l->kerning);
552 static void font_freeglyphnames(SWFFONT*f)
557 for (t = 0; t < f->numchars; t++)
559 if (f->glyphnames[t])
561 rfx_free(f->glyphnames[t]);
562 f->glyphnames[t] = 0;
565 rfx_free(f->glyphnames);
569 static void font_freeusage(SWFFONT*f)
573 rfx_free(f->use->chars);f->use->chars = 0;
575 rfx_free(f->use); f->use = 0;
578 static void font_freelayout(SWFFONT*f)
581 swf_LayoutFree(f->layout);
585 static void font_freename(SWFFONT*f)
593 int swf_FontReduce_old(SWFFONT * f)
597 if ((!f) || (!f->use) || f->use->is_reduced)
602 for (i = 0; i < f->numchars; i++) {
603 if (f->glyph[i].shape && f->use->chars[i]) {
604 f->glyph2ascii[j] = f->glyph2ascii[i];
605 f->glyph[j] = f->glyph[i];
606 f->use->chars[i] = j;
609 f->glyph2ascii[i] = 0;
610 if(f->glyph[i].shape) {
611 swf_ShapeFree(f->glyph[i].shape);
612 f->glyph[i].shape = 0;
613 f->glyph[i].advance = 0;
615 f->use->chars[i] = -1;
619 for (i = 0; i < f->maxascii; i++) {
620 if(f->use->chars[f->ascii2glyph[i]]<0) {
621 f->ascii2glyph[i] = -1;
623 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
627 f->maxascii = max_unicode;
628 f->use->is_reduced = 1;
631 font_freeglyphnames(f);
636 int swf_FontReduce_swfc(SWFFONT * f)
640 if ((!f) || (!f->use) || f->use->is_reduced)
643 font_freeglyphnames(f);
646 for (i = 0; i < f->numchars; i++) {
647 if (f->glyph[i].shape && f->use->chars[i]) {
648 f->glyph2ascii[j] = f->glyph2ascii[i];
650 f->layout->bounds[j] = f->layout->bounds[i];
651 f->glyph[j] = f->glyph[i];
652 f->use->chars[i] = j;
655 f->glyph2ascii[i] = 0;
656 if(f->glyph[i].shape) {
657 swf_ShapeFree(f->glyph[i].shape);
658 f->glyph[i].shape = 0;
659 f->glyph[i].advance = 0;
661 f->use->chars[i] = -1;
664 f->use->used_glyphs = j;
665 for (i = 0; i < f->maxascii; i++) {
666 if(f->ascii2glyph[i] > -1) {
667 if (f->use->chars[f->ascii2glyph[i]]<0) {
668 f->use->chars[f->ascii2glyph[i]] = 0;
669 f->ascii2glyph[i] = -1;
671 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
672 f->use->chars[f->ascii2glyph[i]] = 1;
677 f->maxascii = max_unicode;
678 f->use->is_reduced = 1;
684 int swf_FontReduce(SWFFONT * f)
689 if ((!f) || (!f->use) || f->use->is_reduced)
693 font_freeglyphnames(f);
695 f->use->used_glyphs= 0;
696 for (i = 0; i < f->numchars; i++) {
697 if(!f->use->chars[i]) {
699 f->glyph2ascii[i] = 0;
701 if(f->glyph[i].shape) {
702 swf_ShapeFree(f->glyph[i].shape);
703 f->glyph[i].shape = 0;
704 f->glyph[i].advance = 0;
706 // f->use->used_glyphs++;
708 f->use->used_glyphs++;
712 for (i = 0; i < f->maxascii; i++) {
713 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
715 f->ascii2glyph[i] = -1;
721 f->maxascii = max_unicode;
722 f->numchars = max_glyph;
727 void swf_FontSort(SWFFONT * font)
735 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
737 for (i = 0; i < font->numchars; i++) {
740 for (i = 0; i < font->numchars; i++)
741 for (j = 0; j < i; j++) {
742 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
751 n1 = font->glyph2ascii[i];
752 n2 = font->glyph2ascii[j];
753 font->glyph2ascii[j] = n1;
754 font->glyph2ascii[i] = n2;
759 if (font->glyphnames) {
760 c1 = font->glyphnames[i];
761 c2 = font->glyphnames[j];
762 font->glyphnames[j] = c1;
763 font->glyphnames[i] = c2;
766 r1 = font->layout->bounds[i];
767 r2 = font->layout->bounds[j];
768 font->layout->bounds[j] = r1;
769 font->layout->bounds[i] = r2;
773 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
774 for (i = 0; i < font->numchars; i++) {
775 newpos[newplace[i]] = i;
777 for (i = 0; i < font->maxascii; i++) {
778 if (font->ascii2glyph[i] >= 0)
779 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
786 void swf_FontPrepareForEditText(SWFFONT * font)
789 swf_FontCreateLayout(font);
793 int swf_FontInitUsage(SWFFONT * f)
798 fprintf(stderr, "Usage initialized twice");
801 f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
802 f->use->is_reduced = 0;
803 f->use->used_glyphs = 0;
804 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
805 f->use->glyphs_specified = 0;
809 void swf_FontClearUsage(SWFFONT * f)
813 rfx_free(f->use->chars); f->use->chars = 0;
814 rfx_free(f->use); f->use = 0;
817 int swf_FontUse(SWFFONT * f, U8 * s)
822 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
823 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
829 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
836 ascii = readUTF8char(&s);
837 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
838 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
843 int swf_FontUseAll(SWFFONT* f)
848 swf_FontInitUsage(f);
849 for (i = 0; i < f->numchars; i++)
850 f->use->chars[i] = 1;
851 f->use->used_glyphs = f->numchars;
855 int swf_FontUseGlyph(SWFFONT * f, int glyph)
858 swf_FontInitUsage(f);
859 if(glyph < 0 || glyph >= f->numchars)
861 if(!f->use->chars[glyph])
862 f->use->used_glyphs++;
863 f->use->chars[glyph] = 1;
867 int swf_FontSetDefine(TAG * t, SWFFONT * f)
869 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
874 swf_ResetWriteBits(t);
875 swf_SetU16(t, f->id);
879 for (i = 0; i < f->numchars; i++)
880 if (f->glyph[i].shape) {
882 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
885 for (i = 0; i < j; i++)
886 swf_SetU16(t, ofs[i] + j * 2);
888 fprintf(stderr, "rfxswf: warning: Font is empty\n");
892 for (i = 0; i < f->numchars; i++)
893 if (f->glyph[i].shape)
894 swf_SetSimpleShape(t, f->glyph[i].shape);
896 swf_ResetWriteBits(t);
901 static inline int fontSize(SWFFONT * font)
905 for (t = 0; t < font->numchars; t++) {
907 if(font->glyph[t].shape)
908 l = (font->glyph[t].shape->bitlen + 7) / 8;
913 return size + (font->numchars + 1) * 2;
916 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
921 swf_SetU16(tag, f->id);
923 if (f->layout) flags |= 128; // haslayout
924 if (f->numchars > 256)
925 flags |= 4; // widecodes
926 if (f->style & FONT_STYLE_BOLD)
928 if (f->style & FONT_STYLE_ITALIC)
929 flags |= 2; // italic
930 if (f->maxascii >= 256)
931 flags |= 4; //wide codecs
932 if (fontSize(f) > 65535)
933 flags |= 8; //wide offsets
934 flags |= 8 | 4; //FIXME: the above check doesn't work
936 if (f->encoding & FONT_ENCODING_ANSI)
938 if (f->encoding & FONT_ENCODING_UNICODE)
939 flags |= 32; // unicode
940 if (f->encoding & FONT_ENCODING_SHIFTJIS)
941 flags |= 64; // shiftjis
943 swf_SetU8(tag, flags);
944 swf_SetU8(tag, 0); //reserved flags
947 swf_SetU8(tag, strlen((const char*)f->name)+1);
948 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
950 /* font name (="") */
954 /* number of glyphs */
955 swf_SetU16(tag, f->numchars);
956 /* font offset table */
958 for (t = 0; t <= f->numchars; t++) {
960 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
962 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
965 for (t = 0; t <= f->numchars; t++) {
967 tag->data[pos + t * 4] = (tag->len - pos);
968 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
969 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
970 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
972 if (tag->len - pos > 65535) {
973 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
976 tag->data[pos + t * 2] = (tag->len - pos);
977 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
979 if (t < f->numchars) {
980 if(f->glyph[t].shape) {
981 swf_SetSimpleShape(tag, f->glyph[t].shape);
983 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
989 /* font code table */
990 for (t = 0; t < f->numchars; t++) {
991 if (flags & 4) { /* wide codes */
992 if(f->glyph2ascii[t]) {
993 swf_SetU16(tag, f->glyph2ascii[t]);
998 if(f->glyph2ascii[t]) {
999 swf_SetU8(tag, f->glyph2ascii[t]);
1007 swf_SetU16(tag, f->layout->ascent);
1008 swf_SetU16(tag, f->layout->descent);
1009 swf_SetU16(tag, f->layout->leading);
1010 for (t = 0; t < f->numchars; t++)
1011 swf_SetU16(tag, f->glyph[t].advance);
1012 for (t = 0; t < f->numchars; t++) {
1013 swf_ResetWriteBits(tag);
1014 swf_SetRect(tag, &f->layout->bounds[t]);
1016 swf_SetU16(tag, f->layout->kerningcount);
1017 for (t = 0; t < f->layout->kerningcount; t++) {
1018 if (flags & 4) { /* wide codes */
1019 swf_SetU16(tag, f->layout->kerning[t].char1);
1020 swf_SetU16(tag, f->layout->kerning[t].char2);
1022 swf_SetU8(tag, f->layout->kerning[t].char1);
1023 swf_SetU8(tag, f->layout->kerning[t].char2);
1025 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1031 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1033 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1034 f->layout->ascent = ascent;
1035 f->layout->descent = descent;
1036 f->layout->leading = leading;
1037 f->layout->kerningcount = 0;
1038 f->layout->kerning = 0;
1039 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1042 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1049 swf_ResetWriteBits(t);
1050 swf_SetU16(t, f->id);
1051 l = f->name ? strlen((const char *)f->name) : 0;
1056 swf_SetBlock(t, f->name, l);
1057 if (f->numchars >= 256)
1060 if (f->style & FONT_STYLE_BOLD)
1062 if (f->style & FONT_STYLE_ITALIC)
1064 if (f->style & FONT_ENCODING_ANSI)
1066 if (f->style & FONT_ENCODING_SHIFTJIS)
1068 if (f->style & FONT_ENCODING_UNICODE)
1071 swf_SetU8(t, (flags & 0xfe) | wide);
1073 for (i = 0; i < f->numchars; i++) {
1074 if (f->glyph[i].shape) {
1075 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1076 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1083 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1085 int id = swf_GetTagID(t);
1086 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1087 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1093 void swf_FontFree(SWFFONT * f)
1101 for (i = 0; i < f->numchars; i++)
1102 if (f->glyph[i].shape)
1104 swf_ShapeFree(f->glyph[i].shape);
1105 f->glyph[i].shape = NULL;
1112 rfx_free(f->ascii2glyph);
1113 f->ascii2glyph = NULL;
1117 rfx_free(f->glyph2ascii);
1118 f->glyph2ascii = NULL;
1122 font_freeglyphnames(f);
1128 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1134 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1135 | (y ? TF_HASYOFFSET : 0);
1137 swf_SetU8(t, flags);
1139 swf_SetU16(t, font->id);
1141 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1142 swf_SetRGBA(t, color);
1144 swf_SetRGB(t, color);
1147 if(x != SET_TO_ZERO) {
1148 if(x>32767 || x<-32768)
1149 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1156 if(y != SET_TO_ZERO) {
1157 if(y>32767 || y<-32768)
1158 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1165 swf_SetU16(t, size);
1170 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1174 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1178 if (!strcmp(encoding, "UTF8"))
1180 else if (!strcmp(encoding, "iso-8859-1"))
1183 fprintf(stderr, "Unknown encoding: %s", encoding);
1191 c = readUTF8char(&s);
1193 if (c < font->maxascii)
1194 glyph = font->ascii2glyph[c];
1196 g = swf_CountUBits(glyph, g);
1197 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1208 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1213 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1216 if (!strcmp(encoding, "UTF8"))
1218 else if (!strcmp(encoding, "iso-8859-1"))
1221 fprintf(stderr, "Unknown encoding: %s", encoding);
1224 swf_SetU8(t, l); //placeholder
1232 c = readUTF8char(&s);
1234 if (c < font->maxascii)
1235 g = font->ascii2glyph[c];
1237 swf_SetBits(t, g, gbits);
1238 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1240 /* We split into 127 characters per text field.
1241 We could do 255, by the (formerly wrong) flash specification,
1242 but some SWF parsing code out there still assumes that char blocks
1243 are at max 127 characters, and it would save only a few bits.
1250 PUT8(&t->data[pos], l);
1252 swf_ResetWriteBits(t);
1256 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1258 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1261 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1263 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1266 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1268 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1271 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1273 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1276 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1283 if (*s < font->maxascii)
1284 g = font->ascii2glyph[*s];
1286 res += font->glyph[g].advance / 20;
1290 res = (res * scale) / 100;
1295 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1302 int c = readUTF8char(&s);
1303 if(c==13 || c==10) {
1308 ypos+=font->layout->leading;
1311 if (c < font->maxascii) {
1312 int g = font->ascii2glyph[c];
1314 SRECT rn = font->layout->bounds[g];
1315 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1316 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1317 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1318 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1319 swf_ExpandRect2(&r, &rn);
1320 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1328 SWFFONT *swf_ReadFont(char *filename)
1334 f = open(filename, O_RDONLY|O_BINARY);
1336 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1337 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1343 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1350 void swf_WriteFont(SWFFONT * font, char *filename)
1357 int useDefineFont2 = 0;
1358 int storeGlyphNames = 1;
1361 useDefineFont2 = 1; /* the only thing new in definefont2
1362 is layout information. */
1364 font->id = WRITEFONTID; //"FN"
1366 memset(&swf, 0x00, sizeof(SWF));
1368 swf.fileVersion = 4;
1369 swf.frameRate = 0x4000;
1371 /* if we use DefineFont1 to store the characters,
1372 we have to build a textfield to store the
1373 advance values. While at it, we can also
1374 make the whole .swf viewable */
1376 /* we now always create viewable swfs, even if we
1377 did use definefont2 -mk */
1378 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1383 swf_SetRGB(t, &rgb);
1384 if (!useDefineFont2) {
1385 t = swf_InsertTag(t, ST_DEFINEFONT);
1386 swf_FontSetDefine(t, font);
1387 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1388 swf_FontSetInfo(t, font);
1390 t = swf_InsertTag(t, ST_DEFINEFONT2);
1391 swf_FontSetDefine2(t, font);
1394 if (storeGlyphNames && font->glyphnames) {
1396 t = swf_InsertTag(t, ST_GLYPHNAMES);
1397 swf_SetU16(t, WRITEFONTID);
1398 swf_SetU16(t, font->numchars);
1399 for (c = 0; c < font->numchars; c++) {
1400 if (font->glyphnames[c])
1401 swf_SetString(t, (U8*)font->glyphnames[c]);
1403 swf_SetString(t, (U8*)"");
1407 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1409 int textscale = 400;
1416 int range = font->maxascii;
1419 if (useDefineFont2 && range > 256) {
1423 for (s = 0; s < range; s++) {
1424 int g = font->ascii2glyph[s];
1426 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1427 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1431 if ((s & 15) == 0) {
1438 ymax = ypos * textscale * 2;
1440 swf.movieSize.xmax = xmax * 20;
1441 swf.movieSize.ymax = ymax;
1443 t = swf_InsertTag(t, ST_DEFINETEXT);
1445 swf_SetU16(t, font->id + 1); // ID
1449 r.xmax = swf.movieSize.xmax;
1450 r.ymax = swf.movieSize.ymax;
1454 swf_SetMatrix(t, NULL);
1456 abits = swf_CountBits(xmax * 16, 0);
1459 swf_SetU8(t, gbits);
1460 swf_SetU8(t, abits);
1466 for (y = 0; y < ((range + 15) / 16); y++) {
1467 int c = 0, lastx = -1;
1468 for (x = 0; x < 16; x++) {
1469 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1470 if (g >= 0 && font->glyph[g].shape) {
1477 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1478 for (x = 0; x < 16; x++) {
1479 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1480 if (g >= 0 && font->glyph[g].shape) {
1481 if (lastx != x * xmax) {
1482 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1485 swf_SetBits(t, g, gbits);
1486 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1487 lastx = x * xmax + (font->glyph[g].advance / 20);
1488 swf_ResetWriteBits(t);
1497 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1499 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1501 t = swf_InsertTag(t, ST_SHOWFRAME);
1505 t = swf_InsertTag(t, ST_END);
1507 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1509 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1516 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1518 swf_SetRect(tag, &r);
1519 swf_ResetWriteBits(tag);
1521 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1523 flags |= ET_HASTEXT;
1525 flags |= ET_HASTEXTCOLOR;
1527 flags |= ET_HASMAXLENGTH;
1529 flags |= ET_HASFONT;
1531 flags |= ET_HASLAYOUT;
1533 swf_SetBits(tag, flags, 16);
1535 if (flags & ET_HASFONT) {
1536 swf_SetU16(tag, font); //font
1537 swf_SetU16(tag, height); //fontheight
1539 if (flags & ET_HASTEXTCOLOR) {
1540 swf_SetRGBA(tag, color);
1542 if (flags & ET_HASMAXLENGTH) {
1543 swf_SetU16(tag, maxlength); //maxlength
1545 if (flags & ET_HASLAYOUT) {
1546 swf_SetU8(tag, layout->align); //align
1547 swf_SetU16(tag, layout->leftmargin); //left margin
1548 swf_SetU16(tag, layout->rightmargin); //right margin
1549 swf_SetU16(tag, layout->indent); //indent
1550 swf_SetU16(tag, layout->leading); //leading
1552 swf_SetString(tag, (U8*)variable);
1553 if (flags & ET_HASTEXT)
1554 swf_SetString(tag, (U8*)text);
1557 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1561 U8 *utext = (U8 *) strdup(text);
1567 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1568 ystep = font->layout->leading;
1570 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1571 /* Hm, without layout information, we can't compute a bounding
1572 box. We could call swf_FontCreateLayout to create a layout,
1573 but the caller probably doesn't want us to mess up his font
1576 r.xmin = r.ymin = 0;
1577 r.xmax = r.ymax = 1024 * 20;
1581 swf_SetRect(tag, &r);
1583 /* The text matrix is pretty boring, as it doesn't apply to
1584 individual characters, but rather whole text objects (or
1585 at least whole char records- haven't tested).
1586 So it can't do anything which we can't already do with
1587 the placeobject tag we use for placing the text on the scene.
1589 swf_SetMatrix(tag, 0);
1591 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1592 swf_SetU8(tag, gbits);
1593 swf_SetU8(tag, abits);
1599 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1602 while(*next && *next!=13 && *next!=10 && count<127) {
1603 readUTF8char(&next);
1606 if(next[0] == 13 || next[0] == 10) {
1611 if(next[0] == 13 && next[1] == 10)
1614 if(next[0] == 13 || next[0] == 10) {
1619 /* now set the text params- notice that a font size of
1620 1024 means that the glyphs will be displayed exactly
1621 as they would be in/with a defineshape. (Try to find
1622 *that* in the flash specs)
1624 /* set the actual text- notice that we just pass our scale
1625 parameter over, as TextSetCharRecord calculates with
1627 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1637 void swf_FontCreateLayout(SWFFONT * f)
1646 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1647 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1648 f->layout->ascent = -32767;
1649 f->layout->descent = -32767;
1651 for (t = 0; t < f->numchars; t++) {
1655 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1657 fprintf(stderr, "Shape parse error\n");
1660 bbox = swf_GetShapeBoundingBox(shape2);
1661 swf_Shape2Free(shape2);
1662 f->layout->bounds[t] = bbox;
1664 width = (bbox.xmax);
1666 /* The following is a heuristic- it may be that extractfont_DefineText
1667 has already found out some widths for individual characters (from the way
1668 they are used)- we now have to guess whether that width might be possible,
1669 which is the case if it isn't either much too big or much too small */
1670 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1671 f->glyph[t].advance = width;
1673 if (-bbox.ymin > f->layout->ascent)
1674 f->layout->ascent = bbox.ymin;
1675 if (bbox.ymax > f->layout->descent)
1676 f->layout->descent = bbox.ymax;
1680 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1682 U8 *s = (U8 *) text;
1688 U32 c = readUTF8char(&s);
1689 int g = font->ascii2glyph[c];
1690 shape = font->glyph[g].shape;
1691 if (((int) g) < 0) {
1692 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1695 shape2 = swf_ShapeToShape2(shape);
1698 if (l->type == moveTo) {
1700 to.x = l->x * size / 100.0 / 20.0 + advance;
1701 to.y = l->y * size / 100.0 / 20.0;
1702 draw->moveTo(draw, &to);
1703 } else if (l->type == lineTo) {
1705 to.x = l->x * size / 100.0 / 20.0 + advance;
1706 to.y = l->y * size / 100.0 / 20.0;
1707 draw->lineTo(draw, &to);
1708 } else if (l->type == splineTo) {
1710 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1711 mid.y = l->sy * size / 100.0 / 20.0;
1712 to.x = l->x * size / 100.0 / 20.0 + advance;
1713 to.y = l->y * size / 100.0 / 20.0;
1714 draw->splineTo(draw, &mid, &to);
1718 swf_Shape2Free(shape2);
1719 advance += font->glyph[g].advance * size / 100.0 / 20.0;