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])
34 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
38 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
39 if(((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2])
41 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
45 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
46 if(((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2] && (*text)[3] )
48 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f)<<6 | ((*text)[3] & 0x3f);
52 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
53 if(((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4])
55 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f)<<12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
59 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
60 if(((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4] && (*text)[5])
62 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 | ((*text)[2] & 0x3f)<<18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
69 #define TF_TEXTCONTROL 0x80
70 #define TF_HASFONT 0x08
71 #define TF_HASCOLOR 0x04
72 #define TF_HASYOFFSET 0x02
73 #define TF_HASXOFFSET 0x01
75 #define FF_WIDECODES 0x01
77 #define FF_ITALIC 0x04
79 #define FF_SHIFTJIS 0x10
80 #define FF_UNICODE 0x20
83 #define FF2_ITALIC 0x02
84 #define FF2_WIDECODES 0x04
85 #define FF2_WIDEOFFSETS 0x08
87 #define FF2_UNICODE 0x20
88 #define FF2_SHIFTJIS 0x40
89 #define FF2_LAYOUT 0x80
91 int swf_FontIsItalic(SWFFONT * f) { return f->style&FONT_STYLE_ITALIC;}
92 int swf_FontIsBold(SWFFONT * f) { return f->style&FONT_STYLE_BOLD;}
94 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
96 int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*))
105 if (swf_GetTagID(t)==ST_DEFINEFONT2 || swf_GetTagID(t)==ST_DEFINEFONT)
116 if(swf_GetTagID(t) == ST_DEFINEFONT2 ||
117 swf_GetTagID(t) == ST_DEFINEFONTINFO ||
118 swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
125 (FontCallback)(id,s);
127 swf_RestoreTagPos(t);
135 int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t)
141 if ((!id)||(id==fid))
152 f->glyph = malloc(sizeof(SWFGLYPH)*n);
153 memset(f->glyph, 0, sizeof(SWFGLYPH)*n);
155 for (i=1;i<n;i++) swf_GetU16(t);
156 for (i=0;i<n;i++) swf_GetSimpleShape(t,&f->glyph[i].shape);
159 swf_RestoreTagPos(t);
163 int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t)
172 { U8 l = swf_GetU8(t);
176 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
177 too. However, they only add little information to what's already
178 inside the DefineFont2 tag */
182 if (f->name) free(f->name);
184 f->name = (U8*)malloc(l+1);
185 swf_GetBlock(t,f->name,l);
188 flags = swf_GetU8(t);
190 f->style |= FONT_STYLE_BOLD;
192 f->style |= FONT_STYLE_ITALIC;
194 f->encoding |= FONT_ENCODING_ANSI;
196 f->encoding |= FONT_ENCODING_SHIFTJIS;
198 f->encoding |= FONT_ENCODING_UNICODE;
200 if(t->id == ST_DEFINEFONTINFO2) {
201 f->language = swf_GetU8(t);
204 f->glyph2ascii = (U16*)malloc(sizeof(U16)*f->numchars);
206 for(i=0; i < f->numchars; i++) {
207 f->glyph2ascii[i] = ((flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t));
208 if(f->glyph2ascii[i] > maxcode)
209 maxcode = f->glyph2ascii[i];
214 f->maxascii = maxcode;
215 f->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
216 memset(f->ascii2glyph, -1, sizeof(int)*maxcode);
218 for(i = 0; i < f->numchars; i++)
219 f->ascii2glyph[f->glyph2ascii[i]] = i;
222 swf_RestoreTagPos(t);
226 int swf_FontExtract_GlyphNames(int id,SWFFONT * f,TAG * tag)
232 swf_SetTagPos(tag,0);
234 fid = swf_GetU16(tag);
238 int num = swf_GetU16(tag);
240 f->glyphnames = malloc(sizeof(char*)*num);
242 f->glyphnames[t] = strdup(swf_GetString(tag));
246 swf_RestoreTagPos(tag);
251 int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag)
256 U8 flags1,flags2,namelen;
258 swf_SetTagPos(tag,0);
260 fid = swf_GetU16(tag);
264 flags1 = swf_GetU8(tag);
265 flags2 = swf_GetU8(tag); //reserved flags
268 font->style |= FONT_STYLE_BOLD;
270 font->style |= FONT_STYLE_ITALIC;
272 font->encoding |= FONT_ENCODING_ANSI;
274 font->encoding |= FONT_ENCODING_UNICODE;
276 font->encoding |= FONT_ENCODING_SHIFTJIS;
278 namelen = swf_GetU8(tag);
279 font->name = (U8*)malloc(namelen+1);
280 font->name[namelen]=0;
281 swf_GetBlock(tag, font->name, namelen);
283 glyphcount = swf_GetU16(tag);
284 font->numchars = glyphcount;
286 font->glyph = (SWFGLYPH*)malloc(sizeof(SWFGLYPH)*glyphcount);
287 memset(font->glyph, 0, sizeof(SWFGLYPH)*glyphcount);
288 font->glyph2ascii = (U16*)malloc(sizeof(U16)*glyphcount);
289 memset(font->glyph2ascii, 0, sizeof(U16)*glyphcount);
291 if(flags1&8) { // wide offsets
292 for(t=0;t<glyphcount;t++)
293 swf_GetU32(tag); //offset[t]
295 if(glyphcount) /* this _if_ is not in the specs */
296 swf_GetU32(tag); // fontcodeoffset
298 for(t=0;t<glyphcount;t++)
299 swf_GetU16(tag); //offset[t]
301 if(glyphcount) /* this _if_ is not in the specs */
302 swf_GetU16(tag); // fontcodeoffset
304 for(t=0;t<glyphcount;t++)
305 swf_GetSimpleShape(tag,&(font->glyph[t].shape));
308 for(t=0;t<glyphcount;t++) {
310 if(flags1&4) // wide codes
311 code = swf_GetU16(tag);
313 code = swf_GetU8(tag);
314 font->glyph2ascii[t] = code;
321 font->maxascii = maxcode;
322 font->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
323 memset(font->ascii2glyph, -1, sizeof(int)*maxcode);
324 for(t=0;t<glyphcount;t++)
326 font->ascii2glyph[font->glyph2ascii[t]] = t;
329 if(flags1&128) { // has layout
331 font->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
332 font->layout->ascent=swf_GetU16(tag);
333 font->layout->descent=swf_GetU16(tag);
334 font->layout->leading=swf_GetU16(tag);
335 for(t=0;t<glyphcount;t++) {
336 S16 advance = swf_GetS16(tag);
337 font->glyph[t].advance = advance;
339 font->layout->bounds = malloc(glyphcount*sizeof(SRECT));
340 for(t=0;t<glyphcount;t++) {
341 swf_ResetReadBits(tag);
342 swf_GetRect(tag, &font->layout->bounds[t]);
345 kerningcount = swf_GetU16(tag);
346 font->layout->kerningcount = kerningcount;
348 font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount);
350 font->layout->kerning =
351 malloc(sizeof(*font->layout->kerning)* kerningcount);
352 for(t=0;t<kerningcount;t++)
354 if(flags1&4) { // wide codes
355 font->layout->kerning[t].char1 = swf_GetU16(tag);
356 font->layout->kerning[t].char2 = swf_GetU16(tag);
358 font->layout->kerning[t].char1 = swf_GetU8(tag);
359 font->layout->kerning[t].char2 = swf_GetU8(tag);
361 font->layout->kerning[t].adjustment = swf_GetS16(tag);
365 swf_RestoreTagPos(t);
370 #define FEDTJ_PRINT 0x01
371 #define FEDTJ_MODIFY 0x02
372 #define FEDTJ_CALLBACK 0x04
374 static int swf_FontExtract_DefineTextCallback(int id,SWFFONT * f,TAG * t,int jobs,
375 void(*callback)(void*self, int*chars, int*ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA* color), void*self)
385 memset(&color, 0, sizeof(color));
393 gbits = swf_GetU8(t);
394 abits = swf_GetU8(t);
399 flags = swf_GetU8(t);
403 if (flags&TF_TEXTCONTROL)
404 { if (flags&TF_HASFONT) fid = swf_GetU16(t);
405 if (flags&TF_HASCOLOR)
406 { color.r = swf_GetU8(t); // rgb
407 color.g = swf_GetU8(t);
408 color.b = swf_GetU8(t);
409 if (swf_GetTagID(t)==ST_DEFINETEXT2) color.a = swf_GetU8(t);
411 if (flags&TF_HASXOFFSET) x = swf_GetS16(t);
412 if (flags&TF_HASYOFFSET) y = swf_GetS16(t);
413 if (flags&TF_HASFONT) fontsize = swf_GetU16(t);
428 glyph = swf_GetBits(t,gbits);
429 adv = swf_GetBits(t,abits);
434 if (jobs&FEDTJ_PRINT) {
435 int code = f->glyph2ascii[glyph];
438 if (jobs&FEDTJ_MODIFY)
439 f->glyph[glyph].advance = adv*20; //?
441 if (jobs&FEDTJ_PRINT) {
449 if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n");
450 if (jobs&FEDTJ_CALLBACK)
451 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
456 swf_RestoreTagPos(t);
459 int swf_ParseDefineText(TAG * tag, void(*callback)(void*self, int*chars, int*ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA* color), void*self)
461 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
464 int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)
466 return swf_FontExtract_DefineTextCallback(id,f,t,jobs,0,0);
469 int swf_FontExtract(SWF * swf,int id,SWFFONT * * font)
473 if ((!swf)||(!font)) return -1;
475 f = (SWFFONT *)malloc(sizeof(SWFFONT));
476 memset(f,0x00,sizeof(SWFFONT));
482 switch (swf_GetTagID(t))
483 { case ST_DEFINEFONT:
484 nid = swf_FontExtract_DefineFont(id,f,t);
488 nid = swf_FontExtract_DefineFont2(id,f,t);
491 case ST_DEFINEFONTINFO:
492 case ST_DEFINEFONTINFO2:
493 nid = swf_FontExtract_DefineFontInfo(id,f,t);
498 nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY);
502 nid = swf_FontExtract_GlyphNames(id,f,t);
516 int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
518 int swf_FontReduce(SWFFONT * f,FONTUSAGE * use)
520 if ((!f)||(!use)) return -1;
522 /* TODO: layout, glyphnames */
524 for (i=0;i<f->numchars;i++)
525 if (f->glyph[i].shape)
526 { if (f->glyph2ascii[i]<f->maxascii&&
527 use->code[f->glyph2ascii[i]])
528 { f->ascii2glyph[f->glyph2ascii[i]] = j;
529 f->glyph2ascii[j] = f->glyph2ascii[i];
530 f->glyph[j] = f->glyph[i];
534 { swf_ShapeFree(f->glyph[i].shape);
535 f->ascii2glyph[f->glyph2ascii[i]] = -1;
536 f->glyph2ascii[i] = 0;
537 f->glyph[i].shape = NULL;
538 f->glyph[i].advance = 0;
540 } else f->ascii2glyph[f->glyph2ascii[i]] = -1;
546 void swf_FontSort(SWFFONT * font)
550 int* newplace = malloc(sizeof(int)*font->numchars);
553 for(i=0;i<font->numchars;i++) {
556 for(i=0;i<font->numchars;i++)
558 if(font->glyph2ascii[i] < font->glyph2ascii[j]) {
567 n1=font->glyph2ascii[i];
568 n2=font->glyph2ascii[j];
569 font->glyph2ascii[j] = n1;
570 font->glyph2ascii[i] = n2;
575 if(font->glyphnames) {
576 c1 = font->glyphnames[i];
577 c2 = font->glyphnames[j];
578 font->glyphnames[j] = c1;
579 font->glyphnames[i] = c2;
582 r1 = font->layout->bounds[i];
583 r2 = font->layout->bounds[j];
584 font->layout->bounds[j] = r1;
585 font->layout->bounds[i] = r2;
589 newpos = malloc(sizeof(int)*font->numchars);
590 for(i=0;i<font->numchars;i++) {
591 newpos[newplace[i]] = i;
593 for(i=0;i<font->maxascii;i++) {
594 if(font->ascii2glyph[i]>=0)
595 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
602 void swf_FontPrepareForEditText(SWFFONT * font)
605 swf_FontCreateLayout(font);
609 int swf_FontInitUsage(SWFFONT* f, FONTUSAGE * use)
610 { if (!use) return -1;
611 use->code = malloc(sizeof(use->code[0])*f->maxascii);
612 memset(use->code,0,sizeof(use->code[0])*f->maxascii);
616 void swf_FontClearUsage(SWFFONT* f, FONTUSAGE * use)
621 int swf_FontUse(SWFFONT*f, FONTUSAGE * use,U8 * s)
622 { if ((!use)||(!s)) return -1;
624 { use->code[s[0]] = 1;
630 int swf_FontSetDefine(TAG * t,SWFFONT * f)
631 { U16*ofs = (U16*)malloc(f->numchars*2);
634 if ((!t)||(!f)) return -1;
635 swf_ResetWriteBits(t);
639 for (i=0;i<f->numchars;i++)
640 if (f->glyph[i].shape)
642 p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
645 for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
647 fprintf(stderr, "rfxswf: warning: Font is empty\n");
651 for (i=0;i<f->numchars;i++)
652 if (f->glyph[i].shape)
653 swf_SetSimpleShape(t,f->glyph[i].shape);
655 swf_ResetWriteBits(t);
660 static inline int fontSize(SWFFONT*font)
664 for(t=0;t<font->numchars;t++) {
665 int l = (font->glyph[t].shape->bitlen+7)/8;
668 return size + (font->numchars+1)*2;
671 int swf_FontSetDefine2(TAG *tag, SWFFONT * f)
677 swf_SetU16(tag, f->id);
680 flags |= 128; // haslayout
682 flags |= 4; // widecodes
683 if(f->style & FONT_STYLE_BOLD)
685 if(f->style & FONT_STYLE_ITALIC)
686 flags |= 2; // italic
688 flags |= 4; //wide codecs
689 if(fontSize(f)>65535)
690 flags |= 8; //wide offsets
691 flags |= 8|4; //FIXME: the above check doesn't work
693 if(f->encoding & FONT_ENCODING_ANSI)
695 if(f->encoding & FONT_ENCODING_UNICODE)
696 flags |= 32; // unicode
697 if(f->encoding & FONT_ENCODING_SHIFTJIS)
698 flags |= 64; // shiftjis
700 swf_SetU8(tag, flags);
701 swf_SetU8(tag, 0); //reserved flags
704 swf_SetU8(tag, strlen(f->name));
705 swf_SetBlock(tag, f->name, strlen(f->name));
707 /* font name (="") */
708 swf_SetU8(tag, 0); /*placeholder*/
710 /* number of glyphs */
711 swf_SetU16(tag, f->numchars);
712 /* font offset table */
714 for(t=0;t<=f->numchars;t++)
717 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder*/
719 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder*/
722 for(t=0;t<=f->numchars;t++) {
724 tag->data[pos + t*4 ] = (tag->len-pos);
725 tag->data[pos + t*4 + 1] = (tag->len-pos) >> 8;
726 tag->data[pos + t*4 + 2] = (tag->len-pos) >> 16;
727 tag->data[pos + t*4 + 3] = (tag->len-pos) >> 24;
729 if(tag->len - pos > 65535) {
730 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
733 tag->data[pos + t*2 ] = (tag->len-pos);
734 tag->data[pos + t*2 + 1] = (tag->len-pos) >> 8;
737 swf_SetSimpleShape(tag, f->glyph[t].shape);
741 /* font code table */
742 if(flags & 4) /* wide codes */ {
743 for(t=0;t<f->numchars;t++) {
744 swf_SetU16(tag,f->glyph2ascii[t]);
747 for(t=0;t<f->numchars;t++)
748 swf_SetU8(tag,f->glyph2ascii[t]);
752 swf_SetU16(tag,f->layout->ascent);
753 swf_SetU16(tag,f->layout->descent);
754 swf_SetU16(tag,f->layout->leading);
755 for(t=0;t<f->numchars;t++)
756 swf_SetU16(tag,f->glyph[t].advance);
757 for(t=0;t<f->numchars;t++) {
758 swf_ResetWriteBits(tag);
759 swf_SetRect(tag,&f->layout->bounds[t]);
761 swf_SetU16(tag, f->layout->kerningcount);
762 for(t=0;t<f->layout->kerningcount;t++) {
763 if(flags & 4) /* wide codes */ {
764 swf_SetU16(tag,f->layout->kerning[t].char1);
765 swf_SetU16(tag,f->layout->kerning[t].char2);
767 swf_SetU8(tag,f->layout->kerning[t].char1);
768 swf_SetU8(tag,f->layout->kerning[t].char2);
770 swf_SetU16(tag,f->layout->kerning[t].adjustment);
776 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
778 f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
779 f->layout->ascent = ascent;
780 f->layout->descent = descent;
781 f->layout->leading = leading;
782 f->layout->kerningcount = 0;
783 f->layout->kerning = 0;
784 f->layout->bounds = (SRECT*)malloc(sizeof(SRECT)*f->numchars);
785 memset(f->layout->bounds, 0, sizeof(SRECT)*f->numchars);
788 int swf_FontSetInfo(TAG * t,SWFFONT * f)
792 if ((!t)||(!f)) return -1;
793 swf_ResetWriteBits(t);
795 l = f->name?strlen(f->name):0; if (l>255) l = 255;
798 swf_SetBlock(t,f->name,l);
802 if(f->style & FONT_STYLE_BOLD)
804 if(f->style & FONT_STYLE_ITALIC)
806 if(f->style & FONT_ENCODING_ANSI)
808 if(f->style & FONT_ENCODING_SHIFTJIS)
810 if(f->style & FONT_ENCODING_UNICODE)
813 swf_SetU8(t,(flags&0xfe)|wide);
815 for (i=0;i<f->numchars;i++) {
816 if (f->glyph[i].shape) {
817 int g2a = f->glyph2ascii[i];
818 wide?swf_SetU16(t,g2a):swf_SetU8(t,g2a);
825 int swf_TextPrintDefineText(TAG * t,SWFFONT * f)
826 { int id = swf_GetTagID(t);
827 if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
832 void swf_LayoutFree(SWFLAYOUT * l)
834 { if (l->kerning) free(l->kerning);
836 if (l->bounds) free(l->bounds);
842 void swf_FontFree(SWFFONT * f)
846 if (f->name) free(f->name);
847 if (f->layout) swf_LayoutFree(f->layout);
853 for (i=0;i<f->numchars;i++)
854 if (f->glyph[i].shape)
855 { swf_ShapeFree(f->glyph[i].shape);
856 f->glyph[i].shape = NULL;
862 free(f->ascii2glyph);
863 f->ascii2glyph = NULL;
866 free(f->glyph2ascii);
867 f->glyph2ascii = NULL;
871 for(t=0;t<f->numchars;t++) {
873 free(f->glyphnames[t]);
881 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,int dx,int dy)
885 flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
888 if (font) swf_SetU16(t,font->id);
890 { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
891 else swf_SetRGB(t,color);
893 if (dx) swf_SetS16(t,dx);
894 if (dy) swf_SetS16(t,dy);
895 if (font) swf_SetU16(t,size);
900 static int swf_TextCountBits2(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits, char*encoding)
903 if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1;
906 if(!strcmp(encoding, "UTF8")) utf8=1;
907 else if(!strcmp(encoding, "iso-8859-1")) utf8=0;
908 else fprintf(stderr, "Unknown encoding: %s", encoding);
915 else c = readUTF8char(&s);
917 if(c < font->maxascii)
918 glyph = font->ascii2glyph[c];
920 g = swf_CountUBits(glyph,g);
921 a = swf_CountBits(((((U32)font->glyph[glyph].advance)*scale)/20)/100,a);
925 if (gbits) gbits[0] = (U8)g;
926 if (abits) abits[0] = (U8)a;
930 static int swf_TextSetCharRecord2(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits, char*encoding)
934 if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1;
936 if(!strcmp(encoding, "UTF8")) utf8=1;
937 else if(!strcmp(encoding, "iso-8859-1")) utf8=0;
938 else fprintf(stderr, "Unknown encoding: %s", encoding);
941 swf_SetU8(t, l); //placeholder
948 else c = readUTF8char(&s);
950 if(c < font->maxascii)
951 g = font->ascii2glyph[c];
953 swf_SetBits(t,g,gbits);
954 swf_SetBits(t,((((U32)font->glyph[g].advance)*scale)/20)/100,abits);
961 PUT8(&t->data[pos], l);
963 swf_ResetWriteBits(t);
967 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) {
968 return swf_TextCountBits2(font,s,scale,gbits,abits,"iso-8859-1");
970 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) {
971 return swf_TextSetCharRecord2(t,font,s,scale,gbits,abits,"iso-8859-1");
973 int swf_TextCountBitsUTF8(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) {
974 return swf_TextCountBits2(font,s,scale,gbits,abits,"UTF8");
976 int swf_TextSetCharRecordUTF8(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) {
977 return swf_TextSetCharRecord2(t,font,s,scale,gbits,abits,"UTF8");
980 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
987 if(*s < font->maxascii)
988 g = font->ascii2glyph[*s];
990 res += font->glyph[g].advance/20;
993 if (scale) res = (res*scale)/100;
998 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font,U8 * s,int scale)
1004 int c = readUTF8char(&s);
1005 if(c < font->maxascii) {
1006 int g = font->ascii2glyph[c];
1008 SRECT rn = font->layout->bounds[g];
1009 rn.xmin = (rn.xmin * scale)/20/100 + pos;
1010 rn.xmax = (rn.xmax * scale)/20/100 + pos;
1011 rn.ymin = (rn.ymin * scale)/20/100;
1012 rn.ymax = (rn.ymax * scale)/20/100;
1013 swf_ExpandRect2(&r, &rn);
1014 pos += (font->glyph[g].advance*scale)/20/100;
1023 SWFFONT* swf_ReadFont(char* filename)
1029 f = open(filename,O_RDONLY);
1031 if (f<0 || swf_ReadSWF(f,&swf)<0)
1032 { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
1039 if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1046 void swf_WriteFont(SWFFONT*font, char* filename)
1052 int useDefineFont2 = 0;
1053 int storeGlyphNames = 1;
1056 useDefineFont2 = 1; /* the only thing new in definefont2
1057 is layout information. */
1059 font->id = WRITEFONTID; //"FN"
1061 memset(&swf,0x00,sizeof(SWF));
1063 swf.fileVersion = 4;
1064 swf.frameRate = 0x4000;
1066 /* if we use DefineFont1 to store the characters,
1067 we have to build a textfield to store the
1068 advance values. While at it, we can also
1069 make the whole .swf viewable */
1071 /* we now always create viewable swfs, even if we
1072 did use definefont2 -mk*/
1073 t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1079 if(!useDefineFont2) {
1080 t = swf_InsertTag(t,ST_DEFINEFONT);
1081 swf_FontSetDefine(t,font);
1082 t = swf_InsertTag(t,ST_DEFINEFONTINFO);
1083 swf_FontSetInfo(t,font);
1085 t = swf_InsertTag(t,ST_DEFINEFONT2);
1086 swf_FontSetDefine2(t,font);
1089 if(storeGlyphNames && font->glyphnames)
1092 t = swf_InsertTag(t,ST_GLYPHNAMES);
1093 swf_SetU16(t, WRITEFONTID);
1094 swf_SetU16(t, font->numchars);
1095 for(c=0;c<font->numchars;c++) {
1096 if(font->glyphnames[c])
1097 swf_SetString(t, font->glyphnames[c]);
1099 swf_SetString(t, "");
1103 if(1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1105 int textscale = 400;
1112 int range = font->maxascii;
1115 if(useDefineFont2 && range > 256) {
1119 for(s=0;s<range;s++)
1121 int g = font->ascii2glyph[s];
1123 if((font->glyph[g].advance*textscale/20)/64 > xmax) {
1124 xmax = (font->glyph[g].advance*textscale/20)/64;
1135 ymax = ypos*textscale*2;
1137 swf.movieSize.xmax = xmax*20;
1138 swf.movieSize.ymax = ymax;
1140 t = swf_InsertTag(t,ST_DEFINETEXT);
1142 swf_SetU16(t,font->id+1); // ID
1146 r.xmax = swf.movieSize.xmax;
1147 r.ymax = swf.movieSize.ymax;
1151 swf_SetMatrix(t,NULL);
1153 abits = swf_CountBits(xmax*16, 0);
1163 for(y=0;y<((range+15)/16);y++)
1167 int g = (y*16+x<range)?font->ascii2glyph[y*16+x]:-1;
1168 if(g>=0 && font->glyph[g].shape) {
1175 swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*ypos*2);
1178 int g = (y*16+x<range)?font->ascii2glyph[y*16+x]:-1;
1179 if(g>=0 && font->glyph[g].shape) {
1180 if(lastx != x*xmax) {
1181 swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
1184 swf_SetBits(t, g, gbits);
1185 swf_SetBits(t, font->glyph[g].advance/20, abits);
1186 lastx = x*xmax+(font->glyph[g].advance/20);
1187 swf_ResetWriteBits(t);
1196 t = swf_InsertTag(t,ST_PLACEOBJECT2);
1198 swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
1200 t = swf_InsertTag(t,ST_SHOWFRAME);
1204 t = swf_InsertTag(t,ST_END);
1206 f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
1207 if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
1214 void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color,
1215 int maxlength, U16 font, U16 height, EditTextLayout*layout, char*variable)
1217 swf_SetRect(tag,&r);
1218 swf_ResetWriteBits(tag);
1220 flags &= ~(ET_HASTEXT|ET_HASTEXTCOLOR|ET_HASMAXLENGTH|ET_HASFONT|ET_HASLAYOUT);
1221 if(text) flags |= ET_HASTEXT;
1222 if(color) flags |= ET_HASTEXTCOLOR;
1223 if(maxlength) flags |= ET_HASMAXLENGTH;
1224 if(font) flags |= ET_HASFONT;
1225 if(layout) flags |= ET_HASLAYOUT;
1227 swf_SetBits(tag, flags, 16);
1229 if(flags & ET_HASFONT) {
1230 swf_SetU16(tag, font); //font
1231 swf_SetU16(tag, height); //fontheight
1233 if(flags & ET_HASTEXTCOLOR) {
1234 swf_SetRGBA(tag, color);
1236 if(flags & ET_HASMAXLENGTH) {
1237 swf_SetU16(tag, maxlength); //maxlength
1239 if(flags & ET_HASLAYOUT) {
1240 swf_SetU8(tag,layout->align); //align
1241 swf_SetU16(tag,layout->leftmargin); //left margin
1242 swf_SetU16(tag,layout->rightmargin); //right margin
1243 swf_SetU16(tag,layout->indent); //indent
1244 swf_SetU16(tag,layout->leading); //leading
1246 swf_SetString(tag, variable);
1247 if(flags & ET_HASTEXT)
1248 swf_SetString(tag,text);
1251 SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale)
1258 r = swf_TextCalculateBBoxUTF8(font,text,scale*20);
1260 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1261 /* Hm, without layout information, we can't compute a bounding
1262 box. We could call swf_FontCreateLayout to create a layout,
1263 but the caller probably doesn't want us to mess up his font
1266 r.xmin = r.ymin = 0;
1267 r.xmax = r.ymax = 1024*20;
1270 swf_SetRect(tag,&r);
1272 /* The text matrix is pretty boring, as it doesn't apply to
1273 individual characters, but rather whole text objects (or
1274 at least whole char records- haven't tested).
1275 So it can't do anything which we can't already do with
1276 the placeobject tag we use for placing the text on the scene.
1278 swf_SetMatrix(tag,0);
1280 swf_TextCountBitsUTF8(font,text,scale*20,&gbits,&abits);
1281 swf_SetU8(tag,gbits);
1282 swf_SetU8(tag,abits);
1284 /* now set the text params- notice that a font size of
1285 1024 means that the glyphs will be displayed exactly
1286 as they would be in/with a defineshape. (Try to find
1287 *that* in the flash specs)
1289 swf_TextSetInfoRecord(tag,font,(scale*1024)/100,rgb,0,0); //scale
1291 /* set the actual text- notice that we just pass our scale
1292 parameter over, as TextSetCharRecord calculates with
1294 swf_TextSetCharRecordUTF8(tag,font,text,scale*20,gbits,abits);
1300 void swf_FontCreateLayout(SWFFONT*f)
1309 f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
1310 memset(f->layout, 0, sizeof(SWFLAYOUT));
1311 f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT));
1312 f->layout->ascent = -32767;
1313 f->layout->descent = -32767;
1315 for(t=0;t<f->numchars;t++) {
1319 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1321 fprintf(stderr, "Shape parse error\n");exit(1);
1323 bbox = swf_GetShapeBoundingBox(shape2);
1324 swf_Shape2Free(shape2);
1325 f->layout->bounds[t] = bbox;
1327 width = (bbox.xmax);
1329 /* The following is a heuristic- it may be that extractfont_DefineText
1330 has already found out some widths for individual characters (from the way
1331 they are used)- we now have to guess whether that width might be possible,
1332 which is the case if it isn't either much too big or much too small */
1333 if(width > f->glyph[t].advance*3/2 ||
1334 width < f->glyph[t].advance/2)
1335 f->glyph[t].advance = width;
1337 if(-bbox.ymin > f->layout->ascent)
1338 f->layout->ascent = bbox.ymin;
1339 if(bbox.ymax > f->layout->descent)
1340 f->layout->descent = bbox.ymax;
1344 void swf_DrawText(drawer_t*draw, SWFFONT*font, int size, char*text)
1352 U32 c = readUTF8char(&s);
1353 int g = font->ascii2glyph[c];
1354 shape = font->glyph[g].shape;
1356 fprintf(stderr, "No char %d in font %s\n", c, font->name?(char*)font->name:"?");
1359 shape2 = swf_ShapeToShape2(shape);
1362 if(l->type == moveTo) {
1364 to.x = l->x*size/100.0/20.0+advance;
1365 to.y = l->y*size/100.0/20.0;
1366 draw->moveTo(draw, &to);
1367 } else if(l->type == lineTo) {
1369 to.x = l->x*size/100.0/20.0+advance;
1370 to.y = l->y*size/100.0/20.0;
1371 draw->lineTo(draw, &to);
1372 } else if(l->type == splineTo) {
1374 mid.x = l->sx*size/100.0/20.0+advance;
1375 mid.y = l->sy*size/100.0/20.0;
1376 to.x = l->x*size/100.0/20.0+advance;
1377 to.y = l->y*size/100.0/20.0;
1378 draw->splineTo(draw, &mid, &to);
1382 swf_Shape2Free(shape2);
1383 advance += font->glyph[g].advance*size/100.0/20.0;