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 static U32 readUTF8char(U8 ** text)
28 if (!(*(*text) & 0x80))
31 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
32 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
33 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
37 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
38 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
39 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
43 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
44 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
46 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
50 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
51 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
54 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
58 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
59 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
61 && (*text)[4] && (*text)[5]) {
62 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
63 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
70 #define TF_TEXTCONTROL 0x80
71 #define TF_HASFONT 0x08
72 #define TF_HASCOLOR 0x04
73 #define TF_HASYOFFSET 0x02
74 #define TF_HASXOFFSET 0x01
76 #define FF_WIDECODES 0x01
78 #define FF_ITALIC 0x04
80 #define FF_SHIFTJIS 0x10
81 #define FF_UNICODE 0x20
84 #define FF2_ITALIC 0x02
85 #define FF2_WIDECODES 0x04
86 #define FF2_WIDEOFFSETS 0x08
88 #define FF2_UNICODE 0x20
89 #define FF2_SHIFTJIS 0x40
90 #define FF2_LAYOUT 0x80
92 int swf_FontIsItalic(SWFFONT * f)
94 return f->style & FONT_STYLE_ITALIC;
97 int swf_FontIsBold(SWFFONT * f)
99 return f->style & FONT_STYLE_BOLD;
102 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
104 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
114 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
125 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
128 swf_GetBlock(t, s, l);
132 (FontCallback) (self, id, s);
134 swf_RestoreTagPos(t);
142 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
149 if ((!id) || (id == fid)) {
160 f->glyph = rfx_calloc(sizeof(SWFGLYPH) * n);
162 for (i = 1; i < n; i++)
164 for (i = 0; i < n; i++)
165 swf_GetSimpleShape(t, &f->glyph[i].shape);
168 swf_RestoreTagPos(t);
172 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
185 if (f->version > 1) {
186 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
187 too. However, they only add little information to what's already
188 inside the DefineFont2 tag */
195 f->name = (U8 *) rfx_alloc(l + 1);
196 swf_GetBlock(t, f->name, l);
199 flags = swf_GetU8(t);
201 f->style |= FONT_STYLE_BOLD;
203 f->style |= FONT_STYLE_ITALIC;
205 f->encoding |= FONT_ENCODING_ANSI;
207 f->encoding |= FONT_ENCODING_SHIFTJIS;
209 f->encoding |= FONT_ENCODING_UNICODE;
211 if (t->id == ST_DEFINEFONTINFO2) {
212 f->language = swf_GetU8(t);
215 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
217 for (i = 0; i < f->numchars; i++) {
218 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
219 if (f->glyph2ascii[i] > maxcode)
220 maxcode = f->glyph2ascii[i];
225 f->maxascii = maxcode;
226 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
227 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
229 for (i = 0; i < f->numchars; i++)
230 f->ascii2glyph[f->glyph2ascii[i]] = i;
233 swf_RestoreTagPos(t);
237 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
243 swf_SetTagPos(tag, 0);
245 fid = swf_GetU16(tag);
248 int num = swf_GetU16(tag);
250 f->glyphnames = rfx_alloc(sizeof(char *) * num);
251 for (t = 0; t < num; t++) {
252 f->glyphnames[t] = strdup(swf_GetString(tag));
256 swf_RestoreTagPos(tag);
261 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
268 U8 flags1, flags2, namelen;
270 swf_SetTagPos(tag, 0);
272 fid = swf_GetU16(tag);
276 flags1 = swf_GetU8(tag);
277 flags2 = swf_GetU8(tag); //reserved flags
280 font->style |= FONT_STYLE_BOLD;
282 font->style |= FONT_STYLE_ITALIC;
284 font->encoding |= FONT_ENCODING_ANSI;
286 font->encoding |= FONT_ENCODING_UNICODE;
288 font->encoding |= FONT_ENCODING_SHIFTJIS;
290 namelen = swf_GetU8(tag);
291 font->name = (U8 *) rfx_alloc(namelen + 1);
292 font->name[namelen] = 0;
293 swf_GetBlock(tag, font->name, namelen);
295 glyphcount = swf_GetU16(tag);
296 font->numchars = glyphcount;
298 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
299 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
301 offset = rfx_calloc(sizeof(U32)*(glyphcount+1));
302 offset_start = tag->pos;
304 if (flags1 & 8) { // wide offsets
305 for (t = 0; t < glyphcount; t++)
306 offset[t] = swf_GetU32(tag); //offset[t]
308 if (glyphcount) /* this _if_ is not in the specs */
309 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
311 offset[glyphcount] = tag->pos;
313 for (t = 0; t < glyphcount; t++)
314 offset[t] = swf_GetU16(tag); //offset[t]
316 if (glyphcount) /* this _if_ is not in the specs */
317 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
319 offset[glyphcount] = tag->pos;
321 for (t = 0; t < glyphcount; t++) {
322 swf_SetTagPos(tag, offset[t]+offset_start);
323 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
326 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
331 for (t = 0; t < glyphcount; t++) {
333 if (flags1 & 4) // wide codes
334 code = swf_GetU16(tag);
336 code = swf_GetU8(tag);
337 font->glyph2ascii[t] = code;
344 font->maxascii = maxcode;
345 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
346 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
347 for (t = 0; t < glyphcount; t++) {
348 font->ascii2glyph[font->glyph2ascii[t]] = t;
351 if (flags1 & 128) { // has layout
353 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
354 font->layout->ascent = swf_GetU16(tag);
355 font->layout->descent = swf_GetU16(tag);
356 font->layout->leading = swf_GetU16(tag);
357 for (t = 0; t < glyphcount; t++) {
358 S16 advance = swf_GetS16(tag);
359 font->glyph[t].advance = advance;
361 font->layout->bounds = rfx_alloc(glyphcount * sizeof(SRECT));
362 for (t = 0; t < glyphcount; t++) {
363 swf_ResetReadBits(tag);
364 swf_GetRect(tag, &font->layout->bounds[t]);
367 kerningcount = swf_GetU16(tag);
368 font->layout->kerningcount = kerningcount;
370 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
372 font->layout->kerning = rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
373 for (t = 0; t < kerningcount; t++) {
374 if (flags1 & 4) { // wide codes
375 font->layout->kerning[t].char1 = swf_GetU16(tag);
376 font->layout->kerning[t].char2 = swf_GetU16(tag);
378 font->layout->kerning[t].char1 = swf_GetU8(tag);
379 font->layout->kerning[t].char2 = swf_GetU8(tag);
381 font->layout->kerning[t].adjustment = swf_GetS16(tag);
385 swf_RestoreTagPos(t);
390 #define FEDTJ_PRINT 0x01
391 #define FEDTJ_MODIFY 0x02
392 #define FEDTJ_CALLBACK 0x04
395 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
396 void (*callback) (void *self,
397 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
408 memset(&color, 0, sizeof(color));
415 swf_GetMatrix(t, &m);
416 gbits = swf_GetU8(t);
417 abits = swf_GetU8(t);
421 flags = swf_GetU8(t);
425 if (flags & TF_TEXTCONTROL) {
426 if (flags & TF_HASFONT)
428 if (flags & TF_HASCOLOR) {
429 color.r = swf_GetU8(t); // rgb
430 color.g = swf_GetU8(t);
431 color.b = swf_GetU8(t);
432 if (swf_GetTagID(t) == ST_DEFINETEXT2)
433 color.a = swf_GetU8(t);
437 if (flags & TF_HASXOFFSET)
439 if (flags & TF_HASYOFFSET)
441 if (flags & TF_HASFONT)
442 fontsize = swf_GetU16(t);
454 for (i = 0; i < num; i++) {
458 glyph = swf_GetBits(t, gbits);
459 adv = swf_GetBits(t, abits);
464 if (jobs & FEDTJ_PRINT) {
465 int code = f->glyph2ascii[glyph];
468 if (jobs & FEDTJ_MODIFY)
469 f->glyph[glyph].advance = adv * 20; //?
471 if (jobs & FEDTJ_PRINT) {
479 if ((id == fid) && (jobs & FEDTJ_PRINT))
481 if (jobs & FEDTJ_CALLBACK)
482 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
487 swf_RestoreTagPos(t);
491 int swf_ParseDefineText(TAG * tag,
492 void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
494 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
497 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
499 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
502 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
507 if ((!swf) || (!font))
510 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
516 switch (swf_GetTagID(t)) {
518 nid = swf_FontExtract_DefineFont(id, f, t);
522 nid = swf_FontExtract_DefineFont2(id, f, t);
525 case ST_DEFINEFONTINFO:
526 case ST_DEFINEFONTINFO2:
527 nid = swf_FontExtract_DefineFontInfo(id, f, t);
532 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
536 nid = swf_FontExtract_GlyphNames(id, f, t);
551 int swf_FontSetID(SWFFONT * f, U16 id)
559 void swf_LayoutFree(SWFLAYOUT * l)
563 rfx_free(l->kerning);
573 static void font_freeglyphnames(SWFFONT*f)
577 for (t = 0; t < f->numchars; t++) {
578 if (f->glyphnames[t]) {
579 rfx_free(f->glyphnames[t]);
580 f->glyphnames[t] = 0;
583 rfx_free(f->glyphnames);
588 static void font_freeusage(SWFFONT*f)
592 rfx_free(f->use->chars);f->use->chars = 0;
594 rfx_free(f->use); f->use = 0;
597 static void font_freelayout(SWFFONT*f)
600 swf_LayoutFree(f->layout);
604 static void font_freename(SWFFONT*f)
612 int swf_FontReduce_old(SWFFONT * f)
616 if ((!f) || (!f->use) || f->use->is_reduced)
621 for (i = 0; i < f->numchars; i++) {
622 if (f->glyph[i].shape && f->use->chars[i]) {
623 f->glyph2ascii[j] = f->glyph2ascii[i];
624 f->glyph[j] = f->glyph[i];
625 f->use->chars[i] = j;
628 f->glyph2ascii[i] = 0;
629 if(f->glyph[i].shape) {
630 swf_ShapeFree(f->glyph[i].shape);
631 f->glyph[i].shape = 0;
632 f->glyph[i].advance = 0;
634 f->use->chars[i] = -1;
638 for (i = 0; i < f->maxascii; i++) {
639 if(f->use->chars[f->ascii2glyph[i]]<0) {
640 f->ascii2glyph[i] = -1;
642 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
646 f->maxascii = max_unicode;
647 f->use->is_reduced = 1;
650 font_freeglyphnames(f);
655 int swf_FontReduce(SWFFONT * f)
660 if ((!f) || (!f->use) || f->use->is_reduced)
664 font_freeglyphnames(f);
666 for (i = 0; i < f->numchars; i++) {
667 if(!f->use->chars[i]) {
668 f->glyph2ascii[i] = 0;
669 if(f->glyph[i].shape) {
670 swf_ShapeFree(f->glyph[i].shape);
671 f->glyph[i].shape = 0;
672 f->glyph[i].advance = 0;
678 for (i = 0; i < f->maxascii; i++) {
679 if(!f->use->chars[f->ascii2glyph[i]]) {
680 f->ascii2glyph[i] = -1;
685 f->maxascii = max_unicode;
686 f->numchars = max_glyph;
691 void swf_FontSort(SWFFONT * font)
699 newplace = rfx_alloc(sizeof(int) * font->numchars);
701 for (i = 0; i < font->numchars; i++) {
704 for (i = 0; i < font->numchars; i++)
705 for (j = 0; j < i; j++) {
706 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
715 n1 = font->glyph2ascii[i];
716 n2 = font->glyph2ascii[j];
717 font->glyph2ascii[j] = n1;
718 font->glyph2ascii[i] = n2;
723 if (font->glyphnames) {
724 c1 = font->glyphnames[i];
725 c2 = font->glyphnames[j];
726 font->glyphnames[j] = c1;
727 font->glyphnames[i] = c2;
730 r1 = font->layout->bounds[i];
731 r2 = font->layout->bounds[j];
732 font->layout->bounds[j] = r1;
733 font->layout->bounds[i] = r2;
737 newpos = rfx_alloc(sizeof(int) * font->numchars);
738 for (i = 0; i < font->numchars; i++) {
739 newpos[newplace[i]] = i;
741 for (i = 0; i < font->maxascii; i++) {
742 if (font->ascii2glyph[i] >= 0)
743 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
750 void swf_FontPrepareForEditText(SWFFONT * font)
753 swf_FontCreateLayout(font);
757 int swf_FontInitUsage(SWFFONT * f)
762 fprintf(stderr, "Usage initialized twice");
765 f->use = rfx_alloc(sizeof(FONTUSAGE));
766 f->use->is_reduced = 0;
767 f->use->chars = rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
771 void swf_FontClearUsage(SWFFONT * f)
775 rfx_free(f->use->chars); f->use->chars = 0;
776 rfx_free(f->use); f->use = 0;
779 int swf_FontUse(SWFFONT * f, U8 * s)
782 swf_FontInitUsage(f);
786 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
787 f->use->chars[f->ascii2glyph[*s]] = 1;
793 int swf_FontUseGlyph(SWFFONT * f, int glyph)
796 swf_FontInitUsage(f);
797 if(glyph < 0 || glyph >= f->numchars)
799 f->use->chars[glyph] = 1;
803 int swf_FontSetDefine(TAG * t, SWFFONT * f)
805 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
810 swf_ResetWriteBits(t);
811 swf_SetU16(t, f->id);
815 for (i = 0; i < f->numchars; i++)
816 if (f->glyph[i].shape) {
818 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
821 for (i = 0; i < j; i++)
822 swf_SetU16(t, ofs[i] + j * 2);
824 fprintf(stderr, "rfxswf: warning: Font is empty\n");
828 for (i = 0; i < f->numchars; i++)
829 if (f->glyph[i].shape)
830 swf_SetSimpleShape(t, f->glyph[i].shape);
832 swf_ResetWriteBits(t);
837 static inline int fontSize(SWFFONT * font)
841 for (t = 0; t < font->numchars; t++) {
843 if(font->glyph[t].shape)
844 l = (font->glyph[t].shape->bitlen + 7) / 8;
849 return size + (font->numchars + 1) * 2;
852 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
858 swf_SetU16(tag, f->id);
860 if (f->layout) flags |= 128; // haslayout
861 if (f->numchars > 256)
862 flags |= 4; // widecodes
863 if (f->style & FONT_STYLE_BOLD)
865 if (f->style & FONT_STYLE_ITALIC)
866 flags |= 2; // italic
867 if (f->maxascii >= 256)
868 flags |= 4; //wide codecs
869 if (fontSize(f) > 65535)
870 flags |= 8; //wide offsets
871 flags |= 8 | 4; //FIXME: the above check doesn't work
873 if (f->encoding & FONT_ENCODING_ANSI)
875 if (f->encoding & FONT_ENCODING_UNICODE)
876 flags |= 32; // unicode
877 if (f->encoding & FONT_ENCODING_SHIFTJIS)
878 flags |= 64; // shiftjis
880 swf_SetU8(tag, flags);
881 swf_SetU8(tag, 0); //reserved flags
884 swf_SetU8(tag, strlen(f->name));
885 swf_SetBlock(tag, f->name, strlen(f->name));
887 /* font name (="") */
890 /* number of glyphs */
891 swf_SetU16(tag, f->numchars);
892 /* font offset table */
894 for (t = 0; t <= f->numchars; t++) {
896 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
898 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
901 for (t = 0; t <= f->numchars; t++) {
903 tag->data[pos + t * 4] = (tag->len - pos);
904 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
905 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
906 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
908 if (tag->len - pos > 65535) {
909 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
912 tag->data[pos + t * 2] = (tag->len - pos);
913 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
915 if (t < f->numchars) {
916 if(f->glyph[t].shape) {
917 swf_SetSimpleShape(tag, f->glyph[t].shape);
919 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
925 /* font code table */
926 if (flags & 4) { /* wide codes */
927 for (t = 0; t < f->numchars; t++) {
928 swf_SetU16(tag, f->glyph2ascii[t]);
931 for (t = 0; t < f->numchars; t++)
932 swf_SetU8(tag, f->glyph2ascii[t]);
935 swf_SetU16(tag, f->layout->ascent);
936 swf_SetU16(tag, f->layout->descent);
937 swf_SetU16(tag, f->layout->leading);
938 for (t = 0; t < f->numchars; t++)
939 swf_SetU16(tag, f->glyph[t].advance);
940 for (t = 0; t < f->numchars; t++) {
941 swf_ResetWriteBits(tag);
942 swf_SetRect(tag, &f->layout->bounds[t]);
944 swf_SetU16(tag, f->layout->kerningcount);
945 for (t = 0; t < f->layout->kerningcount; t++) {
946 if (flags & 4) { /* wide codes */
947 swf_SetU16(tag, f->layout->kerning[t].char1);
948 swf_SetU16(tag, f->layout->kerning[t].char2);
950 swf_SetU8(tag, f->layout->kerning[t].char1);
951 swf_SetU8(tag, f->layout->kerning[t].char2);
953 swf_SetU16(tag, f->layout->kerning[t].adjustment);
959 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
961 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
962 f->layout->ascent = ascent;
963 f->layout->descent = descent;
964 f->layout->leading = leading;
965 f->layout->kerningcount = 0;
966 f->layout->kerning = 0;
967 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
970 int swf_FontSetInfo(TAG * t, SWFFONT * f)
977 swf_ResetWriteBits(t);
978 swf_SetU16(t, f->id);
979 l = f->name ? strlen(f->name) : 0;
984 swf_SetBlock(t, f->name, l);
985 if (f->numchars >= 256)
988 if (f->style & FONT_STYLE_BOLD)
990 if (f->style & FONT_STYLE_ITALIC)
992 if (f->style & FONT_ENCODING_ANSI)
994 if (f->style & FONT_ENCODING_SHIFTJIS)
996 if (f->style & FONT_ENCODING_UNICODE)
999 swf_SetU8(t, (flags & 0xfe) | wide);
1001 for (i = 0; i < f->numchars; i++) {
1002 if (f->glyph[i].shape) {
1003 int g2a = f->glyph2ascii[i];
1004 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1011 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1013 int id = swf_GetTagID(t);
1014 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1015 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1021 void swf_FontFree(SWFFONT * f)
1028 for (i = 0; i < f->numchars; i++)
1029 if (f->glyph[i].shape) {
1030 swf_ShapeFree(f->glyph[i].shape);
1031 f->glyph[i].shape = NULL;
1036 if (f->ascii2glyph) {
1037 rfx_free(f->ascii2glyph);
1038 f->ascii2glyph = NULL;
1040 if (f->glyph2ascii) {
1041 rfx_free(f->glyph2ascii);
1042 f->glyph2ascii = NULL;
1046 font_freeglyphnames(f);
1052 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1058 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1059 | (dy ? TF_HASYOFFSET : 0);
1061 swf_SetU8(t, flags);
1063 swf_SetU16(t, font->id);
1065 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1066 swf_SetRGBA(t, color);
1068 swf_SetRGB(t, color);
1071 if(dx != SET_TO_ZERO) {
1072 if(dx>32767 || dx<-32768)
1073 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1080 if(dy != SET_TO_ZERO) {
1081 if(dy>32767 || dy<-32768)
1082 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1089 swf_SetU16(t, size);
1094 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1098 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1102 if (!strcmp(encoding, "UTF8"))
1104 else if (!strcmp(encoding, "iso-8859-1"))
1107 fprintf(stderr, "Unknown encoding: %s", encoding);
1115 c = readUTF8char(&s);
1117 if (c < font->maxascii)
1118 glyph = font->ascii2glyph[c];
1120 g = swf_CountUBits(glyph, g);
1121 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1132 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1137 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1140 if (!strcmp(encoding, "UTF8"))
1142 else if (!strcmp(encoding, "iso-8859-1"))
1145 fprintf(stderr, "Unknown encoding: %s", encoding);
1148 swf_SetU8(t, l); //placeholder
1156 c = readUTF8char(&s);
1158 if (c < font->maxascii)
1159 g = font->ascii2glyph[c];
1161 swf_SetBits(t, g, gbits);
1162 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1164 /* We split into 127 characters per text field.
1165 We could do 255, by the (formerly wrong) flash specification,
1166 but some SWF parsing code out there still assumes that char blocks
1167 are at max 127 characters, and it would save only a few bits.
1174 PUT8(&t->data[pos], l);
1176 swf_ResetWriteBits(t);
1180 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1182 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1185 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1187 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1190 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1192 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1195 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1197 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1200 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1207 if (*s < font->maxascii)
1208 g = font->ascii2glyph[*s];
1210 res += font->glyph[g].advance / 20;
1214 res = (res * scale) / 100;
1219 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1226 int c = readUTF8char(&s);
1227 if(c==13 || c==10) {
1232 ypos+=font->layout->leading;
1235 if (c < font->maxascii) {
1236 int g = font->ascii2glyph[c];
1238 SRECT rn = font->layout->bounds[g];
1239 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1240 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1241 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1242 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1243 swf_ExpandRect2(&r, &rn);
1244 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1252 SWFFONT *swf_ReadFont(char *filename)
1258 f = open(filename, O_RDONLY|O_BINARY);
1260 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1261 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1267 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1274 void swf_WriteFont(SWFFONT * font, char *filename)
1281 int useDefineFont2 = 0;
1282 int storeGlyphNames = 1;
1285 useDefineFont2 = 1; /* the only thing new in definefont2
1286 is layout information. */
1288 font->id = WRITEFONTID; //"FN"
1290 memset(&swf, 0x00, sizeof(SWF));
1292 swf.fileVersion = 4;
1293 swf.frameRate = 0x4000;
1295 /* if we use DefineFont1 to store the characters,
1296 we have to build a textfield to store the
1297 advance values. While at it, we can also
1298 make the whole .swf viewable */
1300 /* we now always create viewable swfs, even if we
1301 did use definefont2 -mk */
1302 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1307 swf_SetRGB(t, &rgb);
1308 if (!useDefineFont2) {
1309 t = swf_InsertTag(t, ST_DEFINEFONT);
1310 swf_FontSetDefine(t, font);
1311 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1312 swf_FontSetInfo(t, font);
1314 t = swf_InsertTag(t, ST_DEFINEFONT2);
1315 swf_FontSetDefine2(t, font);
1318 if (storeGlyphNames && font->glyphnames) {
1320 t = swf_InsertTag(t, ST_GLYPHNAMES);
1321 swf_SetU16(t, WRITEFONTID);
1322 swf_SetU16(t, font->numchars);
1323 for (c = 0; c < font->numchars; c++) {
1324 if (font->glyphnames[c])
1325 swf_SetString(t, font->glyphnames[c]);
1327 swf_SetString(t, "");
1331 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1333 int textscale = 400;
1340 int range = font->maxascii;
1343 if (useDefineFont2 && range > 256) {
1347 for (s = 0; s < range; s++) {
1348 int g = font->ascii2glyph[s];
1350 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1351 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1355 if ((s & 15) == 0) {
1362 ymax = ypos * textscale * 2;
1364 swf.movieSize.xmax = xmax * 20;
1365 swf.movieSize.ymax = ymax;
1367 t = swf_InsertTag(t, ST_DEFINETEXT);
1369 swf_SetU16(t, font->id + 1); // ID
1373 r.xmax = swf.movieSize.xmax;
1374 r.ymax = swf.movieSize.ymax;
1378 swf_SetMatrix(t, NULL);
1380 abits = swf_CountBits(xmax * 16, 0);
1383 swf_SetU8(t, gbits);
1384 swf_SetU8(t, abits);
1390 for (y = 0; y < ((range + 15) / 16); y++) {
1391 int c = 0, lastx = -1;
1392 for (x = 0; x < 16; x++) {
1393 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1394 if (g >= 0 && font->glyph[g].shape) {
1401 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1402 for (x = 0; x < 16; x++) {
1403 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1404 if (g >= 0 && font->glyph[g].shape) {
1405 if (lastx != x * xmax) {
1406 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1409 swf_SetBits(t, g, gbits);
1410 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1411 lastx = x * xmax + (font->glyph[g].advance / 20);
1412 swf_ResetWriteBits(t);
1421 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1423 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1425 t = swf_InsertTag(t, ST_SHOWFRAME);
1429 t = swf_InsertTag(t, ST_END);
1431 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1433 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1440 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1442 swf_SetRect(tag, &r);
1443 swf_ResetWriteBits(tag);
1445 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1447 flags |= ET_HASTEXT;
1449 flags |= ET_HASTEXTCOLOR;
1451 flags |= ET_HASMAXLENGTH;
1453 flags |= ET_HASFONT;
1455 flags |= ET_HASLAYOUT;
1457 swf_SetBits(tag, flags, 16);
1459 if (flags & ET_HASFONT) {
1460 swf_SetU16(tag, font); //font
1461 swf_SetU16(tag, height); //fontheight
1463 if (flags & ET_HASTEXTCOLOR) {
1464 swf_SetRGBA(tag, color);
1466 if (flags & ET_HASMAXLENGTH) {
1467 swf_SetU16(tag, maxlength); //maxlength
1469 if (flags & ET_HASLAYOUT) {
1470 swf_SetU8(tag, layout->align); //align
1471 swf_SetU16(tag, layout->leftmargin); //left margin
1472 swf_SetU16(tag, layout->rightmargin); //right margin
1473 swf_SetU16(tag, layout->indent); //indent
1474 swf_SetU16(tag, layout->leading); //leading
1476 swf_SetString(tag, variable);
1477 if (flags & ET_HASTEXT)
1478 swf_SetString(tag, text);
1481 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1485 U8 *utext = (U8 *) strdup(text);
1491 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1492 ystep = font->layout->leading;
1494 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1495 /* Hm, without layout information, we can't compute a bounding
1496 box. We could call swf_FontCreateLayout to create a layout,
1497 but the caller probably doesn't want us to mess up his font
1500 r.xmin = r.ymin = 0;
1501 r.xmax = r.ymax = 1024 * 20;
1505 swf_SetRect(tag, &r);
1507 /* The text matrix is pretty boring, as it doesn't apply to
1508 individual characters, but rather whole text objects (or
1509 at least whole char records- haven't tested).
1510 So it can't do anything which we can't already do with
1511 the placeobject tag we use for placing the text on the scene.
1513 swf_SetMatrix(tag, 0);
1515 swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1516 swf_SetU8(tag, gbits);
1517 swf_SetU8(tag, abits);
1523 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1526 while(*next && *next!=13 && *next!=10 && count<127) {
1527 readUTF8char(&next);
1530 if(next[0] == 13 || next[0] == 10) {
1535 if(next[0] == 13 && next[1] == 10)
1538 if(next[0] == 13 || next[0] == 10) {
1543 /* now set the text params- notice that a font size of
1544 1024 means that the glyphs will be displayed exactly
1545 as they would be in/with a defineshape. (Try to find
1546 *that* in the flash specs)
1548 /* set the actual text- notice that we just pass our scale
1549 parameter over, as TextSetCharRecord calculates with
1551 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1555 printf("%s\n", upos);
1563 void swf_FontCreateLayout(SWFFONT * f)
1572 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1573 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1574 f->layout->ascent = -32767;
1575 f->layout->descent = -32767;
1577 for (t = 0; t < f->numchars; t++) {
1581 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1583 fprintf(stderr, "Shape parse error\n");
1586 bbox = swf_GetShapeBoundingBox(shape2);
1587 swf_Shape2Free(shape2);
1588 f->layout->bounds[t] = bbox;
1590 width = (bbox.xmax);
1592 /* The following is a heuristic- it may be that extractfont_DefineText
1593 has already found out some widths for individual characters (from the way
1594 they are used)- we now have to guess whether that width might be possible,
1595 which is the case if it isn't either much too big or much too small */
1596 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1597 f->glyph[t].advance = width;
1599 if (-bbox.ymin > f->layout->ascent)
1600 f->layout->ascent = bbox.ymin;
1601 if (bbox.ymax > f->layout->descent)
1602 f->layout->descent = bbox.ymax;
1606 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1608 U8 *s = (U8 *) text;
1614 U32 c = readUTF8char(&s);
1615 int g = font->ascii2glyph[c];
1616 shape = font->glyph[g].shape;
1617 if (((int) g) < 0) {
1618 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1621 shape2 = swf_ShapeToShape2(shape);
1624 if (l->type == moveTo) {
1626 to.x = l->x * size / 100.0 / 20.0 + advance;
1627 to.y = l->y * size / 100.0 / 20.0;
1628 draw->moveTo(draw, &to);
1629 } else if (l->type == lineTo) {
1631 to.x = l->x * size / 100.0 / 20.0 + advance;
1632 to.y = l->y * size / 100.0 / 20.0;
1633 draw->lineTo(draw, &to);
1634 } else if (l->type == splineTo) {
1636 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1637 mid.y = l->sy * size / 100.0 / 20.0;
1638 to.x = l->x * size / 100.0 / 20.0 + advance;
1639 to.y = l->y * size / 100.0 / 20.0;
1640 draw->splineTo(draw, &mid, &to);
1644 swf_Shape2Free(shape2);
1645 advance += font->glyph[g].advance * size / 100.0 / 20.0;