added overflow checking for text coordinates.
[swftools.git] / lib / modules / swftext.c
bloba01e10b737448876545f7c2fc10a3b57c9d8e067
1 /* swftext.c
3 Text and font routines
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)
27 U32 c = 0;
28 if (!(*(*text) & 0x80))
29 return *((*text)++);
31 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
32 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
33 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
34 (*text) += 2;
35 return c;
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);
40 (*text) += 3;
41 return c;
43 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
44 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
45 && (*text)[3]) {
46 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
47 (*text) += 4;
48 return c;
50 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
51 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
52 && (*text)[3]
53 && (*text)[4]) {
54 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
55 (*text) += 5;
56 return c;
58 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
59 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
60 && (*text)[3]
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;
64 (*text) += 6;
65 return c;
67 return *((*text)++);
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
77 #define FF_BOLD 0x02
78 #define FF_ITALIC 0x04
79 #define FF_ANSI 0x08
80 #define FF_SHIFTJIS 0x10
81 #define FF_UNICODE 0x20
83 #define FF2_BOLD 0x01
84 #define FF2_ITALIC 0x02
85 #define FF2_WIDECODES 0x04
86 #define FF2_WIDEOFFSETS 0x08
87 #define FF2_ANSI 0x10
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 *))
106 int n;
107 TAG *t;
108 if (!swf)
109 return -1;
110 t = swf->firstTag;
111 n = 0;
113 while (t) {
114 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
115 n++;
116 if (FontCallback) {
117 U16 id;
118 int l;
119 U8 s[257];
120 s[0] = 0;
121 swf_SaveTagPos(t);
122 swf_SetTagPos(t, 0);
124 id = swf_GetU16(t);
125 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
126 swf_GetU16(t);
127 l = swf_GetU8(t);
128 swf_GetBlock(t, s, l);
129 s[l] = 0;
132 (FontCallback) (id, s);
134 swf_RestoreTagPos(t);
137 t = swf_NextTag(t);
139 return n;
142 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
144 U16 fid;
145 swf_SaveTagPos(t);
146 swf_SetTagPos(t, 0);
148 fid = swf_GetU16(t);
149 if ((!id) || (id == fid)) {
150 U16 of;
151 int n, i;
153 id = fid;
154 f->version = 1;
155 f->id = fid;
157 of = swf_GetU16(t);
158 n = of / 2;
159 f->numchars = n;
160 f->glyph = malloc(sizeof(SWFGLYPH) * n);
161 memset(f->glyph, 0, sizeof(SWFGLYPH) * n);
163 for (i = 1; i < n; i++)
164 swf_GetU16(t);
165 for (i = 0; i < n; i++)
166 swf_GetSimpleShape(t, &f->glyph[i].shape);
169 swf_RestoreTagPos(t);
170 return id;
173 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
175 U16 fid;
176 U16 maxcode;
177 U8 flags;
178 swf_SaveTagPos(t);
179 swf_SetTagPos(t, 0);
181 fid = swf_GetU16(t);
182 if (fid == id) {
183 U8 l = swf_GetU8(t);
184 int i;
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 */
190 return id;
193 if (f->name)
194 free(f->name);
196 f->name = (U8 *) malloc(l + 1);
197 swf_GetBlock(t, f->name, l);
198 f->name[l] = 0;
200 flags = swf_GetU8(t);
201 if (flags & 2)
202 f->style |= FONT_STYLE_BOLD;
203 if (flags & 4)
204 f->style |= FONT_STYLE_ITALIC;
205 if (flags & 8)
206 f->encoding |= FONT_ENCODING_ANSI;
207 if (flags & 16)
208 f->encoding |= FONT_ENCODING_SHIFTJIS;
209 if (flags & 32)
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);
217 maxcode = 0;
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];
223 maxcode++;
224 if (maxcode < 256)
225 maxcode = 256;
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);
235 return id;
238 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
240 U16 fid;
241 U16 maxcode;
242 U8 flags;
243 swf_SaveTagPos(tag);
244 swf_SetTagPos(tag, 0);
246 fid = swf_GetU16(tag);
248 if (fid == id) {
249 int num = swf_GetU16(tag);
250 int t;
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);
258 return id;
262 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
264 int t, glyphcount;
265 int maxcode;
266 int fid;
267 U8 flags1, flags2, namelen;
268 swf_SaveTagPos(tag);
269 swf_SetTagPos(tag, 0);
270 font->version = 2;
271 fid = swf_GetU16(tag);
272 if (id && id != fid)
273 return id;
274 font->id = fid;
275 flags1 = swf_GetU8(tag);
276 flags2 = swf_GetU8(tag); //reserved flags
278 if (flags1 & 1)
279 font->style |= FONT_STYLE_BOLD;
280 if (flags1 & 2)
281 font->style |= FONT_STYLE_ITALIC;
282 if (flags1 & 16)
283 font->encoding |= FONT_ENCODING_ANSI;
284 if (flags1 & 32)
285 font->encoding |= FONT_ENCODING_UNICODE;
286 if (flags1 & 64)
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);
293 font->version = 2;
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
308 } else {
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));
320 maxcode = 0;
321 for (t = 0; t < glyphcount; t++) {
322 int code;
323 if (flags1 & 4) // wide codes
324 code = swf_GetU16(tag);
325 else
326 code = swf_GetU8(tag);
327 font->glyph2ascii[t] = code;
328 if (code > maxcode)
329 maxcode = code;
331 maxcode++;
332 if (maxcode < 256)
333 maxcode = 256;
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
342 U16 kerningcount;
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);
361 if (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);
367 } else {
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);
376 return font->id;
380 #define FEDTJ_PRINT 0x01
381 #define FEDTJ_MODIFY 0x02
382 #define FEDTJ_CALLBACK 0x04
384 static int
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)
389 U16 cid;
390 SRECT r;
391 MATRIX m;
392 U8 gbits, abits;
393 int fid = 0;
394 RGBA color;
395 int x = 0, y = 0;
396 int fontsize = 0;
398 memset(&color, 0, sizeof(color));
400 swf_SaveTagPos(t);
401 swf_SetTagPos(t, 0);
403 cid = swf_GetU16(t);
404 swf_GetRect(t, &r);
405 swf_GetMatrix(t, &m);
406 gbits = swf_GetU8(t);
407 abits = swf_GetU8(t);
409 while (1) {
410 int flags, num;
411 flags = swf_GetU8(t);
412 if (!flags)
413 break;
415 if (flags & TF_TEXTCONTROL) {
416 if (flags & TF_HASFONT)
417 fid = swf_GetU16(t);
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)
426 x = swf_GetS16(t);
427 if (flags & TF_HASYOFFSET)
428 y = swf_GetS16(t);
429 if (flags & TF_HASFONT)
430 fontsize = swf_GetU16(t);
433 num = swf_GetU8(t);
434 if (!num)
435 break;
438 int i;
439 int buf[256];
440 int advance[256];
441 int xpos = 0;
442 for (i = 0; i < num; i++) {
443 int glyph;
444 int adv = 0;
445 advance[i] = xpos;
446 glyph = swf_GetBits(t, gbits);
447 adv = swf_GetBits(t, abits);
448 xpos += adv;
450 // <deprecated>
451 if (id == fid) {
452 if (jobs & FEDTJ_PRINT) {
453 int code = f->glyph2ascii[glyph];
454 printf("%c", code);
456 if (jobs & FEDTJ_MODIFY)
457 f->glyph[glyph].advance = adv * 20; //?
458 } else {
459 if (jobs & FEDTJ_PRINT) {
460 printf("?");
463 // </deprecated>
465 buf[i] = glyph;
467 if ((id == fid) && (jobs & FEDTJ_PRINT))
468 printf("\n");
469 if (jobs & FEDTJ_CALLBACK)
470 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
471 x += xpos;
475 swf_RestoreTagPos(t);
476 return id;
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)
492 TAG *t;
493 SWFFONT *f;
495 if ((!swf) || (!font))
496 return -1;
498 f = (SWFFONT *) malloc(sizeof(SWFFONT));
499 memset(f, 0x00, sizeof(SWFFONT));
501 t = swf->firstTag;
503 while (t) {
504 int nid = 0;
505 switch (swf_GetTagID(t)) {
506 case ST_DEFINEFONT:
507 nid = swf_FontExtract_DefineFont(id, f, t);
508 break;
510 case ST_DEFINEFONT2:
511 nid = swf_FontExtract_DefineFont2(id, f, t);
512 break;
514 case ST_DEFINEFONTINFO:
515 case ST_DEFINEFONTINFO2:
516 nid = swf_FontExtract_DefineFontInfo(id, f, t);
517 break;
519 case ST_DEFINETEXT:
520 case ST_DEFINETEXT2:
521 nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
522 break;
524 case ST_GLYPHNAMES:
525 nid = swf_FontExtract_GlyphNames(id, f, t);
526 break;
528 if (nid > 0)
529 id = nid;
530 t = swf_NextTag(t);
532 if (f->id != id) {
533 free(f);
534 f = 0;
536 font[0] = f;
537 return 0;
540 int swf_FontSetID(SWFFONT * f, U16 id)
542 if (!f)
543 return -1;
544 f->id = id;
545 return 0;
548 void swf_LayoutFree(SWFLAYOUT * l)
550 if (l) {
551 if (l->kerning)
552 free(l->kerning);
553 l->kerning = NULL;
554 if (l->bounds)
555 free(l->bounds);
556 l->bounds = NULL;
558 free(l);
562 static void font_freeglyphnames(SWFFONT*f)
564 if (f->glyphnames) {
565 int t;
566 for (t = 0; t < f->numchars; t++) {
567 if (f->glyphnames[t])
568 free(f->glyphnames[t]);
570 free(f->glyphnames);
571 f->glyphnames = 0;
575 static void font_freeusage(SWFFONT*f)
577 if (f->use) {
578 if(f->use->chars) {
579 free(f->use->chars);f->use->chars = 0;
581 free(f->use); f->use = 0;
584 static void font_freelayout(SWFFONT*f)
586 if (f->layout) {
587 swf_LayoutFree(f->layout);
588 f->layout = 0;
591 static void font_freename(SWFFONT*f)
593 if (f->name) {
594 free(f->name);
595 f->name = 0;
599 int swf_FontReduce(SWFFONT * f)
601 int i, j;
602 int max_unicode = 0;
603 if ((!f) || (!f->use) || f->use->is_reduced)
604 return -1;
606 j = 0;
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;
613 j++;
614 } else {
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;
622 j++; //TODO: remove
625 for (i = 0; i < f->maxascii; i++) {
626 if(f->use->chars[f->ascii2glyph[i]]<0) {
627 f->ascii2glyph[i] = -1;
628 } else {
629 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
630 max_unicode = i;
633 f->maxascii = max_unicode;
634 f->use->is_reduced = 1;
635 f->numchars = j;
636 font_freelayout(f);
637 font_freeglyphnames(f);
638 font_freename(f);
639 return j;
642 void swf_FontSort(SWFFONT * font)
644 int i, j, k;
645 int *newplace;
646 int *newpos;
647 if (!font)
648 return;
650 newplace = malloc(sizeof(int) * font->numchars);
652 for (i = 0; i < font->numchars; i++) {
653 newplace[i] = i;
655 for (i = 0; i < font->numchars; i++)
656 for (j = 0; j < i; j++) {
657 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
658 int n1, n2;
659 char *c1, *c2;
660 SWFGLYPH g1, g2;
661 SRECT r1, r2;
662 n1 = newplace[i];
663 n2 = newplace[j];
664 newplace[j] = n1;
665 newplace[i] = n2;
666 n1 = font->glyph2ascii[i];
667 n2 = font->glyph2ascii[j];
668 font->glyph2ascii[j] = n1;
669 font->glyph2ascii[i] = n2;
670 g1 = font->glyph[i];
671 g2 = font->glyph[j];
672 font->glyph[j] = g1;
673 font->glyph[i] = g2;
674 if (font->glyphnames) {
675 c1 = font->glyphnames[i];
676 c2 = font->glyphnames[j];
677 font->glyphnames[j] = c1;
678 font->glyphnames[i] = c2;
680 if (font->layout) {
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]];
697 free(newpos);
698 free(newplace);
701 void swf_FontPrepareForEditText(SWFFONT * font)
703 if (!font->layout)
704 swf_FontCreateLayout(font);
705 swf_FontSort(font);
708 int swf_FontInitUsage(SWFFONT * f)
710 if (!f)
711 return -1;
712 if(f->use) {
713 fprintf(stderr, "Usage initialized twice");
714 return -1;
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);
720 return 0;
723 void swf_FontClearUsage(SWFFONT * f)
725 if (!f || !f->use)
726 return;
727 free(f->use->chars); f->use->chars = 0;
728 free(f->use); f->use = 0;
731 int swf_FontUse(SWFFONT * f, U8 * s)
733 if (!f->use)
734 swf_FontInitUsage(f);
735 if( (!s))
736 return -1;
737 while (*s) {
738 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
739 f->use->chars[f->ascii2glyph[*s]] = 1;
740 s++;
742 return 0;
745 int swf_FontUseGlyph(SWFFONT * f, int glyph)
747 if (!f->use)
748 swf_FontInitUsage(f);
749 if(glyph < 0 || glyph > f->numchars)
750 return -1;
751 f->use->chars[glyph] = 1;
752 return 0;
755 int swf_FontSetDefine(TAG * t, SWFFONT * f)
757 U16 *ofs = (U16 *) malloc(f->numchars * 2);
758 int p, i, j;
760 if ((!t) || (!f))
761 return -1;
762 swf_ResetWriteBits(t);
763 swf_SetU16(t, f->id);
765 p = 0;
766 j = 0;
767 for (i = 0; i < f->numchars; i++)
768 if (f->glyph[i].shape) {
769 ofs[j++] = p;
770 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
773 for (i = 0; i < j; i++)
774 swf_SetU16(t, ofs[i] + j * 2);
775 if (!j) {
776 fprintf(stderr, "rfxswf: warning: Font is empty\n");
777 swf_SetU16(t, 0);
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);
785 free(ofs);
786 return 0;
789 static inline int fontSize(SWFFONT * font)
791 int t;
792 int size = 0;
793 for (t = 0; t < font->numchars; t++) {
794 int l = 0;
795 if(font->glyph[t].shape)
796 l = (font->glyph[t].shape->bitlen + 7) / 8;
797 else
798 l = 8;
799 size += l + 1;
801 return size + (font->numchars + 1) * 2;
804 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
806 U8 flags = 0;
807 int t;
808 int pos;
809 int pos2;
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)
816 flags |= 1; // 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)
826 flags |= 16; // 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
834 if (f->name) {
835 /* font name */
836 swf_SetU8(tag, strlen(f->name));
837 swf_SetBlock(tag, f->name, strlen(f->name));
838 } else {
839 /* font name (="") */
840 swf_SetU8(tag, 0);
842 /* number of glyphs */
843 swf_SetU16(tag, f->numchars);
844 /* font offset table */
845 pos = tag->len;
846 for (t = 0; t <= f->numchars; t++) {
847 if (flags & 8)
848 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
849 else
850 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
853 for (t = 0; t <= f->numchars; t++) {
854 if (flags & 8) {
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;
859 } else {
860 if (tag->len - pos > 65535) {
861 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
862 exit(1);
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);
870 } else {
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]);
882 } else {
883 for (t = 0; t < f->numchars; t++)
884 swf_SetU8(tag, f->glyph2ascii[t]);
886 if (f->layout) {
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);
901 } else {
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);
908 return 0;
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)
925 int l, i;
926 U8 wide = 0;
927 U8 flags = 0;
928 if ((!t) || (!f))
929 return -1;
930 swf_ResetWriteBits(t);
931 swf_SetU16(t, f->id);
932 l = f->name ? strlen(f->name) : 0;
933 if (l > 255)
934 l = 255;
935 swf_SetU8(t, l);
936 if (l)
937 swf_SetBlock(t, f->name, l);
938 if (f->numchars >= 256)
939 wide = 1;
941 if (f->style & FONT_STYLE_BOLD)
942 flags |= 2;
943 if (f->style & FONT_STYLE_ITALIC)
944 flags |= 4;
945 if (f->style & FONT_ENCODING_ANSI)
946 flags |= 8;
947 if (f->style & FONT_ENCODING_SHIFTJIS)
948 flags |= 16;
949 if (f->style & FONT_ENCODING_UNICODE)
950 flags |= 32;
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);
961 return 0;
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);
969 else
970 return -1;
971 return 0;
974 void swf_FontFree(SWFFONT * f)
976 int i;
977 if (!f)
978 return;
980 if (f->glyph) {
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;
986 free(f->glyph);
987 f->glyph = 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;
997 font_freename(f);
998 font_freelayout(f);
999 font_freeglyphnames(f);
1000 font_freeusage(f);
1002 free(f);
1005 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1007 U8 flags;
1008 if (!t)
1009 return -1;
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);
1015 if (font)
1016 swf_SetU16(t, font->id);
1017 if (color) {
1018 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1019 swf_SetRGBA(t, color);
1020 else
1021 swf_SetRGB(t, color);
1023 if (dx) {
1024 if(dx>32767 || dx<-32768)
1025 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1026 swf_SetS16(t, dx);
1028 if (dy) {
1029 if(dy>32767 || dy<-32768)
1030 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1031 swf_SetS16(t, dy);
1033 if (font)
1034 swf_SetU16(t, size);
1036 return 0;
1039 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1041 U16 g, a;
1042 char utf8 = 0;
1043 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1044 return -1;
1045 g = a = 0;
1047 if (!strcmp(encoding, "UTF8"))
1048 utf8 = 1;
1049 else if (!strcmp(encoding, "iso-8859-1"))
1050 utf8 = 0;
1051 else
1052 fprintf(stderr, "Unknown encoding: %s", encoding);
1054 while (*s) {
1055 int glyph = -1, c;
1057 if (!utf8)
1058 c = *s++;
1059 else
1060 c = readUTF8char(&s);
1062 if (c < font->maxascii)
1063 glyph = font->ascii2glyph[c];
1064 if (glyph >= 0) {
1065 g = swf_CountUBits(glyph, g);
1066 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1070 if (gbits)
1071 gbits[0] = (U8) g;
1072 if (abits)
1073 abits[0] = (U8) a;
1074 return 0;
1077 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1079 int l = 0, pos;
1080 char utf8 = 0;
1082 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1083 return -1;
1085 if (!strcmp(encoding, "UTF8"))
1086 utf8 = 1;
1087 else if (!strcmp(encoding, "iso-8859-1"))
1088 utf8 = 0;
1089 else
1090 fprintf(stderr, "Unknown encoding: %s", encoding);
1092 pos = t->len;
1093 swf_SetU8(t, l); //placeholder
1095 while (*s) {
1096 int g = -1, c;
1098 if (!utf8)
1099 c = *s++;
1100 else
1101 c = readUTF8char(&s);
1103 if (c < font->maxascii)
1104 g = font->ascii2glyph[c];
1105 if (g >= 0) {
1106 swf_SetBits(t, g, gbits);
1107 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1108 l++;
1109 if (l == 0x7f)
1110 break;
1114 PUT8(&t->data[pos], l);
1116 swf_ResetWriteBits(t);
1117 return 0;
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)
1142 U32 res = 0;
1144 if (font && s) {
1145 while (s[0]) {
1146 int g = -1;
1147 if (*s < font->maxascii)
1148 g = font->ascii2glyph[*s];
1149 if (g >= 0)
1150 res += font->glyph[g].advance / 20;
1151 s++;
1153 if (scale)
1154 res = (res * scale) / 100;
1156 return res;
1159 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1161 int pos = 0;
1162 SRECT r;
1163 swf_GetRect(0, &r);
1164 while (*s) {
1165 int c = readUTF8char(&s);
1166 if (c < font->maxascii) {
1167 int g = font->ascii2glyph[c];
1168 if (g >= 0) {
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;
1178 c++;
1180 return r;
1184 SWFFONT *swf_ReadFont(char *filename)
1186 int f;
1187 SWF swf;
1188 if (!filename)
1189 return 0;
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);
1194 close(f);
1195 return 0;
1196 } else {
1197 SWFFONT *font;
1198 close(f);
1199 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1200 return 0;
1201 swf_FreeTags(&swf);
1202 return font;
1206 void swf_WriteFont(SWFFONT * font, char *filename)
1208 SWF swf;
1209 TAG *t;
1210 SRECT r;
1211 RGBA rgb;
1212 int f;
1213 int useDefineFont2 = 0;
1214 int storeGlyphNames = 1;
1216 if (font->layout)
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);
1235 swf.firstTag = t;
1236 rgb.r = 0xef;
1237 rgb.g = 0xef;
1238 rgb.b = 0xff;
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);
1245 } else {
1246 t = swf_InsertTag(t, ST_DEFINEFONT2);
1247 swf_FontSetDefine2(t, font);
1250 if (storeGlyphNames && font->glyphnames) {
1251 int c;
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]);
1258 else
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;
1266 int s;
1267 int xmax = 0;
1268 int ymax = 0;
1269 int ypos = 1;
1270 U8 gbits, abits;
1271 int x, y, c;
1272 int range = font->maxascii;
1274 c = 0;
1275 if (useDefineFont2 && range > 256) {
1276 range = 256;
1279 for (s = 0; s < range; s++) {
1280 int g = font->ascii2glyph[s];
1281 if (g >= 0) {
1282 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1283 xmax = (font->glyph[g].advance * textscale / 20) / 64;
1285 c++;
1287 if ((s & 15) == 0) {
1288 if (c) {
1289 ypos++;
1291 c = 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
1303 r.xmin = 0;
1304 r.ymin = 0;
1305 r.xmax = swf.movieSize.xmax;
1306 r.ymax = swf.movieSize.ymax;
1308 swf_SetRect(t, &r);
1310 swf_SetMatrix(t, NULL);
1312 abits = swf_CountBits(xmax * 16, 0);
1313 gbits = 8;
1315 swf_SetU8(t, gbits);
1316 swf_SetU8(t, abits);
1318 rgb.r = 0x00;
1319 rgb.g = 0x00;
1320 rgb.b = 0x00;
1321 ypos = 1;
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) {
1327 c++;
1328 if (lastx < 0)
1329 lastx = x * xmax;
1332 if (c) {
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);
1340 swf_SetU8(t, 1);
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);
1347 ypos++;
1350 swf_SetU8(t, 0);
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);
1364 if FAILED
1365 (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1366 close(f);
1368 swf_FreeTags(&swf);
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);
1378 if (text)
1379 flags |= ET_HASTEXT;
1380 if (color)
1381 flags |= ET_HASTEXTCOLOR;
1382 if (maxlength)
1383 flags |= ET_HASMAXLENGTH;
1384 if (font)
1385 flags |= ET_HASFONT;
1386 if (layout)
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)
1415 SRECT r;
1416 U8 gbits, abits;
1417 U8 *c = (U8 *) text;
1418 int pos = 0;
1419 if (font->layout) {
1420 r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1421 } else {
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
1426 structure.
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
1455 percent, too */
1456 swf_TextSetCharRecordUTF8(tag, font, text, scale * 20, gbits, abits);
1458 swf_SetU8(tag, 0);
1459 return r;
1462 void swf_FontCreateLayout(SWFFONT * f)
1464 S16 leading = 0;
1465 int t;
1466 if (f->layout)
1467 return;
1468 if (!f->numchars)
1469 return;
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++) {
1478 SHAPE2 *shape2;
1479 SRECT bbox;
1480 int width;
1481 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1482 if (!shape2) {
1483 fprintf(stderr, "Shape parse error\n");
1484 exit(1);
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;
1509 int advance = 0;
1510 while (*s) {
1511 SHAPE *shape;
1512 SHAPE2 *shape2;
1513 SHAPELINE *l;
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 : "?");
1519 continue;
1521 shape2 = swf_ShapeToShape2(shape);
1522 l = shape2->lines;
1523 while (l) {
1524 if (l->type == moveTo) {
1525 FPOINT to;
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) {
1530 FPOINT to;
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) {
1535 FPOINT mid, to;
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);
1542 l = l->next;
1544 swf_Shape2Free(shape2);
1545 advance += font->glyph[g].advance * size / 100.0 / 20.0;