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);
1169 PUT8(&t->data[pos], l);
1171 swf_ResetWriteBits(t);
1175 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1177 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1180 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1182 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1185 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1187 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1190 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1192 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1195 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1202 if (*s < font->maxascii)
1203 g = font->ascii2glyph[*s];
1205 res += font->glyph[g].advance / 20;
1209 res = (res * scale) / 100;
1214 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1221 int c = readUTF8char(&s);
1222 if (c < font->maxascii) {
1223 int g = font->ascii2glyph[c];
1225 SRECT rn = font->layout->bounds[g];
1226 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1227 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1228 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1229 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1230 swf_ExpandRect2(&r, &rn);
1231 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1240 SWFFONT *swf_ReadFont(char *filename)
1246 f = open(filename, O_RDONLY|O_BINARY);
1248 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1249 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1255 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1262 void swf_WriteFont(SWFFONT * font, char *filename)
1269 int useDefineFont2 = 0;
1270 int storeGlyphNames = 1;
1273 useDefineFont2 = 1; /* the only thing new in definefont2
1274 is layout information. */
1276 font->id = WRITEFONTID; //"FN"
1278 memset(&swf, 0x00, sizeof(SWF));
1280 swf.fileVersion = 4;
1281 swf.frameRate = 0x4000;
1283 /* if we use DefineFont1 to store the characters,
1284 we have to build a textfield to store the
1285 advance values. While at it, we can also
1286 make the whole .swf viewable */
1288 /* we now always create viewable swfs, even if we
1289 did use definefont2 -mk */
1290 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1295 swf_SetRGB(t, &rgb);
1296 if (!useDefineFont2) {
1297 t = swf_InsertTag(t, ST_DEFINEFONT);
1298 swf_FontSetDefine(t, font);
1299 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1300 swf_FontSetInfo(t, font);
1302 t = swf_InsertTag(t, ST_DEFINEFONT2);
1303 swf_FontSetDefine2(t, font);
1306 if (storeGlyphNames && font->glyphnames) {
1308 t = swf_InsertTag(t, ST_GLYPHNAMES);
1309 swf_SetU16(t, WRITEFONTID);
1310 swf_SetU16(t, font->numchars);
1311 for (c = 0; c < font->numchars; c++) {
1312 if (font->glyphnames[c])
1313 swf_SetString(t, font->glyphnames[c]);
1315 swf_SetString(t, "");
1319 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1321 int textscale = 400;
1328 int range = font->maxascii;
1331 if (useDefineFont2 && range > 256) {
1335 for (s = 0; s < range; s++) {
1336 int g = font->ascii2glyph[s];
1338 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1339 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1343 if ((s & 15) == 0) {
1350 ymax = ypos * textscale * 2;
1352 swf.movieSize.xmax = xmax * 20;
1353 swf.movieSize.ymax = ymax;
1355 t = swf_InsertTag(t, ST_DEFINETEXT);
1357 swf_SetU16(t, font->id + 1); // ID
1361 r.xmax = swf.movieSize.xmax;
1362 r.ymax = swf.movieSize.ymax;
1366 swf_SetMatrix(t, NULL);
1368 abits = swf_CountBits(xmax * 16, 0);
1371 swf_SetU8(t, gbits);
1372 swf_SetU8(t, abits);
1378 for (y = 0; y < ((range + 15) / 16); y++) {
1379 int c = 0, lastx = -1;
1380 for (x = 0; x < 16; x++) {
1381 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1382 if (g >= 0 && font->glyph[g].shape) {
1389 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1390 for (x = 0; x < 16; x++) {
1391 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1392 if (g >= 0 && font->glyph[g].shape) {
1393 if (lastx != x * xmax) {
1394 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1397 swf_SetBits(t, g, gbits);
1398 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1399 lastx = x * xmax + (font->glyph[g].advance / 20);
1400 swf_ResetWriteBits(t);
1409 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1411 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1413 t = swf_InsertTag(t, ST_SHOWFRAME);
1417 t = swf_InsertTag(t, ST_END);
1419 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1421 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1428 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1430 swf_SetRect(tag, &r);
1431 swf_ResetWriteBits(tag);
1433 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1435 flags |= ET_HASTEXT;
1437 flags |= ET_HASTEXTCOLOR;
1439 flags |= ET_HASMAXLENGTH;
1441 flags |= ET_HASFONT;
1443 flags |= ET_HASLAYOUT;
1445 swf_SetBits(tag, flags, 16);
1447 if (flags & ET_HASFONT) {
1448 swf_SetU16(tag, font); //font
1449 swf_SetU16(tag, height); //fontheight
1451 if (flags & ET_HASTEXTCOLOR) {
1452 swf_SetRGBA(tag, color);
1454 if (flags & ET_HASMAXLENGTH) {
1455 swf_SetU16(tag, maxlength); //maxlength
1457 if (flags & ET_HASLAYOUT) {
1458 swf_SetU8(tag, layout->align); //align
1459 swf_SetU16(tag, layout->leftmargin); //left margin
1460 swf_SetU16(tag, layout->rightmargin); //right margin
1461 swf_SetU16(tag, layout->indent); //indent
1462 swf_SetU16(tag, layout->leading); //leading
1464 swf_SetString(tag, variable);
1465 if (flags & ET_HASTEXT)
1466 swf_SetString(tag, text);
1469 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1473 U8 *c = (U8 *) text;
1476 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1478 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1479 /* Hm, without layout information, we can't compute a bounding
1480 box. We could call swf_FontCreateLayout to create a layout,
1481 but the caller probably doesn't want us to mess up his font
1484 r.xmin = r.ymin = 0;
1485 r.xmax = r.ymax = 1024 * 20;
1488 swf_SetRect(tag, &r);
1490 /* The text matrix is pretty boring, as it doesn't apply to
1491 individual characters, but rather whole text objects (or
1492 at least whole char records- haven't tested).
1493 So it can't do anything which we can't already do with
1494 the placeobject tag we use for placing the text on the scene.
1496 swf_SetMatrix(tag, 0);
1498 swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1499 swf_SetU8(tag, gbits);
1500 swf_SetU8(tag, abits);
1502 /* now set the text params- notice that a font size of
1503 1024 means that the glyphs will be displayed exactly
1504 as they would be in/with a defineshape. (Try to find
1505 *that* in the flash specs)
1507 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, 0, 0); //scale
1509 /* set the actual text- notice that we just pass our scale
1510 parameter over, as TextSetCharRecord calculates with
1512 swf_TextSetCharRecordUTF8(tag, font, text, scale * 20, gbits, abits);
1518 void swf_FontCreateLayout(SWFFONT * f)
1527 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1528 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1529 f->layout->ascent = -32767;
1530 f->layout->descent = -32767;
1532 for (t = 0; t < f->numchars; t++) {
1536 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1538 fprintf(stderr, "Shape parse error\n");
1541 bbox = swf_GetShapeBoundingBox(shape2);
1542 swf_Shape2Free(shape2);
1543 f->layout->bounds[t] = bbox;
1545 width = (bbox.xmax);
1547 /* The following is a heuristic- it may be that extractfont_DefineText
1548 has already found out some widths for individual characters (from the way
1549 they are used)- we now have to guess whether that width might be possible,
1550 which is the case if it isn't either much too big or much too small */
1551 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1552 f->glyph[t].advance = width;
1554 if (-bbox.ymin > f->layout->ascent)
1555 f->layout->ascent = bbox.ymin;
1556 if (bbox.ymax > f->layout->descent)
1557 f->layout->descent = bbox.ymax;
1561 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1563 U8 *s = (U8 *) text;
1569 U32 c = readUTF8char(&s);
1570 int g = font->ascii2glyph[c];
1571 shape = font->glyph[g].shape;
1572 if (((int) g) < 0) {
1573 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1576 shape2 = swf_ShapeToShape2(shape);
1579 if (l->type == moveTo) {
1581 to.x = l->x * size / 100.0 / 20.0 + advance;
1582 to.y = l->y * size / 100.0 / 20.0;
1583 draw->moveTo(draw, &to);
1584 } else if (l->type == lineTo) {
1586 to.x = l->x * size / 100.0 / 20.0 + advance;
1587 to.y = l->y * size / 100.0 / 20.0;
1588 draw->lineTo(draw, &to);
1589 } else if (l->type == splineTo) {
1591 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1592 mid.y = l->sy * size / 100.0 / 20.0;
1593 to.x = l->x * size / 100.0 / 20.0 + advance;
1594 to.y = l->y * size / 100.0 / 20.0;
1595 draw->splineTo(draw, &mid, &to);
1599 swf_Shape2Free(shape2);
1600 advance += font->glyph[g].advance * size / 100.0 / 20.0;