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
) (U16
, U8
*))
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
) (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
= malloc(sizeof(SWFGLYPH
) * n
);
161 memset(f
->glyph
, 0, sizeof(SWFGLYPH
) * n
);
163 for (i
= 1; i
< n
; i
++)
165 for (i
= 0; i
< n
; i
++)
166 swf_GetSimpleShape(t
, &f
->glyph
[i
].shape
);
169 swf_RestoreTagPos(t
);
173 int swf_FontExtract_DefineFontInfo(int id
, SWFFONT
* f
, TAG
* t
)
186 if (f
->version
> 1) {
187 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
188 too. However, they only add little information to what's already
189 inside the DefineFont2 tag */
196 f
->name
= (U8
*) malloc(l
+ 1);
197 swf_GetBlock(t
, f
->name
, l
);
200 flags
= swf_GetU8(t
);
202 f
->style
|= FONT_STYLE_BOLD
;
204 f
->style
|= FONT_STYLE_ITALIC
;
206 f
->encoding
|= FONT_ENCODING_ANSI
;
208 f
->encoding
|= FONT_ENCODING_SHIFTJIS
;
210 f
->encoding
|= FONT_ENCODING_UNICODE
;
212 if (t
->id
== ST_DEFINEFONTINFO2
) {
213 f
->language
= swf_GetU8(t
);
216 f
->glyph2ascii
= (U16
*) malloc(sizeof(U16
) * f
->numchars
);
218 for (i
= 0; i
< f
->numchars
; i
++) {
219 f
->glyph2ascii
[i
] = ((flags
& FF_WIDECODES
) ? swf_GetU16(t
) : swf_GetU8(t
));
220 if (f
->glyph2ascii
[i
] > maxcode
)
221 maxcode
= f
->glyph2ascii
[i
];
226 f
->maxascii
= maxcode
;
227 f
->ascii2glyph
= (int *) malloc(sizeof(int) * maxcode
);
228 memset(f
->ascii2glyph
, -1, sizeof(int) * maxcode
);
230 for (i
= 0; i
< f
->numchars
; i
++)
231 f
->ascii2glyph
[f
->glyph2ascii
[i
]] = i
;
234 swf_RestoreTagPos(t
);
238 int swf_FontExtract_GlyphNames(int id
, SWFFONT
* f
, TAG
* tag
)
244 swf_SetTagPos(tag
, 0);
246 fid
= swf_GetU16(tag
);
249 int num
= swf_GetU16(tag
);
251 f
->glyphnames
= malloc(sizeof(char *) * num
);
252 for (t
= 0; t
< num
; t
++) {
253 f
->glyphnames
[t
] = strdup(swf_GetString(tag
));
257 swf_RestoreTagPos(tag
);
262 int swf_FontExtract_DefineFont2(int id
, SWFFONT
* font
, TAG
* tag
)
267 U8 flags1
, flags2
, namelen
;
269 swf_SetTagPos(tag
, 0);
271 fid
= swf_GetU16(tag
);
275 flags1
= swf_GetU8(tag
);
276 flags2
= swf_GetU8(tag
); //reserved flags
279 font
->style
|= FONT_STYLE_BOLD
;
281 font
->style
|= FONT_STYLE_ITALIC
;
283 font
->encoding
|= FONT_ENCODING_ANSI
;
285 font
->encoding
|= FONT_ENCODING_UNICODE
;
287 font
->encoding
|= FONT_ENCODING_SHIFTJIS
;
289 namelen
= swf_GetU8(tag
);
290 font
->name
= (U8
*) malloc(namelen
+ 1);
291 font
->name
[namelen
] = 0;
292 swf_GetBlock(tag
, font
->name
, namelen
);
294 glyphcount
= swf_GetU16(tag
);
295 font
->numchars
= glyphcount
;
297 font
->glyph
= (SWFGLYPH
*) malloc(sizeof(SWFGLYPH
) * glyphcount
);
298 memset(font
->glyph
, 0, sizeof(SWFGLYPH
) * glyphcount
);
299 font
->glyph2ascii
= (U16
*) malloc(sizeof(U16
) * glyphcount
);
300 memset(font
->glyph2ascii
, 0, sizeof(U16
) * glyphcount
);
302 if (flags1
& 8) { // wide offsets
303 for (t
= 0; t
< glyphcount
; t
++)
304 swf_GetU32(tag
); //offset[t]
306 if (glyphcount
) /* this _if_ is not in the specs */
307 swf_GetU32(tag
); // fontcodeoffset
309 for (t
= 0; t
< glyphcount
; t
++)
310 swf_GetU16(tag
); //offset[t]
312 if (glyphcount
) /* this _if_ is not in the specs */
313 swf_GetU16(tag
); // fontcodeoffset
315 /* TODO: we should use the offset positions, not just
316 blindly read in shapes */
317 for (t
= 0; t
< glyphcount
; t
++)
318 swf_GetSimpleShape(tag
, &(font
->glyph
[t
].shape
));
321 for (t
= 0; t
< glyphcount
; t
++) {
323 if (flags1
& 4) // wide codes
324 code
= swf_GetU16(tag
);
326 code
= swf_GetU8(tag
);
327 font
->glyph2ascii
[t
] = code
;
334 font
->maxascii
= maxcode
;
335 font
->ascii2glyph
= (int *) malloc(sizeof(int) * maxcode
);
336 memset(font
->ascii2glyph
, -1, sizeof(int) * maxcode
);
337 for (t
= 0; t
< glyphcount
; t
++) {
338 font
->ascii2glyph
[font
->glyph2ascii
[t
]] = t
;
341 if (flags1
& 128) { // has layout
343 font
->layout
= (SWFLAYOUT
*) malloc(sizeof(SWFLAYOUT
));
344 font
->layout
->ascent
= swf_GetU16(tag
);
345 font
->layout
->descent
= swf_GetU16(tag
);
346 font
->layout
->leading
= swf_GetU16(tag
);
347 for (t
= 0; t
< glyphcount
; t
++) {
348 S16 advance
= swf_GetS16(tag
);
349 font
->glyph
[t
].advance
= advance
;
351 font
->layout
->bounds
= malloc(glyphcount
* sizeof(SRECT
));
352 for (t
= 0; t
< glyphcount
; t
++) {
353 swf_ResetReadBits(tag
);
354 swf_GetRect(tag
, &font
->layout
->bounds
[t
]);
357 kerningcount
= swf_GetU16(tag
);
358 font
->layout
->kerningcount
= kerningcount
;
360 font
->layout
->kerning
= (SWFKERNING
*) malloc(sizeof(SWFKERNING
) * kerningcount
);
362 font
->layout
->kerning
= malloc(sizeof(*font
->layout
->kerning
) * kerningcount
);
363 for (t
= 0; t
< kerningcount
; t
++) {
364 if (flags1
& 4) { // wide codes
365 font
->layout
->kerning
[t
].char1
= swf_GetU16(tag
);
366 font
->layout
->kerning
[t
].char2
= swf_GetU16(tag
);
368 font
->layout
->kerning
[t
].char1
= swf_GetU8(tag
);
369 font
->layout
->kerning
[t
].char2
= swf_GetU8(tag
);
371 font
->layout
->kerning
[t
].adjustment
= swf_GetS16(tag
);
375 swf_RestoreTagPos(t
);
380 #define FEDTJ_PRINT 0x01
381 #define FEDTJ_MODIFY 0x02
382 #define FEDTJ_CALLBACK 0x04
385 swf_FontExtract_DefineTextCallback(int id
, SWFFONT
* f
, TAG
* t
, int jobs
,
386 void (*callback
) (void *self
,
387 int *chars
, int *ypos
, int nr
, int fontid
, int fontsize
, int xstart
, int ystart
, RGBA
* color
), void *self
)
398 memset(&color
, 0, sizeof(color
));
405 swf_GetMatrix(t
, &m
);
406 gbits
= swf_GetU8(t
);
407 abits
= swf_GetU8(t
);
411 flags
= swf_GetU8(t
);
415 if (flags
& TF_TEXTCONTROL
) {
416 if (flags
& TF_HASFONT
)
418 if (flags
& TF_HASCOLOR
) {
419 color
.r
= swf_GetU8(t
); // rgb
420 color
.g
= swf_GetU8(t
);
421 color
.b
= swf_GetU8(t
);
422 if (swf_GetTagID(t
) == ST_DEFINETEXT2
)
423 color
.a
= swf_GetU8(t
);
425 if (flags
& TF_HASXOFFSET
)
427 if (flags
& TF_HASYOFFSET
)
429 if (flags
& TF_HASFONT
)
430 fontsize
= swf_GetU16(t
);
442 for (i
= 0; i
< num
; i
++) {
446 glyph
= swf_GetBits(t
, gbits
);
447 adv
= swf_GetBits(t
, abits
);
452 if (jobs
& FEDTJ_PRINT
) {
453 int code
= f
->glyph2ascii
[glyph
];
456 if (jobs
& FEDTJ_MODIFY
)
457 f
->glyph
[glyph
].advance
= adv
* 20; //?
459 if (jobs
& FEDTJ_PRINT
) {
467 if ((id
== fid
) && (jobs
& FEDTJ_PRINT
))
469 if (jobs
& FEDTJ_CALLBACK
)
470 callback(self
, buf
, advance
, num
, fid
, fontsize
, x
, y
, &color
);
475 swf_RestoreTagPos(t
);
479 int swf_ParseDefineText(TAG
* tag
,
480 void (*callback
) (void *self
, int *chars
, int *ypos
, int nr
, int fontid
, int fontsize
, int xstart
, int ystart
, RGBA
* color
), void *self
)
482 return swf_FontExtract_DefineTextCallback(-1, 0, tag
, FEDTJ_CALLBACK
, callback
, self
);
485 int swf_FontExtract_DefineText(int id
, SWFFONT
* f
, TAG
* t
, int jobs
)
487 return swf_FontExtract_DefineTextCallback(id
, f
, t
, jobs
, 0, 0);
490 int swf_FontExtract(SWF
* swf
, int id
, SWFFONT
* *font
)
495 if ((!swf
) || (!font
))
498 f
= (SWFFONT
*) malloc(sizeof(SWFFONT
));
499 memset(f
, 0x00, sizeof(SWFFONT
));
505 switch (swf_GetTagID(t
)) {
507 nid
= swf_FontExtract_DefineFont(id
, f
, t
);
511 nid
= swf_FontExtract_DefineFont2(id
, f
, t
);
514 case ST_DEFINEFONTINFO
:
515 case ST_DEFINEFONTINFO2
:
516 nid
= swf_FontExtract_DefineFontInfo(id
, f
, t
);
521 nid
= swf_FontExtract_DefineText(id
, f
, t
, f
->layout
? 0 : FEDTJ_MODIFY
);
525 nid
= swf_FontExtract_GlyphNames(id
, f
, t
);
540 int swf_FontSetID(SWFFONT
* f
, U16 id
)
548 void swf_LayoutFree(SWFLAYOUT
* l
)
562 static void font_freeglyphnames(SWFFONT
*f
)
566 for (t
= 0; t
< f
->numchars
; t
++) {
567 if (f
->glyphnames
[t
])
568 free(f
->glyphnames
[t
]);
575 static void font_freeusage(SWFFONT
*f
)
579 free(f
->use
->chars
);f
->use
->chars
= 0;
581 free(f
->use
); f
->use
= 0;
584 static void font_freelayout(SWFFONT
*f
)
587 swf_LayoutFree(f
->layout
);
591 static void font_freename(SWFFONT
*f
)
599 int swf_FontReduce(SWFFONT
* f
)
603 if ((!f
) || (!f
->use
) || f
->use
->is_reduced
)
608 for (i
= 0; i
< f
->numchars
; i
++) {
609 if (f
->glyph
[i
].shape
&& f
->use
->chars
[i
]) {
610 f
->glyph2ascii
[j
] = f
->glyph2ascii
[i
];
611 f
->glyph
[j
] = f
->glyph
[i
];
612 f
->use
->chars
[i
] = j
;
615 f
->glyph2ascii
[i
] = 0;
616 if(f
->glyph
[i
].shape
) {
617 swf_ShapeFree(f
->glyph
[i
].shape
);
618 f
->glyph
[i
].shape
= 0;
619 f
->glyph
[i
].advance
= 0;
621 f
->use
->chars
[i
] = -1;
625 for (i
= 0; i
< f
->maxascii
; i
++) {
626 if(f
->use
->chars
[f
->ascii2glyph
[i
]]<0) {
627 f
->ascii2glyph
[i
] = -1;
629 f
->ascii2glyph
[i
] = f
->use
->chars
[f
->ascii2glyph
[i
]];
633 f
->maxascii
= max_unicode
;
634 f
->use
->is_reduced
= 1;
637 font_freeglyphnames(f
);
642 void swf_FontSort(SWFFONT
* font
)
650 newplace
= malloc(sizeof(int) * font
->numchars
);
652 for (i
= 0; i
< font
->numchars
; i
++) {
655 for (i
= 0; i
< font
->numchars
; i
++)
656 for (j
= 0; j
< i
; j
++) {
657 if (font
->glyph2ascii
[i
] < font
->glyph2ascii
[j
]) {
666 n1
= font
->glyph2ascii
[i
];
667 n2
= font
->glyph2ascii
[j
];
668 font
->glyph2ascii
[j
] = n1
;
669 font
->glyph2ascii
[i
] = n2
;
674 if (font
->glyphnames
) {
675 c1
= font
->glyphnames
[i
];
676 c2
= font
->glyphnames
[j
];
677 font
->glyphnames
[j
] = c1
;
678 font
->glyphnames
[i
] = c2
;
681 r1
= font
->layout
->bounds
[i
];
682 r2
= font
->layout
->bounds
[j
];
683 font
->layout
->bounds
[j
] = r1
;
684 font
->layout
->bounds
[i
] = r2
;
688 newpos
= malloc(sizeof(int) * font
->numchars
);
689 for (i
= 0; i
< font
->numchars
; i
++) {
690 newpos
[newplace
[i
]] = i
;
692 for (i
= 0; i
< font
->maxascii
; i
++) {
693 if (font
->ascii2glyph
[i
] >= 0)
694 font
->ascii2glyph
[i
] = newpos
[font
->ascii2glyph
[i
]];
701 void swf_FontPrepareForEditText(SWFFONT
* font
)
704 swf_FontCreateLayout(font
);
708 int swf_FontInitUsage(SWFFONT
* f
)
713 fprintf(stderr
, "Usage initialized twice");
716 f
->use
= malloc(sizeof(FONTUSAGE
));
717 f
->use
->is_reduced
= 0;
718 f
->use
->chars
= malloc(sizeof(f
->use
->chars
[0]) * f
->numchars
);
719 memset(f
->use
->chars
, 0, sizeof(f
->use
->chars
[0]) * f
->numchars
);
723 void swf_FontClearUsage(SWFFONT
* f
)
727 free(f
->use
->chars
); f
->use
->chars
= 0;
728 free(f
->use
); f
->use
= 0;
731 int swf_FontUse(SWFFONT
* f
, U8
* s
)
734 swf_FontInitUsage(f
);
738 if(*s
< f
->maxascii
&& f
->ascii2glyph
[*s
]>=0)
739 f
->use
->chars
[f
->ascii2glyph
[*s
]] = 1;
745 int swf_FontUseGlyph(SWFFONT
* f
, int glyph
)
748 swf_FontInitUsage(f
);
749 if(glyph
< 0 || glyph
> f
->numchars
)
751 f
->use
->chars
[glyph
] = 1;
755 int swf_FontSetDefine(TAG
* t
, SWFFONT
* f
)
757 U16
*ofs
= (U16
*) malloc(f
->numchars
* 2);
762 swf_ResetWriteBits(t
);
763 swf_SetU16(t
, f
->id
);
767 for (i
= 0; i
< f
->numchars
; i
++)
768 if (f
->glyph
[i
].shape
) {
770 p
+= swf_SetSimpleShape(NULL
, f
->glyph
[i
].shape
);
773 for (i
= 0; i
< j
; i
++)
774 swf_SetU16(t
, ofs
[i
] + j
* 2);
776 fprintf(stderr
, "rfxswf: warning: Font is empty\n");
780 for (i
= 0; i
< f
->numchars
; i
++)
781 if (f
->glyph
[i
].shape
)
782 swf_SetSimpleShape(t
, f
->glyph
[i
].shape
);
784 swf_ResetWriteBits(t
);
789 static inline int fontSize(SWFFONT
* font
)
793 for (t
= 0; t
< font
->numchars
; t
++) {
795 if(font
->glyph
[t
].shape
)
796 l
= (font
->glyph
[t
].shape
->bitlen
+ 7) / 8;
801 return size
+ (font
->numchars
+ 1) * 2;
804 int swf_FontSetDefine2(TAG
* tag
, SWFFONT
* f
)
810 swf_SetU16(tag
, f
->id
);
812 if (f
->layout
) flags
|= 128; // haslayout
813 if (f
->numchars
> 256)
814 flags
|= 4; // widecodes
815 if (f
->style
& FONT_STYLE_BOLD
)
817 if (f
->style
& FONT_STYLE_ITALIC
)
818 flags
|= 2; // italic
819 if (f
->maxascii
>= 256)
820 flags
|= 4; //wide codecs
821 if (fontSize(f
) > 65535)
822 flags
|= 8; //wide offsets
823 flags
|= 8 | 4; //FIXME: the above check doesn't work
825 if (f
->encoding
& FONT_ENCODING_ANSI
)
827 if (f
->encoding
& FONT_ENCODING_UNICODE
)
828 flags
|= 32; // unicode
829 if (f
->encoding
& FONT_ENCODING_SHIFTJIS
)
830 flags
|= 64; // shiftjis
832 swf_SetU8(tag
, flags
);
833 swf_SetU8(tag
, 0); //reserved flags
836 swf_SetU8(tag
, strlen(f
->name
));
837 swf_SetBlock(tag
, f
->name
, strlen(f
->name
));
839 /* font name (="") */
842 /* number of glyphs */
843 swf_SetU16(tag
, f
->numchars
);
844 /* font offset table */
846 for (t
= 0; t
<= f
->numchars
; t
++) {
848 swf_SetU32(tag
, /* fontoffset */ 0); /*placeholder */
850 swf_SetU16(tag
, /* fontoffset */ 0); /*placeholder */
853 for (t
= 0; t
<= f
->numchars
; t
++) {
855 tag
->data
[pos
+ t
* 4] = (tag
->len
- pos
);
856 tag
->data
[pos
+ t
* 4 + 1] = (tag
->len
- pos
) >> 8;
857 tag
->data
[pos
+ t
* 4 + 2] = (tag
->len
- pos
) >> 16;
858 tag
->data
[pos
+ t
* 4 + 3] = (tag
->len
- pos
) >> 24;
860 if (tag
->len
- pos
> 65535) {
861 fprintf(stderr
, "Internal error: Font too big and WideOffsets flag not set\n");
864 tag
->data
[pos
+ t
* 2] = (tag
->len
- pos
);
865 tag
->data
[pos
+ t
* 2 + 1] = (tag
->len
- pos
) >> 8;
867 if (t
< f
->numchars
) {
868 if(f
->glyph
[t
].shape
) {
869 swf_SetSimpleShape(tag
, f
->glyph
[t
].shape
);
871 swf_SetU8(tag
, 0); //non-edge(1) + edge flags(5)
877 /* font code table */
878 if (flags
& 4) { /* wide codes */
879 for (t
= 0; t
< f
->numchars
; t
++) {
880 swf_SetU16(tag
, f
->glyph2ascii
[t
]);
883 for (t
= 0; t
< f
->numchars
; t
++)
884 swf_SetU8(tag
, f
->glyph2ascii
[t
]);
887 swf_SetU16(tag
, f
->layout
->ascent
);
888 swf_SetU16(tag
, f
->layout
->descent
);
889 swf_SetU16(tag
, f
->layout
->leading
);
890 for (t
= 0; t
< f
->numchars
; t
++)
891 swf_SetU16(tag
, f
->glyph
[t
].advance
);
892 for (t
= 0; t
< f
->numchars
; t
++) {
893 swf_ResetWriteBits(tag
);
894 swf_SetRect(tag
, &f
->layout
->bounds
[t
]);
896 swf_SetU16(tag
, f
->layout
->kerningcount
);
897 for (t
= 0; t
< f
->layout
->kerningcount
; t
++) {
898 if (flags
& 4) { /* wide codes */
899 swf_SetU16(tag
, f
->layout
->kerning
[t
].char1
);
900 swf_SetU16(tag
, f
->layout
->kerning
[t
].char2
);
902 swf_SetU8(tag
, f
->layout
->kerning
[t
].char1
);
903 swf_SetU8(tag
, f
->layout
->kerning
[t
].char2
);
905 swf_SetU16(tag
, f
->layout
->kerning
[t
].adjustment
);
911 void swf_FontAddLayout(SWFFONT
* f
, int ascent
, int descent
, int leading
)
913 f
->layout
= (SWFLAYOUT
*) malloc(sizeof(SWFLAYOUT
));
914 f
->layout
->ascent
= ascent
;
915 f
->layout
->descent
= descent
;
916 f
->layout
->leading
= leading
;
917 f
->layout
->kerningcount
= 0;
918 f
->layout
->kerning
= 0;
919 f
->layout
->bounds
= (SRECT
*) malloc(sizeof(SRECT
) * f
->numchars
);
920 memset(f
->layout
->bounds
, 0, sizeof(SRECT
) * f
->numchars
);
923 int swf_FontSetInfo(TAG
* t
, SWFFONT
* f
)
930 swf_ResetWriteBits(t
);
931 swf_SetU16(t
, f
->id
);
932 l
= f
->name
? strlen(f
->name
) : 0;
937 swf_SetBlock(t
, f
->name
, l
);
938 if (f
->numchars
>= 256)
941 if (f
->style
& FONT_STYLE_BOLD
)
943 if (f
->style
& FONT_STYLE_ITALIC
)
945 if (f
->style
& FONT_ENCODING_ANSI
)
947 if (f
->style
& FONT_ENCODING_SHIFTJIS
)
949 if (f
->style
& FONT_ENCODING_UNICODE
)
952 swf_SetU8(t
, (flags
& 0xfe) | wide
);
954 for (i
= 0; i
< f
->numchars
; i
++) {
955 if (f
->glyph
[i
].shape
) {
956 int g2a
= f
->glyph2ascii
[i
];
957 wide
? swf_SetU16(t
, g2a
) : swf_SetU8(t
, g2a
);
964 int swf_TextPrintDefineText(TAG
* t
, SWFFONT
* f
)
966 int id
= swf_GetTagID(t
);
967 if ((id
== ST_DEFINETEXT
) || (id
== ST_DEFINETEXT2
))
968 swf_FontExtract_DefineText(f
->id
, f
, t
, FEDTJ_PRINT
);
974 void swf_FontFree(SWFFONT
* f
)
981 for (i
= 0; i
< f
->numchars
; i
++)
982 if (f
->glyph
[i
].shape
) {
983 swf_ShapeFree(f
->glyph
[i
].shape
);
984 f
->glyph
[i
].shape
= NULL
;
989 if (f
->ascii2glyph
) {
990 free(f
->ascii2glyph
);
991 f
->ascii2glyph
= NULL
;
993 if (f
->glyph2ascii
) {
994 free(f
->glyph2ascii
);
995 f
->glyph2ascii
= NULL
;
999 font_freeglyphnames(f
);
1005 int swf_TextSetInfoRecord(TAG
* t
, SWFFONT
* font
, U16 size
, RGBA
* color
, int dx
, int dy
)
1011 flags
= TF_TEXTCONTROL
| (font
? TF_HASFONT
: 0) | (color
? TF_HASCOLOR
: 0) | (dx
? TF_HASXOFFSET
: 0)
1012 | (dy
? TF_HASYOFFSET
: 0);
1014 swf_SetU8(t
, flags
);
1016 swf_SetU16(t
, font
->id
);
1018 if (swf_GetTagID(t
) == ST_DEFINETEXT2
)
1019 swf_SetRGBA(t
, color
);
1021 swf_SetRGB(t
, color
);
1024 if(dx
>32767 || dx
<-32768)
1025 fprintf(stderr
, "Warning: Horizontal char position overflow: %d\n", dx
);
1029 if(dy
>32767 || dy
<-32768)
1030 fprintf(stderr
, "Warning: Vertical char position overflow: %d\n", dy
);
1034 swf_SetU16(t
, size
);
1039 static int swf_TextCountBits2(SWFFONT
* font
, U8
* s
, int scale
, U8
* gbits
, U8
* abits
, char *encoding
)
1043 if ((!s
) || (!font
) || ((!gbits
) && (!abits
)) || (!font
->ascii2glyph
))
1047 if (!strcmp(encoding
, "UTF8"))
1049 else if (!strcmp(encoding
, "iso-8859-1"))
1052 fprintf(stderr
, "Unknown encoding: %s", encoding
);
1060 c
= readUTF8char(&s
);
1062 if (c
< font
->maxascii
)
1063 glyph
= font
->ascii2glyph
[c
];
1065 g
= swf_CountUBits(glyph
, g
);
1066 a
= swf_CountBits(((((U32
) font
->glyph
[glyph
].advance
) * scale
) / 20) / 100, a
);
1077 static int swf_TextSetCharRecord2(TAG
* t
, SWFFONT
* font
, U8
* s
, int scale
, U8 gbits
, U8 abits
, char *encoding
)
1082 if ((!t
) || (!font
) || (!s
) || (!font
->ascii2glyph
))
1085 if (!strcmp(encoding
, "UTF8"))
1087 else if (!strcmp(encoding
, "iso-8859-1"))
1090 fprintf(stderr
, "Unknown encoding: %s", encoding
);
1093 swf_SetU8(t
, l
); //placeholder
1101 c
= readUTF8char(&s
);
1103 if (c
< font
->maxascii
)
1104 g
= font
->ascii2glyph
[c
];
1106 swf_SetBits(t
, g
, gbits
);
1107 swf_SetBits(t
, ((((U32
) font
->glyph
[g
].advance
) * scale
) / 20) / 100, abits
);
1114 PUT8(&t
->data
[pos
], l
);
1116 swf_ResetWriteBits(t
);
1120 int swf_TextCountBits(SWFFONT
* font
, U8
* s
, int scale
, U8
* gbits
, U8
* abits
)
1122 return swf_TextCountBits2(font
, s
, scale
, gbits
, abits
, "iso-8859-1");
1125 int swf_TextSetCharRecord(TAG
* t
, SWFFONT
* font
, U8
* s
, int scale
, U8 gbits
, U8 abits
)
1127 return swf_TextSetCharRecord2(t
, font
, s
, scale
, gbits
, abits
, "iso-8859-1");
1130 int swf_TextCountBitsUTF8(SWFFONT
* font
, U8
* s
, int scale
, U8
* gbits
, U8
* abits
)
1132 return swf_TextCountBits2(font
, s
, scale
, gbits
, abits
, "UTF8");
1135 int swf_TextSetCharRecordUTF8(TAG
* t
, SWFFONT
* font
, U8
* s
, int scale
, U8 gbits
, U8 abits
)
1137 return swf_TextSetCharRecord2(t
, font
, s
, scale
, gbits
, abits
, "UTF8");
1140 U32
swf_TextGetWidth(SWFFONT
* font
, U8
* s
, int scale
)
1147 if (*s
< font
->maxascii
)
1148 g
= font
->ascii2glyph
[*s
];
1150 res
+= font
->glyph
[g
].advance
/ 20;
1154 res
= (res
* scale
) / 100;
1159 SRECT
swf_TextCalculateBBoxUTF8(SWFFONT
* font
, U8
* s
, int scale
)
1165 int c
= readUTF8char(&s
);
1166 if (c
< font
->maxascii
) {
1167 int g
= font
->ascii2glyph
[c
];
1169 SRECT rn
= font
->layout
->bounds
[g
];
1170 rn
.xmin
= (rn
.xmin
* scale
) / 20 / 100 + pos
;
1171 rn
.xmax
= (rn
.xmax
* scale
) / 20 / 100 + pos
;
1172 rn
.ymin
= (rn
.ymin
* scale
) / 20 / 100;
1173 rn
.ymax
= (rn
.ymax
* scale
) / 20 / 100;
1174 swf_ExpandRect2(&r
, &rn
);
1175 pos
+= (font
->glyph
[g
].advance
* scale
) / 20 / 100;
1184 SWFFONT
*swf_ReadFont(char *filename
)
1190 f
= open(filename
, O_RDONLY
);
1192 if (f
< 0 || swf_ReadSWF(f
, &swf
) < 0) {
1193 fprintf(stderr
, "%s is not a valid SWF font file or contains errors.\n", filename
);
1199 if (swf_FontExtract(&swf
, WRITEFONTID
, &font
) < 0)
1206 void swf_WriteFont(SWFFONT
* font
, char *filename
)
1213 int useDefineFont2
= 0;
1214 int storeGlyphNames
= 1;
1217 useDefineFont2
= 1; /* the only thing new in definefont2
1218 is layout information. */
1220 font
->id
= WRITEFONTID
; //"FN"
1222 memset(&swf
, 0x00, sizeof(SWF
));
1224 swf
.fileVersion
= 4;
1225 swf
.frameRate
= 0x4000;
1227 /* if we use DefineFont1 to store the characters,
1228 we have to build a textfield to store the
1229 advance values. While at it, we can also
1230 make the whole .swf viewable */
1232 /* we now always create viewable swfs, even if we
1233 did use definefont2 -mk */
1234 t
= swf_InsertTag(NULL
, ST_SETBACKGROUNDCOLOR
);
1239 swf_SetRGB(t
, &rgb
);
1240 if (!useDefineFont2
) {
1241 t
= swf_InsertTag(t
, ST_DEFINEFONT
);
1242 swf_FontSetDefine(t
, font
);
1243 t
= swf_InsertTag(t
, ST_DEFINEFONTINFO
);
1244 swf_FontSetInfo(t
, font
);
1246 t
= swf_InsertTag(t
, ST_DEFINEFONT2
);
1247 swf_FontSetDefine2(t
, font
);
1250 if (storeGlyphNames
&& font
->glyphnames
) {
1252 t
= swf_InsertTag(t
, ST_GLYPHNAMES
);
1253 swf_SetU16(t
, WRITEFONTID
);
1254 swf_SetU16(t
, font
->numchars
);
1255 for (c
= 0; c
< font
->numchars
; c
++) {
1256 if (font
->glyphnames
[c
])
1257 swf_SetString(t
, font
->glyphnames
[c
]);
1259 swf_SetString(t
, "");
1263 if (1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1265 int textscale
= 400;
1272 int range
= font
->maxascii
;
1275 if (useDefineFont2
&& range
> 256) {
1279 for (s
= 0; s
< range
; s
++) {
1280 int g
= font
->ascii2glyph
[s
];
1282 if ((font
->glyph
[g
].advance
* textscale
/ 20) / 64 > xmax
) {
1283 xmax
= (font
->glyph
[g
].advance
* textscale
/ 20) / 64;
1287 if ((s
& 15) == 0) {
1294 ymax
= ypos
* textscale
* 2;
1296 swf
.movieSize
.xmax
= xmax
* 20;
1297 swf
.movieSize
.ymax
= ymax
;
1299 t
= swf_InsertTag(t
, ST_DEFINETEXT
);
1301 swf_SetU16(t
, font
->id
+ 1); // ID
1305 r
.xmax
= swf
.movieSize
.xmax
;
1306 r
.ymax
= swf
.movieSize
.ymax
;
1310 swf_SetMatrix(t
, NULL
);
1312 abits
= swf_CountBits(xmax
* 16, 0);
1315 swf_SetU8(t
, gbits
);
1316 swf_SetU8(t
, abits
);
1322 for (y
= 0; y
< ((range
+ 15) / 16); y
++) {
1323 int c
= 0, lastx
= -1;
1324 for (x
= 0; x
< 16; x
++) {
1325 int g
= (y
* 16 + x
< range
) ? font
->ascii2glyph
[y
* 16 + x
] : -1;
1326 if (g
>= 0 && font
->glyph
[g
].shape
) {
1333 swf_TextSetInfoRecord(t
, font
, textscale
, &rgb
, lastx
+ 1, textscale
* ypos
* 2);
1334 for (x
= 0; x
< 16; x
++) {
1335 int g
= (y
* 16 + x
< range
) ? font
->ascii2glyph
[y
* 16 + x
] : -1;
1336 if (g
>= 0 && font
->glyph
[g
].shape
) {
1337 if (lastx
!= x
* xmax
) {
1338 swf_TextSetInfoRecord(t
, 0, 0, 0, x
* xmax
+ 1, 0);
1341 swf_SetBits(t
, g
, gbits
);
1342 swf_SetBits(t
, font
->glyph
[g
].advance
/ 20, abits
);
1343 lastx
= x
* xmax
+ (font
->glyph
[g
].advance
/ 20);
1344 swf_ResetWriteBits(t
);
1353 t
= swf_InsertTag(t
, ST_PLACEOBJECT2
);
1355 swf_ObjectPlace(t
, font
->id
+ 1, 1, NULL
, NULL
, NULL
);
1357 t
= swf_InsertTag(t
, ST_SHOWFRAME
);
1361 t
= swf_InsertTag(t
, ST_END
);
1363 f
= open(filename
, O_RDWR
| O_CREAT
| O_TRUNC
, 0644);
1365 (swf_WriteSWF(f
, &swf
)) fprintf(stderr
, "WriteSWF() failed in writeFont().\n");
1372 void swf_SetEditText(TAG
* tag
, U16 flags
, SRECT r
, char *text
, RGBA
* color
, int maxlength
, U16 font
, U16 height
, EditTextLayout
* layout
, char *variable
)
1374 swf_SetRect(tag
, &r
);
1375 swf_ResetWriteBits(tag
);
1377 flags
&= ~(ET_HASTEXT
| ET_HASTEXTCOLOR
| ET_HASMAXLENGTH
| ET_HASFONT
| ET_HASLAYOUT
);
1379 flags
|= ET_HASTEXT
;
1381 flags
|= ET_HASTEXTCOLOR
;
1383 flags
|= ET_HASMAXLENGTH
;
1385 flags
|= ET_HASFONT
;
1387 flags
|= ET_HASLAYOUT
;
1389 swf_SetBits(tag
, flags
, 16);
1391 if (flags
& ET_HASFONT
) {
1392 swf_SetU16(tag
, font
); //font
1393 swf_SetU16(tag
, height
); //fontheight
1395 if (flags
& ET_HASTEXTCOLOR
) {
1396 swf_SetRGBA(tag
, color
);
1398 if (flags
& ET_HASMAXLENGTH
) {
1399 swf_SetU16(tag
, maxlength
); //maxlength
1401 if (flags
& ET_HASLAYOUT
) {
1402 swf_SetU8(tag
, layout
->align
); //align
1403 swf_SetU16(tag
, layout
->leftmargin
); //left margin
1404 swf_SetU16(tag
, layout
->rightmargin
); //right margin
1405 swf_SetU16(tag
, layout
->indent
); //indent
1406 swf_SetU16(tag
, layout
->leading
); //leading
1408 swf_SetString(tag
, variable
);
1409 if (flags
& ET_HASTEXT
)
1410 swf_SetString(tag
, text
);
1413 SRECT
swf_SetDefineText(TAG
* tag
, SWFFONT
* font
, RGBA
* rgb
, char *text
, int scale
)
1417 U8
*c
= (U8
*) text
;
1420 r
= swf_TextCalculateBBoxUTF8(font
, text
, scale
* 20);
1422 fprintf(stderr
, "No layout information- can't compute text bbox accurately");
1423 /* Hm, without layout information, we can't compute a bounding
1424 box. We could call swf_FontCreateLayout to create a layout,
1425 but the caller probably doesn't want us to mess up his font
1428 r
.xmin
= r
.ymin
= 0;
1429 r
.xmax
= r
.ymax
= 1024 * 20;
1432 swf_SetRect(tag
, &r
);
1434 /* The text matrix is pretty boring, as it doesn't apply to
1435 individual characters, but rather whole text objects (or
1436 at least whole char records- haven't tested).
1437 So it can't do anything which we can't already do with
1438 the placeobject tag we use for placing the text on the scene.
1440 swf_SetMatrix(tag
, 0);
1442 swf_TextCountBitsUTF8(font
, text
, scale
* 20, &gbits
, &abits
);
1443 swf_SetU8(tag
, gbits
);
1444 swf_SetU8(tag
, abits
);
1446 /* now set the text params- notice that a font size of
1447 1024 means that the glyphs will be displayed exactly
1448 as they would be in/with a defineshape. (Try to find
1449 *that* in the flash specs)
1451 swf_TextSetInfoRecord(tag
, font
, (scale
* 1024) / 100, rgb
, 0, 0); //scale
1453 /* set the actual text- notice that we just pass our scale
1454 parameter over, as TextSetCharRecord calculates with
1456 swf_TextSetCharRecordUTF8(tag
, font
, text
, scale
* 20, gbits
, abits
);
1462 void swf_FontCreateLayout(SWFFONT
* f
)
1471 f
->layout
= (SWFLAYOUT
*) malloc(sizeof(SWFLAYOUT
));
1472 memset(f
->layout
, 0, sizeof(SWFLAYOUT
));
1473 f
->layout
->bounds
= (SRECT
*) malloc(f
->numchars
* sizeof(SRECT
));
1474 f
->layout
->ascent
= -32767;
1475 f
->layout
->descent
= -32767;
1477 for (t
= 0; t
< f
->numchars
; t
++) {
1481 shape2
= swf_ShapeToShape2(f
->glyph
[t
].shape
);
1483 fprintf(stderr
, "Shape parse error\n");
1486 bbox
= swf_GetShapeBoundingBox(shape2
);
1487 swf_Shape2Free(shape2
);
1488 f
->layout
->bounds
[t
] = bbox
;
1490 width
= (bbox
.xmax
);
1492 /* The following is a heuristic- it may be that extractfont_DefineText
1493 has already found out some widths for individual characters (from the way
1494 they are used)- we now have to guess whether that width might be possible,
1495 which is the case if it isn't either much too big or much too small */
1496 if (width
> f
->glyph
[t
].advance
* 3 / 2 || width
< f
->glyph
[t
].advance
/ 2)
1497 f
->glyph
[t
].advance
= width
;
1499 if (-bbox
.ymin
> f
->layout
->ascent
)
1500 f
->layout
->ascent
= bbox
.ymin
;
1501 if (bbox
.ymax
> f
->layout
->descent
)
1502 f
->layout
->descent
= bbox
.ymax
;
1506 void swf_DrawText(drawer_t
* draw
, SWFFONT
* font
, int size
, char *text
)
1508 U8
*s
= (U8
*) text
;
1514 U32 c
= readUTF8char(&s
);
1515 int g
= font
->ascii2glyph
[c
];
1516 shape
= font
->glyph
[g
].shape
;
1517 if (((int) g
) < 0) {
1518 fprintf(stderr
, "No char %d in font %s\n", c
, font
->name
? (char *) font
->name
: "?");
1521 shape2
= swf_ShapeToShape2(shape
);
1524 if (l
->type
== moveTo
) {
1526 to
.x
= l
->x
* size
/ 100.0 / 20.0 + advance
;
1527 to
.y
= l
->y
* size
/ 100.0 / 20.0;
1528 draw
->moveTo(draw
, &to
);
1529 } else if (l
->type
== lineTo
) {
1531 to
.x
= l
->x
* size
/ 100.0 / 20.0 + advance
;
1532 to
.y
= l
->y
* size
/ 100.0 / 20.0;
1533 draw
->lineTo(draw
, &to
);
1534 } else if (l
->type
== splineTo
) {
1536 mid
.x
= l
->sx
* size
/ 100.0 / 20.0 + advance
;
1537 mid
.y
= l
->sy
* size
/ 100.0 / 20.0;
1538 to
.x
= l
->x
* size
/ 100.0 / 20.0 + advance
;
1539 to
.y
= l
->y
* size
/ 100.0 / 20.0;
1540 draw
->splineTo(draw
, &mid
, &to
);
1544 swf_Shape2Free(shape2
);
1545 advance
+= font
->glyph
[g
].advance
* size
/ 100.0 / 20.0;