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 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)
578 for (t = 0; t < f->numchars; t++)
580 if (f->glyphnames[t])
582 rfx_free(f->glyphnames[t]);
583 f->glyphnames[t] = 0;
586 rfx_free(f->glyphnames);
590 static void font_freeusage(SWFFONT*f)
594 rfx_free(f->use->chars);f->use->chars = 0;
596 rfx_free(f->use); f->use = 0;
599 static void font_freelayout(SWFFONT*f)
602 swf_LayoutFree(f->layout);
606 static void font_freename(SWFFONT*f)
614 int swf_FontReduce_old(SWFFONT * f)
618 if ((!f) || (!f->use) || f->use->is_reduced)
623 for (i = 0; i < f->numchars; i++) {
624 if (f->glyph[i].shape && f->use->chars[i]) {
625 f->glyph2ascii[j] = f->glyph2ascii[i];
626 f->glyph[j] = f->glyph[i];
627 f->use->chars[i] = j;
630 f->glyph2ascii[i] = 0;
631 if(f->glyph[i].shape) {
632 swf_ShapeFree(f->glyph[i].shape);
633 f->glyph[i].shape = 0;
634 f->glyph[i].advance = 0;
636 f->use->chars[i] = -1;
640 for (i = 0; i < f->maxascii; i++) {
641 if(f->use->chars[f->ascii2glyph[i]]<0) {
642 f->ascii2glyph[i] = -1;
644 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
648 f->maxascii = max_unicode;
649 f->use->is_reduced = 1;
652 font_freeglyphnames(f);
657 int swf_FontReduce_swfc(SWFFONT * f)
661 if ((!f) || (!f->use) || f->use->is_reduced)
664 font_freeglyphnames(f);
667 for (i = 0; i < f->numchars; i++) {
668 if (f->glyph[i].shape && f->use->chars[i]) {
669 f->glyph2ascii[j] = f->glyph2ascii[i];
671 f->layout->bounds[j] = f->layout->bounds[i];
672 f->glyph[j] = f->glyph[i];
673 f->use->chars[i] = j;
676 f->glyph2ascii[i] = 0;
677 if(f->glyph[i].shape) {
678 swf_ShapeFree(f->glyph[i].shape);
679 f->glyph[i].shape = 0;
680 f->glyph[i].advance = 0;
682 f->use->chars[i] = -1;
685 f->use->used_glyphs = j;
686 for (i = 0; i < f->maxascii; i++) {
687 if(f->ascii2glyph[i] > -1)
688 if (f->use->chars[f->ascii2glyph[i]]<0) {
689 f->use->chars[f->ascii2glyph[i]] = 0;
690 f->ascii2glyph[i] = -1;
692 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
693 f->use->chars[f->ascii2glyph[i]] = 1;
697 f->maxascii = max_unicode;
698 f->use->is_reduced = 1;
704 int swf_FontReduce(SWFFONT * f)
709 if ((!f) || (!f->use) || f->use->is_reduced)
713 font_freeglyphnames(f);
715 f->use->used_glyphs= 0;
716 for (i = 0; i < f->numchars; i++) {
717 if(!f->use->chars[i]) {
719 f->glyph2ascii[i] = 0;
721 if(f->glyph[i].shape) {
722 swf_ShapeFree(f->glyph[i].shape);
723 f->glyph[i].shape = 0;
724 f->glyph[i].advance = 0;
726 // f->use->used_glyphs++;
728 f->use->used_glyphs++;
732 for (i = 0; i < f->maxascii; i++) {
733 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
735 f->ascii2glyph[i] = -1;
741 f->maxascii = max_unicode;
742 f->numchars = max_glyph;
747 void swf_FontSort(SWFFONT * font)
755 newplace = rfx_alloc(sizeof(int) * font->numchars);
757 for (i = 0; i < font->numchars; i++) {
760 for (i = 0; i < font->numchars; i++)
761 for (j = 0; j < i; j++) {
762 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
771 n1 = font->glyph2ascii[i];
772 n2 = font->glyph2ascii[j];
773 font->glyph2ascii[j] = n1;
774 font->glyph2ascii[i] = n2;
779 if (font->glyphnames) {
780 c1 = font->glyphnames[i];
781 c2 = font->glyphnames[j];
782 font->glyphnames[j] = c1;
783 font->glyphnames[i] = c2;
786 r1 = font->layout->bounds[i];
787 r2 = font->layout->bounds[j];
788 font->layout->bounds[j] = r1;
789 font->layout->bounds[i] = r2;
793 newpos = rfx_alloc(sizeof(int) * font->numchars);
794 for (i = 0; i < font->numchars; i++) {
795 newpos[newplace[i]] = i;
797 for (i = 0; i < font->maxascii; i++) {
798 if (font->ascii2glyph[i] >= 0)
799 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
806 void swf_FontPrepareForEditText(SWFFONT * font)
809 swf_FontCreateLayout(font);
813 int swf_FontInitUsage(SWFFONT * f)
818 fprintf(stderr, "Usage initialized twice");
821 f->use = rfx_alloc(sizeof(FONTUSAGE));
822 f->use->is_reduced = 0;
823 f->use->chars = rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
827 void swf_FontClearUsage(SWFFONT * f)
831 rfx_free(f->use->chars); f->use->chars = 0;
832 rfx_free(f->use); f->use = 0;
835 int swf_FontUse(SWFFONT * f, U8 * s)
840 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
841 swf_FontUseGlyph(f, f->ascii2glyph[*s]);
847 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
854 ascii = readUTF8char(&s);
855 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
856 swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
861 int swf_FontUseAll(SWFFONT* f)
866 swf_FontInitUsage(f);
867 for (i = 0; i < f->numchars; i++)
868 f->use->chars[i] = 1;
869 f->use->used_glyphs = f->numchars;
873 int swf_FontUseGlyph(SWFFONT * f, int glyph)
876 swf_FontInitUsage(f);
877 if(glyph < 0 || glyph >= f->numchars)
879 if(!f->use->chars[glyph])
880 f->use->used_glyphs++;
881 f->use->chars[glyph] = 1;
885 int swf_FontSetDefine(TAG * t, SWFFONT * f)
887 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
892 swf_ResetWriteBits(t);
893 swf_SetU16(t, f->id);
897 for (i = 0; i < f->numchars; i++)
898 if (f->glyph[i].shape) {
900 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
903 for (i = 0; i < j; i++)
904 swf_SetU16(t, ofs[i] + j * 2);
906 fprintf(stderr, "rfxswf: warning: Font is empty\n");
910 for (i = 0; i < f->numchars; i++)
911 if (f->glyph[i].shape)
912 swf_SetSimpleShape(t, f->glyph[i].shape);
914 swf_ResetWriteBits(t);
919 static inline int fontSize(SWFFONT * font)
923 for (t = 0; t < font->numchars; t++) {
925 if(font->glyph[t].shape)
926 l = (font->glyph[t].shape->bitlen + 7) / 8;
931 return size + (font->numchars + 1) * 2;
934 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
940 swf_SetU16(tag, f->id);
942 if (f->layout) flags |= 128; // haslayout
943 if (f->numchars > 256)
944 flags |= 4; // widecodes
945 if (f->style & FONT_STYLE_BOLD)
947 if (f->style & FONT_STYLE_ITALIC)
948 flags |= 2; // italic
949 if (f->maxascii >= 256)
950 flags |= 4; //wide codecs
951 if (fontSize(f) > 65535)
952 flags |= 8; //wide offsets
953 flags |= 8 | 4; //FIXME: the above check doesn't work
955 if (f->encoding & FONT_ENCODING_ANSI)
957 if (f->encoding & FONT_ENCODING_UNICODE)
958 flags |= 32; // unicode
959 if (f->encoding & FONT_ENCODING_SHIFTJIS)
960 flags |= 64; // shiftjis
962 swf_SetU8(tag, flags);
963 swf_SetU8(tag, 0); //reserved flags
966 swf_SetU8(tag, strlen(f->name));
967 swf_SetBlock(tag, f->name, strlen(f->name));
969 /* font name (="") */
972 /* number of glyphs */
973 swf_SetU16(tag, f->numchars);
974 /* font offset table */
976 for (t = 0; t <= f->numchars; t++) {
978 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
980 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
983 for (t = 0; t <= f->numchars; t++) {
985 tag->data[pos + t * 4] = (tag->len - pos);
986 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
987 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
988 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
990 if (tag->len - pos > 65535) {
991 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
994 tag->data[pos + t * 2] = (tag->len - pos);
995 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
997 if (t < f->numchars) {
998 if(f->glyph[t].shape) {
999 swf_SetSimpleShape(tag, f->glyph[t].shape);
1001 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1007 /* font code table */
1008 for (t = 0; t < f->numchars; t++) {
1009 if (flags & 4) { /* wide codes */
1010 if(f->glyph2ascii[t]) {
1011 swf_SetU16(tag, f->glyph2ascii[t]);
1016 if(f->glyph2ascii[t]) {
1017 swf_SetU8(tag, f->glyph2ascii[t]);
1025 swf_SetU16(tag, f->layout->ascent);
1026 swf_SetU16(tag, f->layout->descent);
1027 swf_SetU16(tag, f->layout->leading);
1028 for (t = 0; t < f->numchars; t++)
1029 swf_SetU16(tag, f->glyph[t].advance);
1030 for (t = 0; t < f->numchars; t++) {
1031 swf_ResetWriteBits(tag);
1032 swf_SetRect(tag, &f->layout->bounds[t]);
1034 swf_SetU16(tag, f->layout->kerningcount);
1035 for (t = 0; t < f->layout->kerningcount; t++) {
1036 if (flags & 4) { /* wide codes */
1037 swf_SetU16(tag, f->layout->kerning[t].char1);
1038 swf_SetU16(tag, f->layout->kerning[t].char2);
1040 swf_SetU8(tag, f->layout->kerning[t].char1);
1041 swf_SetU8(tag, f->layout->kerning[t].char2);
1043 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1049 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1051 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1052 f->layout->ascent = ascent;
1053 f->layout->descent = descent;
1054 f->layout->leading = leading;
1055 f->layout->kerningcount = 0;
1056 f->layout->kerning = 0;
1057 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1060 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1067 swf_ResetWriteBits(t);
1068 swf_SetU16(t, f->id);
1069 l = f->name ? strlen(f->name) : 0;
1074 swf_SetBlock(t, f->name, l);
1075 if (f->numchars >= 256)
1078 if (f->style & FONT_STYLE_BOLD)
1080 if (f->style & FONT_STYLE_ITALIC)
1082 if (f->style & FONT_ENCODING_ANSI)
1084 if (f->style & FONT_ENCODING_SHIFTJIS)
1086 if (f->style & FONT_ENCODING_UNICODE)
1089 swf_SetU8(t, (flags & 0xfe) | wide);
1091 for (i = 0; i < f->numchars; i++) {
1092 if (f->glyph[i].shape) {
1093 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1094 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1101 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1103 int id = swf_GetTagID(t);
1104 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1105 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1111 void swf_FontFree(SWFFONT * f)
1119 for (i = 0; i < f->numchars; i++)
1120 if (f->glyph[i].shape)
1122 swf_ShapeFree(f->glyph[i].shape);
1123 f->glyph[i].shape = NULL;
1130 rfx_free(f->ascii2glyph);
1131 f->ascii2glyph = NULL;
1135 rfx_free(f->glyph2ascii);
1136 f->glyph2ascii = NULL;
1140 font_freeglyphnames(f);
1146 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1152 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1153 | (dy ? TF_HASYOFFSET : 0);
1155 swf_SetU8(t, flags);
1157 swf_SetU16(t, font->id);
1159 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1160 swf_SetRGBA(t, color);
1162 swf_SetRGB(t, color);
1165 if(dx != SET_TO_ZERO) {
1166 if(dx>32767 || dx<-32768)
1167 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1174 if(dy != SET_TO_ZERO) {
1175 if(dy>32767 || dy<-32768)
1176 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1183 swf_SetU16(t, size);
1188 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1192 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1196 if (!strcmp(encoding, "UTF8"))
1198 else if (!strcmp(encoding, "iso-8859-1"))
1201 fprintf(stderr, "Unknown encoding: %s", encoding);
1209 c = readUTF8char(&s);
1211 if (c < font->maxascii)
1212 glyph = font->ascii2glyph[c];
1214 g = swf_CountUBits(glyph, g);
1215 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1226 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1231 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1234 if (!strcmp(encoding, "UTF8"))
1236 else if (!strcmp(encoding, "iso-8859-1"))
1239 fprintf(stderr, "Unknown encoding: %s", encoding);
1242 swf_SetU8(t, l); //placeholder
1250 c = readUTF8char(&s);
1252 if (c < font->maxascii)
1253 g = font->ascii2glyph[c];
1255 swf_SetBits(t, g, gbits);
1256 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1258 /* We split into 127 characters per text field.
1259 We could do 255, by the (formerly wrong) flash specification,
1260 but some SWF parsing code out there still assumes that char blocks
1261 are at max 127 characters, and it would save only a few bits.
1268 PUT8(&t->data[pos], l);
1270 swf_ResetWriteBits(t);
1274 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1276 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1279 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1281 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1284 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1286 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1289 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1291 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1294 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1301 if (*s < font->maxascii)
1302 g = font->ascii2glyph[*s];
1304 res += font->glyph[g].advance / 20;
1308 res = (res * scale) / 100;
1313 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1320 int c = readUTF8char(&s);
1321 if(c==13 || c==10) {
1326 ypos+=font->layout->leading;
1329 if (c < font->maxascii) {
1330 int g = font->ascii2glyph[c];
1332 SRECT rn = font->layout->bounds[g];
1333 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1334 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1335 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1336 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1337 swf_ExpandRect2(&r, &rn);
1338 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1346 SWFFONT *swf_ReadFont(char *filename)
1352 f = open(filename, O_RDONLY|O_BINARY);
1354 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1355 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1361 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1368 void swf_WriteFont(SWFFONT * font, char *filename)
1375 int useDefineFont2 = 0;
1376 int storeGlyphNames = 1;
1379 useDefineFont2 = 1; /* the only thing new in definefont2
1380 is layout information. */
1382 font->id = WRITEFONTID; //"FN"
1384 memset(&swf, 0x00, sizeof(SWF));
1386 swf.fileVersion = 4;
1387 swf.frameRate = 0x4000;
1389 /* if we use DefineFont1 to store the characters,
1390 we have to build a textfield to store the
1391 advance values. While at it, we can also
1392 make the whole .swf viewable */
1394 /* we now always create viewable swfs, even if we
1395 did use definefont2 -mk */
1396 t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1401 swf_SetRGB(t, &rgb);
1402 if (!useDefineFont2) {
1403 t = swf_InsertTag(t, ST_DEFINEFONT);
1404 swf_FontSetDefine(t, font);
1405 t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1406 swf_FontSetInfo(t, font);
1408 t = swf_InsertTag(t, ST_DEFINEFONT2);
1409 swf_FontSetDefine2(t, font);
1412 if (storeGlyphNames && font->glyphnames) {
1414 t = swf_InsertTag(t, ST_GLYPHNAMES);
1415 swf_SetU16(t, WRITEFONTID);
1416 swf_SetU16(t, font->numchars);
1417 for (c = 0; c < font->numchars; c++) {
1418 if (font->glyphnames[c])
1419 swf_SetString(t, font->glyphnames[c]);
1421 swf_SetString(t, "");
1425 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1427 int textscale = 400;
1434 int range = font->maxascii;
1437 if (useDefineFont2 && range > 256) {
1441 for (s = 0; s < range; s++) {
1442 int g = font->ascii2glyph[s];
1444 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1445 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1449 if ((s & 15) == 0) {
1456 ymax = ypos * textscale * 2;
1458 swf.movieSize.xmax = xmax * 20;
1459 swf.movieSize.ymax = ymax;
1461 t = swf_InsertTag(t, ST_DEFINETEXT);
1463 swf_SetU16(t, font->id + 1); // ID
1467 r.xmax = swf.movieSize.xmax;
1468 r.ymax = swf.movieSize.ymax;
1472 swf_SetMatrix(t, NULL);
1474 abits = swf_CountBits(xmax * 16, 0);
1477 swf_SetU8(t, gbits);
1478 swf_SetU8(t, abits);
1484 for (y = 0; y < ((range + 15) / 16); y++) {
1485 int c = 0, lastx = -1;
1486 for (x = 0; x < 16; x++) {
1487 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1488 if (g >= 0 && font->glyph[g].shape) {
1495 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1496 for (x = 0; x < 16; x++) {
1497 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1498 if (g >= 0 && font->glyph[g].shape) {
1499 if (lastx != x * xmax) {
1500 swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1503 swf_SetBits(t, g, gbits);
1504 swf_SetBits(t, font->glyph[g].advance / 20, abits);
1505 lastx = x * xmax + (font->glyph[g].advance / 20);
1506 swf_ResetWriteBits(t);
1515 t = swf_InsertTag(t, ST_PLACEOBJECT2);
1517 swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1519 t = swf_InsertTag(t, ST_SHOWFRAME);
1523 t = swf_InsertTag(t, ST_END);
1525 f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1527 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1534 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1536 swf_SetRect(tag, &r);
1537 swf_ResetWriteBits(tag);
1539 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1541 flags |= ET_HASTEXT;
1543 flags |= ET_HASTEXTCOLOR;
1545 flags |= ET_HASMAXLENGTH;
1547 flags |= ET_HASFONT;
1549 flags |= ET_HASLAYOUT;
1551 swf_SetBits(tag, flags, 16);
1553 if (flags & ET_HASFONT) {
1554 swf_SetU16(tag, font); //font
1555 swf_SetU16(tag, height); //fontheight
1557 if (flags & ET_HASTEXTCOLOR) {
1558 swf_SetRGBA(tag, color);
1560 if (flags & ET_HASMAXLENGTH) {
1561 swf_SetU16(tag, maxlength); //maxlength
1563 if (flags & ET_HASLAYOUT) {
1564 swf_SetU8(tag, layout->align); //align
1565 swf_SetU16(tag, layout->leftmargin); //left margin
1566 swf_SetU16(tag, layout->rightmargin); //right margin
1567 swf_SetU16(tag, layout->indent); //indent
1568 swf_SetU16(tag, layout->leading); //leading
1570 swf_SetString(tag, variable);
1571 if (flags & ET_HASTEXT)
1572 swf_SetString(tag, text);
1575 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1579 U8 *utext = (U8 *) strdup(text);
1585 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1586 ystep = font->layout->leading;
1588 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1589 /* Hm, without layout information, we can't compute a bounding
1590 box. We could call swf_FontCreateLayout to create a layout,
1591 but the caller probably doesn't want us to mess up his font
1594 r.xmin = r.ymin = 0;
1595 r.xmax = r.ymax = 1024 * 20;
1599 swf_SetRect(tag, &r);
1601 /* The text matrix is pretty boring, as it doesn't apply to
1602 individual characters, but rather whole text objects (or
1603 at least whole char records- haven't tested).
1604 So it can't do anything which we can't already do with
1605 the placeobject tag we use for placing the text on the scene.
1607 swf_SetMatrix(tag, 0);
1609 swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1610 swf_SetU8(tag, gbits);
1611 swf_SetU8(tag, abits);
1617 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1620 while(*next && *next!=13 && *next!=10 && count<127) {
1621 readUTF8char(&next);
1624 if(next[0] == 13 || next[0] == 10) {
1629 if(next[0] == 13 && next[1] == 10)
1632 if(next[0] == 13 || next[0] == 10) {
1637 /* now set the text params- notice that a font size of
1638 1024 means that the glyphs will be displayed exactly
1639 as they would be in/with a defineshape. (Try to find
1640 *that* in the flash specs)
1642 /* set the actual text- notice that we just pass our scale
1643 parameter over, as TextSetCharRecord calculates with
1645 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1655 void swf_FontCreateLayout(SWFFONT * f)
1664 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1665 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1666 f->layout->ascent = -32767;
1667 f->layout->descent = -32767;
1669 for (t = 0; t < f->numchars; t++) {
1673 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1675 fprintf(stderr, "Shape parse error\n");
1678 bbox = swf_GetShapeBoundingBox(shape2);
1679 swf_Shape2Free(shape2);
1680 f->layout->bounds[t] = bbox;
1682 width = (bbox.xmax);
1684 /* The following is a heuristic- it may be that extractfont_DefineText
1685 has already found out some widths for individual characters (from the way
1686 they are used)- we now have to guess whether that width might be possible,
1687 which is the case if it isn't either much too big or much too small */
1688 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1689 f->glyph[t].advance = width;
1691 if (-bbox.ymin > f->layout->ascent)
1692 f->layout->ascent = bbox.ymin;
1693 if (bbox.ymax > f->layout->descent)
1694 f->layout->descent = bbox.ymax;
1698 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1700 U8 *s = (U8 *) text;
1706 U32 c = readUTF8char(&s);
1707 int g = font->ascii2glyph[c];
1708 shape = font->glyph[g].shape;
1709 if (((int) g) < 0) {
1710 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1713 shape2 = swf_ShapeToShape2(shape);
1716 if (l->type == moveTo) {
1718 to.x = l->x * size / 100.0 / 20.0 + advance;
1719 to.y = l->y * size / 100.0 / 20.0;
1720 draw->moveTo(draw, &to);
1721 } else if (l->type == lineTo) {
1723 to.x = l->x * size / 100.0 / 20.0 + advance;
1724 to.y = l->y * size / 100.0 / 20.0;
1725 draw->lineTo(draw, &to);
1726 } else if (l->type == splineTo) {
1728 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1729 mid.y = l->sy * size / 100.0 / 20.0;
1730 to.x = l->x * size / 100.0 / 20.0 + advance;
1731 to.y = l->y * size / 100.0 / 20.0;
1732 draw->splineTo(draw, &mid, &to);
1736 swf_Shape2Free(shape2);
1737 advance += font->glyph[g].advance * size / 100.0 / 20.0;