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 #define TF_TEXTCONTROL 0x80
26 #define TF_HASFONT 0x08
27 #define TF_HASCOLOR 0x04
28 #define TF_HASYOFFSET 0x02
29 #define TF_HASXOFFSET 0x01
31 #define FF_WIDECODES 0x01
33 #define FF_ITALIC 0x04
35 #define FF_SHIFTJIS 0x10
36 #define FF_UNICODE 0x20
39 #define FF2_ITALIC 0x02
40 #define FF2_WIDECODES 0x04
41 #define FF2_WIDEOFFSETS 0x08
43 #define FF2_UNICODE 0x20
44 #define FF2_SHIFTJIS 0x40
45 #define FF2_LAYOUT 0x80
47 int swf_FontIsItalic(SWFFONT * f) { return f->style&FONT_STYLE_ITALIC;}
48 int swf_FontIsBold(SWFFONT * f) { return f->style&FONT_STYLE_BOLD;}
50 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
52 int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*))
61 if (swf_GetTagID(t)==ST_DEFINEFONT2 || swf_GetTagID(t)==ST_DEFINEFONT)
72 if(swf_GetTagID(t) == ST_DEFINEFONT2 ||
73 swf_GetTagID(t) == ST_DEFINEFONTINFO ||
74 swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
91 int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t)
108 f->glyph = malloc(sizeof(SWFGLYPH)*n);
109 memset(f->glyph, 0, sizeof(SWFGLYPH)*n);
111 for (i=1;i<n;i++) swf_GetU16(t);
112 for (i=0;i<n;i++) swf_GetSimpleShape(t,&f->glyph[i].shape);
115 swf_RestoreTagPos(t);
119 int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t)
128 { U8 l = swf_GetU8(t);
132 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
133 too. However, they only add little information to what's already
134 inside the DefineFont2 tag */
138 if (f->name) free(f->name);
140 f->name = (U8*)malloc(l+1);
141 swf_GetBlock(t,f->name,l);
144 flags = swf_GetU8(t);
146 f->style |= FONT_STYLE_BOLD;
148 f->style |= FONT_STYLE_ITALIC;
150 f->encoding |= FONT_ENCODING_ANSI;
152 f->encoding |= FONT_ENCODING_SHIFTJIS;
154 f->encoding |= FONT_ENCODING_UNICODE;
156 if(t->id == ST_DEFINEFONTINFO2) {
157 f->language = swf_GetU8(t);
160 f->glyph2ascii = (U16*)malloc(sizeof(U16)*f->numchars);
162 for(i=0; i < f->numchars; i++) {
163 f->glyph2ascii[i] = ((flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t));
164 if(f->glyph2ascii[i] > maxcode)
165 maxcode = f->glyph2ascii[i];
170 f->maxascii = maxcode;
171 f->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
172 memset(f->ascii2glyph, -1, sizeof(int)*maxcode);
174 for(i = 0; i < f->numchars; i++)
175 f->ascii2glyph[f->glyph2ascii[i]] = i;
178 swf_RestoreTagPos(t);
182 int swf_FontExtract_GlyphNames(int id,SWFFONT * f,TAG * tag)
188 swf_SetTagPos(tag,0);
190 fid = swf_GetU16(tag);
194 int num = swf_GetU16(tag);
196 f->glyphnames = malloc(sizeof(char*)*num);
198 f->glyphnames[t] = strdup(swf_GetString(tag));
202 swf_RestoreTagPos(tag);
207 int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag)
212 U8 flags1,flags2,namelen;
214 swf_SetTagPos(tag,0);
216 fid = swf_GetU16(tag);
220 flags1 = swf_GetU8(tag);
221 flags2 = swf_GetU8(tag); //reserved flags
224 font->style |= FONT_STYLE_BOLD;
226 font->style |= FONT_STYLE_ITALIC;
228 font->encoding |= FONT_ENCODING_ANSI;
230 font->encoding |= FONT_ENCODING_UNICODE;
232 font->encoding |= FONT_ENCODING_SHIFTJIS;
234 namelen = swf_GetU8(tag);
235 font->name = (U8*)malloc(namelen+1);
236 font->name[namelen]=0;
237 swf_GetBlock(tag, font->name, namelen);
239 glyphcount = swf_GetU16(tag);
240 font->numchars = glyphcount;
242 font->glyph = (SWFGLYPH*)malloc(sizeof(SWFGLYPH)*glyphcount);
243 memset(font->glyph, 0, sizeof(SWFGLYPH)*glyphcount);
244 font->glyph2ascii = (U16*)malloc(sizeof(U16)*glyphcount);
245 memset(font->glyph2ascii, 0, sizeof(U16)*glyphcount);
247 if(flags1&8) { // wide offsets
248 for(t=0;t<glyphcount;t++)
249 swf_GetU32(tag); //offset[t]
251 if(glyphcount) /* this _if_ is not in the specs */
252 swf_GetU32(tag); // fontcodeoffset
254 for(t=0;t<glyphcount;t++)
255 swf_GetU16(tag); //offset[t]
257 if(glyphcount) /* this _if_ is not in the specs */
258 swf_GetU16(tag); // fontcodeoffset
260 for(t=0;t<glyphcount;t++)
261 swf_GetSimpleShape(tag,&(font->glyph[t].shape));
264 for(t=0;t<glyphcount;t++) {
266 if(flags1&4) // wide codes
267 code = swf_GetU16(tag);
269 code = swf_GetU8(tag);
270 font->glyph2ascii[t] = code;
277 font->maxascii = maxcode;
278 font->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
279 memset(font->ascii2glyph, -1, sizeof(int)*maxcode);
280 for(t=0;t<glyphcount;t++)
282 font->ascii2glyph[font->glyph2ascii[t]] = t;
285 if(flags1&128) { // has layout
287 font->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
288 font->layout->ascent=swf_GetU16(tag);
289 font->layout->descent=swf_GetU16(tag);
290 font->layout->leading=swf_GetU16(tag);
291 for(t=0;t<glyphcount;t++) {
292 S16 advance = swf_GetS16(tag);
293 font->glyph[t].advance = advance;
295 font->layout->bounds = malloc(glyphcount*sizeof(SRECT));
296 for(t=0;t<glyphcount;t++) {
297 swf_ResetReadBits(tag);
298 swf_GetRect(tag, &font->layout->bounds[t]);
301 kerningcount = swf_GetU16(tag);
302 font->layout->kerningcount = kerningcount;
304 font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount);
306 font->layout->kerning =
307 malloc(sizeof(*font->layout->kerning)* kerningcount);
308 for(t=0;t<kerningcount;t++)
310 if(flags1&4) { // wide codes
311 font->layout->kerning[t].char1 = swf_GetU16(tag);
312 font->layout->kerning[t].char2 = swf_GetU16(tag);
314 font->layout->kerning[t].char1 = swf_GetU8(tag);
315 font->layout->kerning[t].char2 = swf_GetU8(tag);
317 font->layout->kerning[t].adjustment = swf_GetS16(tag);
321 swf_RestoreTagPos(t);
326 #define FEDTJ_PRINT 0x01
327 #define FEDTJ_MODIFY 0x02
328 #define FEDTJ_CALLBACK 0x04
330 static int swf_FontExtract_DefineTextCallback(int id,SWFFONT * f,TAG * t,int jobs,
331 void(*callback)(void*self, int*chars, int*ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA* color), void*self)
341 memset(&color, 0, sizeof(color));
349 gbits = swf_GetU8(t);
350 abits = swf_GetU8(t);
355 flags = swf_GetU8(t);
359 if (flags&TF_TEXTCONTROL)
360 { if (flags&TF_HASFONT) fid = swf_GetU16(t);
361 if (flags&TF_HASCOLOR)
362 { color.r = swf_GetU8(t); // rgb
363 color.g = swf_GetU8(t);
364 color.b = swf_GetU8(t);
365 if (swf_GetTagID(t)==ST_DEFINETEXT2) color.a = swf_GetU8(t);
367 if (flags&TF_HASXOFFSET) x = swf_GetS16(t);
368 if (flags&TF_HASYOFFSET) y = swf_GetS16(t);
369 if (flags&TF_HASFONT) fontsize = swf_GetU16(t);
384 glyph = swf_GetBits(t,gbits);
385 adv = swf_GetBits(t,abits);
390 if (jobs&FEDTJ_PRINT) {
391 int code = f->glyph2ascii[glyph];
394 if (jobs&FEDTJ_MODIFY)
395 f->glyph[glyph].advance = adv;
397 if (jobs&FEDTJ_PRINT) {
405 if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n");
406 if (jobs&FEDTJ_CALLBACK)
407 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
412 swf_RestoreTagPos(t);
415 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)
417 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
420 int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)
422 return swf_FontExtract_DefineTextCallback(id,f,t,jobs,0,0);
425 int swf_FontExtract(SWF * swf,int id,SWFFONT * * font)
429 if ((!swf)||(!font)) return -1;
431 f = (SWFFONT *)malloc(sizeof(SWFFONT));
432 memset(f,0x00,sizeof(SWFFONT));
438 switch (swf_GetTagID(t))
439 { case ST_DEFINEFONT:
440 nid = swf_FontExtract_DefineFont(id,f,t);
444 nid = swf_FontExtract_DefineFont2(id,f,t);
447 case ST_DEFINEFONTINFO:
448 case ST_DEFINEFONTINFO2:
449 nid = swf_FontExtract_DefineFontInfo(id,f,t);
454 nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY);
458 nid = swf_FontExtract_GlyphNames(id,f,t);
472 int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
474 int swf_FontReduce(SWFFONT * f,FONTUSAGE * use)
476 if ((!f)||(!use)) return -1;
479 for (i=0;i<f->numchars;i++)
480 if (f->glyph[i].shape)
481 { if (f->glyph2ascii[i]<f->numchars&&
482 use->code[f->glyph2ascii[i]])
483 { f->ascii2glyph[f->glyph2ascii[i]] = j;
484 f->glyph2ascii[j] = f->glyph2ascii[i];
485 f->glyph[j] = f->glyph[i];
489 { swf_ShapeFree(f->glyph[i].shape);
490 f->ascii2glyph[f->glyph2ascii[i]] = -1;
491 f->glyph2ascii[i] = 0;
492 f->glyph[i].shape = NULL;
493 f->glyph[i].advance = 0;
495 } else f->ascii2glyph[f->glyph2ascii[i]] = -1;
502 int swf_FontInitUsage(SWFFONT* f, FONTUSAGE * use)
503 { if (!use) return -1;
504 use->code = malloc(sizeof(use->code[0])*f->numchars);
505 memset(use->code,0,sizeof(use->code[0])*f->numchars);
509 void swf_FontClearUsage(SWFFONT* f, FONTUSAGE * use)
514 int swf_FontUse(FONTUSAGE * use,U8 * s)
515 { if ((!use)||(!s)) return -1;
517 { use->code[s[0]] = 1;
523 int swf_FontSetDefine(TAG * t,SWFFONT * f)
524 { U16*ofs = (U16*)malloc(f->numchars*2);
527 if ((!t)||(!f)) return -1;
528 swf_ResetWriteBits(t);
532 for (i=0;i<f->numchars;i++)
533 if (f->glyph[i].shape)
535 p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
538 for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
540 fprintf(stderr, "rfxswf: warning: Font is empty\n");
544 for (i=0;i<f->numchars;i++)
545 if (f->glyph[i].shape)
546 swf_SetSimpleShape(t,f->glyph[i].shape);
548 swf_ResetWriteBits(t);
553 static inline int fontSize(SWFFONT*font)
557 for(t=0;t<font->numchars;t++) {
558 int l = (font->glyph[t].shape->bitlen+7)/8;
561 return size + (font->numchars+1)*2;
564 int swf_FontSetDefine2(TAG *tag, SWFFONT * f)
570 swf_SetU16(tag, f->id);
573 flags |= 128; // haslayout
575 flags |= 4; // widecodes
576 if(f->style & FONT_STYLE_BOLD)
578 if(f->style & FONT_STYLE_ITALIC)
579 flags |= 2; // italic
581 flags |= 4; //wide codecs
582 if(fontSize(f)>65535)
583 flags |= 8; //wide offsets
584 flags |= 8; //FIXME: the above check doesn't work
586 if(f->encoding & FONT_ENCODING_ANSI)
588 if(f->encoding & FONT_ENCODING_UNICODE)
589 flags |= 32; // unicode
590 if(f->encoding & FONT_ENCODING_SHIFTJIS)
591 flags |= 64; // shiftjis
593 swf_SetU8(tag, flags);
594 swf_SetU8(tag, 0); //reserved flags
597 swf_SetU8(tag, strlen(f->name));
598 swf_SetBlock(tag, f->name, strlen(f->name));
600 /* font name (="") */
601 swf_SetU8(tag, 0); /*placeholder*/
603 /* number of glyphs */
604 swf_SetU16(tag, f->numchars);
605 /* font offset table */
607 for(t=0;t<=f->numchars;t++)
610 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder*/
612 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder*/
615 for(t=0;t<=f->numchars;t++) {
617 tag->data[pos + t*4 ] = (tag->len-pos);
618 tag->data[pos + t*4 + 1] = (tag->len-pos) >> 8;
619 tag->data[pos + t*4 + 2] = (tag->len-pos) >> 16;
620 tag->data[pos + t*4 + 3] = (tag->len-pos) >> 24;
622 if(tag->len - pos > 65535) {
623 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
626 tag->data[pos + t*2 ] = (tag->len-pos);
627 tag->data[pos + t*2 + 1] = (tag->len-pos) >> 8;
630 swf_SetSimpleShape(tag, f->glyph[t].shape);
634 /* font code table */
635 if(flags & 4) /* wide codes */ {
636 for(t=0;t<f->numchars;t++) {
637 swf_SetU16(tag,f->glyph2ascii[t]);
640 for(t=0;t<f->numchars;t++)
641 swf_SetU8(tag,f->glyph2ascii[t]);
645 swf_SetU16(tag,f->layout->ascent);
646 swf_SetU16(tag,f->layout->descent);
647 swf_SetU16(tag,f->layout->leading);
648 for(t=0;t<f->numchars;t++)
649 swf_SetU16(tag,f->glyph[t].advance);
650 for(t=0;t<f->numchars;t++) {
651 swf_ResetWriteBits(tag);
652 swf_SetRect(tag,&f->layout->bounds[t]);
654 swf_SetU16(tag, f->layout->kerningcount);
655 for(t=0;t<f->layout->kerningcount;t++) {
656 if(flags & 4) /* wide codes */ {
657 swf_SetU16(tag,f->layout->kerning[t].char1);
658 swf_SetU16(tag,f->layout->kerning[t].char2);
660 swf_SetU8(tag,f->layout->kerning[t].char1);
661 swf_SetU8(tag,f->layout->kerning[t].char2);
663 swf_SetU16(tag,f->layout->kerning[t].adjustment);
669 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
671 f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
672 f->layout->ascent = ascent;
673 f->layout->descent = descent;
674 f->layout->leading = leading;
675 f->layout->kerningcount = 0;
676 f->layout->kerning = 0;
677 f->layout->bounds = (SRECT*)malloc(sizeof(SRECT)*f->numchars);
678 memset(f->layout->bounds, 0, sizeof(SRECT)*f->numchars);
681 int swf_FontSetInfo(TAG * t,SWFFONT * f)
685 if ((!t)||(!f)) return -1;
686 swf_ResetWriteBits(t);
688 l = f->name?strlen(f->name):0; if (l>255) l = 255;
691 swf_SetBlock(t,f->name,l);
695 if(f->style & FONT_STYLE_BOLD)
697 if(f->style & FONT_STYLE_ITALIC)
699 if(f->style & FONT_ENCODING_ANSI)
701 if(f->style & FONT_ENCODING_SHIFTJIS)
703 if(f->style & FONT_ENCODING_UNICODE)
706 swf_SetU8(t,(flags&0xfe)|wide);
708 for (i=0;i<f->numchars;i++) {
709 if (f->glyph[i].shape)
710 wide?swf_SetU16(t,f->glyph2ascii[i]):
711 swf_SetU8(t,f->glyph2ascii[i]);
717 int swf_TextPrintDefineText(TAG * t,SWFFONT * f)
718 { int id = swf_GetTagID(t);
719 if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
724 void swf_LayoutFree(SWFLAYOUT * l)
726 { if (l->kerning) free(l->kerning);
728 if (l->bounds) free(l->bounds);
734 void swf_FontFree(SWFFONT * f)
738 if (f->name) free(f->name);
739 if (f->layout) swf_LayoutFree(f->layout);
745 for (i=0;i<f->numchars;i++)
746 if (f->glyph[i].shape)
747 { swf_ShapeFree(f->glyph[i].shape);
748 f->glyph[i].shape = NULL;
754 free(f->ascii2glyph);
755 f->ascii2glyph = NULL;
758 free(f->glyph2ascii);
759 f->glyph2ascii = NULL;
763 for(t=0;t<f->numchars;t++) {
764 free(f->glyphnames[t]);
772 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,int dx,int dy)
776 flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
779 if (font) swf_SetU16(t,font->id);
781 { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
782 else swf_SetRGB(t,color);
784 if (dx) swf_SetS16(t,dx);
785 if (dy) swf_SetS16(t,dy);
786 if (font) swf_SetU16(t,size);
791 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)
793 if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1;
799 if(s[0] < font->maxascii)
800 glyph = font->ascii2glyph[s[0]];
802 g = swf_CountUBits(glyph,g);
803 a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a);
808 if (gbits) gbits[0] = (U8)g;
809 if (abits) abits[0] = (U8)a;
814 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
817 if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1;
820 swf_SetU8(t, l); //placeholder
825 if(s[i] < font->maxascii)
826 g = font->ascii2glyph[s[i]];
828 swf_SetBits(t,g,gbits);
829 swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits);
836 PUT8(&t->data[pos], l);
838 swf_ResetWriteBits(t);
842 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
849 if(*s < font->maxascii)
850 g = font->ascii2glyph[*s];
852 res += font->glyph[g].advance;
855 if (scale) res = (res*scale)/100;
860 SWFFONT* swf_ReadFont(char* filename)
866 f = open(filename,O_RDONLY);
868 if (f<0 || swf_ReadSWF(f,&swf)<0)
869 { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
876 if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
883 void swf_WriteFont(SWFFONT*font, char* filename)
889 int useDefineFont2 = 0;
890 int storeGlyphNames = 1;
893 useDefineFont2 = 1; /* the only thing new in definefont2
894 is layout information. */
896 font->id = WRITEFONTID; //"FN"
898 memset(&swf,0x00,sizeof(SWF));
901 swf.frameRate = 0x4000;
903 /* if we use DefineFont1 to store the characters,
904 we have to build a textfield to store the
905 advance values. While at it, we can also
906 make the whole .swf viewable */
908 /* we now always create viewable swfs, even if we
909 did use definefont2 -mk*/
910 t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
916 if(!useDefineFont2) {
917 t = swf_InsertTag(t,ST_DEFINEFONT);
918 swf_FontSetDefine(t,font);
919 t = swf_InsertTag(t,ST_DEFINEFONTINFO);
920 swf_FontSetInfo(t,font);
922 t = swf_InsertTag(t,ST_DEFINEFONT2);
923 swf_FontSetDefine2(t,font);
926 if(storeGlyphNames && font->glyphnames)
929 t = swf_InsertTag(t,ST_GLYPHNAMES);
930 swf_SetU16(t, font->id);
931 swf_SetU16(t, font->numchars);
932 for(c=0;c<font->numchars;c++) {
933 swf_SetString(t, font->glyphnames[c]);
937 if(1) //neccessary only for df1, but pretty to look at anyhow, so do it always
948 for(s=0;s<font->maxascii;s++)
950 int g = font->ascii2glyph[s];
952 if(font->glyph[g].advance*textscale/64 > xmax) {
953 xmax = font->glyph[g].advance*textscale/64;
964 ymax = ypos*textscale*2;
966 swf.movieSize.xmax = xmax*20;
967 swf.movieSize.ymax = ymax;
969 t = swf_InsertTag(t,ST_DEFINETEXT);
971 swf_SetU16(t,font->id+1); // ID
975 r.xmax = swf.movieSize.xmax;
976 r.ymax = swf.movieSize.ymax;
980 swf_SetMatrix(t,NULL);
982 abits = swf_CountBits(xmax*16, 0);
992 for(y=0;y<((font->maxascii+15)/16);y++)
996 int g = (y*16+x<font->maxascii)?font->ascii2glyph[y*16+x]:-1;
997 if(g>=0 && font->glyph[g].shape) {
1004 swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*ypos*2);
1007 int g = (y*16+x<font->maxascii)?font->ascii2glyph[y*16+x]:-1;
1008 if(g>=0 && font->glyph[g].shape) {
1009 if(lastx != x*xmax) {
1010 swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
1013 swf_SetBits(t, g, gbits);
1014 swf_SetBits(t, font->glyph[g].advance, abits);
1015 lastx = x*xmax+font->glyph[g].advance;
1016 swf_ResetWriteBits(t);
1025 t = swf_InsertTag(t,ST_PLACEOBJECT2);
1027 swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
1029 t = swf_InsertTag(t,ST_SHOWFRAME);
1033 t = swf_InsertTag(t,ST_END);
1035 f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
1036 if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
1043 void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color,
1044 int maxlength, U16 font, U16 height, EditTextLayout*layout, char*variable)
1046 swf_SetRect(tag,&r);
1047 swf_ResetWriteBits(tag);
1049 flags &= ~(ET_HASTEXT|ET_HASTEXTCOLOR|ET_HASMAXLENGTH|ET_HASFONT|ET_HASLAYOUT);
1050 if(text) flags |= ET_HASTEXT;
1051 if(color) flags |= ET_HASTEXTCOLOR;
1052 if(maxlength) flags |= ET_HASMAXLENGTH;
1053 if(font) flags |= ET_HASFONT;
1054 if(layout) flags |= ET_HASLAYOUT;
1056 swf_SetBits(tag, flags, 16);
1058 if(flags & ET_HASFONT) {
1059 swf_SetU16(tag, font); //font
1060 swf_SetU16(tag, height); //fontheight
1062 if(flags & ET_HASTEXTCOLOR) {
1063 swf_SetRGBA(tag, color);
1065 if(flags & ET_HASMAXLENGTH) {
1066 swf_SetU16(tag, maxlength); //maxlength
1068 if(flags & ET_HASLAYOUT) {
1069 swf_SetU8(tag,layout->align); //align
1070 swf_SetU16(tag,layout->leftmargin); //left margin
1071 swf_SetU16(tag,layout->rightmargin); //right margin
1072 swf_SetU16(tag,layout->indent); //indent
1073 swf_SetU16(tag,layout->leading); //leading
1075 swf_SetString(tag, variable);
1076 if(flags & ET_HASTEXT)
1077 swf_SetString(tag,text);
1080 SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale)
1089 if(*c < font->maxascii) {
1090 int g = font->ascii2glyph[*c];
1092 SRECT rn = font->layout->bounds[g];
1093 rn.xmin = (rn.xmin * scale)/100 + pos;
1094 rn.xmax = (rn.xmax * scale)/100 + pos;
1095 rn.ymin = (rn.ymin * scale)/100;
1096 rn.ymax = (rn.ymax * scale)/100;
1097 swf_ExpandRect2(&r, &rn);
1098 pos += (font->glyph[g].advance*scale*20)/100;
1104 /* Hm, without layout information, we can't compute a bounding
1105 box. We could call swf_FontCreateLayout to create a layout,
1106 but the caller probably doesn't want us to mess up his font
1109 r.xmin = r.ymin = 0;
1110 r.xmax = r.ymax = 1024*20;
1113 swf_SetRect(tag,&r);
1114 swf_SetMatrix(tag,NULL);
1115 swf_TextCountBits(font,text,scale*20,&gbits,&abits);
1116 swf_SetU8(tag,gbits);
1117 swf_SetU8(tag,abits);
1119 /* now set the text params- notice that a font size of
1120 1024 means that the glyphs will be displayed exactly
1121 as they would be in/with a defineshape. (Try to find
1122 *that* in the flash specs)
1124 swf_TextSetInfoRecord(tag,font,(scale*1024)/100,rgb,0,0); //scale
1126 /* set the actual text- notice that we just pass our scale
1127 parameter over, as TextSetCharRecord calculates with
1129 swf_TextSetCharRecord(tag,font,text,scale*20,gbits,abits);
1135 void swf_FontCreateLayout(SWFFONT*f)
1144 f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
1145 memset(f->layout, 0, sizeof(SWFLAYOUT));
1146 f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT));
1147 f->layout->ascent = -32767;
1148 f->layout->descent = -32767;
1150 for(t=0;t<f->numchars;t++) {
1154 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1156 fprintf(stderr, "Shape parse error\n");exit(1);
1158 bbox = swf_GetShapeBoundingBox(shape2);
1159 swf_Shape2Free(shape2);
1160 f->layout->bounds[t] = bbox;
1162 //width = (bbox.xmax - bbox.xmin)/20;
1163 width = (bbox.xmax)/20;
1165 /* The following is a heuristic- it may be that extractfont_DefineText
1166 has already found out some widths for individual characters (from the way
1167 they are used)- we now have to guess whether that width might be possible,
1168 which is the case if it isn't either much too big or much too small */
1169 if(width > f->glyph[t].advance*3/2 ||
1170 width*2 < f->glyph[t].advance)
1171 f->glyph[t].advance = width;
1173 if(-bbox.ymin > f->layout->ascent)
1174 f->layout->ascent = bbox.ymin;
1175 if(bbox.ymax > f->layout->descent)
1176 f->layout->descent = bbox.ymax;
1180 static U32 readUTF8char(char**text)
1183 if(!(*(*text) & 0x80))
1184 return *((*text)++);
1186 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
1187 if(((*text)[0] & 0xe0) == 0xc0 && (*text)[1])
1189 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
1193 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
1194 if(((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2])
1196 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
1200 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
1201 if(((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2] && (*text)[3] )
1203 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f)<<6 | ((*text)[3] & 0x3f);
1207 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
1208 if(((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4])
1210 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f)<<12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
1214 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
1215 if(((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4] && (*text)[5])
1217 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;
1221 return *((*text)++);
1224 void swf_DrawText(drawer_t*draw, SWFFONT*font, char*text)
1232 U32 c = readUTF8char(&s);
1233 int g = font->ascii2glyph[c];
1234 shape = font->glyph[g].shape;
1235 shape2 = swf_ShapeToShape2(shape);
1238 if(l->type == moveTo) {
1240 to.x = l->x/20.0+advance;
1242 draw->moveTo(draw, &to);
1243 } else if(l->type == lineTo) {
1245 to.x = l->x/20.0+advance;
1247 draw->lineTo(draw, &to);
1248 } else if(l->type == splineTo) {
1250 mid.x = l->sx/20.0+advance;
1252 to.x = l->x/20.0+advance;
1254 draw->splineTo(draw, &mid, &to);
1258 swf_Shape2Free(shape2);
1259 advance += font->glyph[g].advance;