1 /* swftext.c
2
3 Text and font routines
4
5 Extension module for the rfxswf library.
6 Part of the swftools package.
7
8 Copyright (c) 2001 Rainer B�hme <rfxswf@reflex-studio.de>
9 Copyright (c) 2003,2004,2005,2006,2007,2008,2009 Matthias Kramm
10
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.
15
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.
20
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 */
24
25 #include "../rfxswf.h"
26
readUTF8char(U8 ** text)27 U32 readUTF8char(U8 ** text)
28 {
29 U32 c = 0;
30 if (!(*(*text) & 0x80))
31 return *((*text)++);
32
33 /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */
34 if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
35 c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
36 (*text) += 2;
37 return c;
38 }
39 /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */
40 if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
41 c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
42 (*text) += 3;
43 return c;
44 }
45 /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
46 if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
47 && (*text)[3]) {
48 c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
49 (*text) += 4;
50 return c;
51 }
52 /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
53 if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
54 && (*text)[3]
55 && (*text)[4]) {
56 c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
57 (*text) += 5;
58 return c;
59 }
60 /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */
61 if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
62 && (*text)[3]
63 && (*text)[4] && (*text)[5]) {
64 c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
65 ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
66 (*text) += 6;
67 return c;
68 }
69 return *((*text)++);
70 }
71
72 #define TF_TEXTCONTROL 0x80
73 #define TF_HASFONT 0x08
74 #define TF_HASCOLOR 0x04
75 #define TF_HASYOFFSET 0x02
76 #define TF_HASXOFFSET 0x01
77
78 #define FF_WIDECODES 0x01
79 #define FF_BOLD 0x02
80 #define FF_ITALIC 0x04
81 #define FF_ANSI 0x08
82 #define FF_SHIFTJIS 0x10
83 #define FF_UNICODE 0x20
84
85 #define FF2_BOLD 0x01
86 #define FF2_ITALIC 0x02
87 #define FF2_WIDECODES 0x04
88 #define FF2_WIDEOFFSETS 0x08
89 #define FF2_ANSI 0x10
90 #define FF2_UNICODE 0x20
91 #define FF2_SHIFTJIS 0x40
92 #define FF2_LAYOUT 0x80
93
swf_FontIsItalic(SWFFONT * f)94 int swf_FontIsItalic(SWFFONT * f)
95 {
96 return f->style & FONT_STYLE_ITALIC;
97 }
98
swf_FontIsBold(SWFFONT * f)99 int swf_FontIsBold(SWFFONT * f)
100 {
101 return f->style & FONT_STYLE_BOLD;
102 }
103
104 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
105
swf_FontEnumerate(SWF * swf,void (* FontCallback)(void *,U16,U8 *),void * self)106 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
107 {
108 int n;
109 TAG *t;
110 if (!swf)
111 return -1;
112 t = swf->firstTag;
113 n = 0;
114
115 while (t) {
116 if (swf_isFontTag(t)) {
117 n++;
118 if (FontCallback) {
119 U16 id;
120 int l;
121 U8 s[257];
122 s[0] = 0;
123 swf_SetTagPos(t, 0);
124
125 id = swf_GetU16(t);
126 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
127 swf_GetU16(t);
128 l = swf_GetU8(t);
129 swf_GetBlock(t, s, l);
130 s[l] = 0;
131 }
132
133 (FontCallback) (self, id, s);
134 }
135 }
136 t = swf_NextTag(t);
137 }
138 return n;
139 }
140
swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t)141 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
142 {
143 U16 fid;
144 swf_SetTagPos(t, 0);
145
146 fid = swf_GetU16(t);
147 if ((!id) || (id == fid)) {
148 U16 of;
149 int n, i;
150
151 id = fid;
152 f->version = 1;
153 f->id = fid;
154
155 of = swf_GetU16(t);
156 n = of / 2;
157 f->numchars = n;
158 f->glyph = (SWFGLYPH*)rfx_calloc(sizeof(SWFGLYPH) * n);
159
160 for (i = 1; i < n; i++)
161 swf_GetU16(t);
162 for (i = 0; i < n; i++)
163 swf_GetSimpleShape(t, &f->glyph[i].shape);
164 }
165 return id;
166 }
167
swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t)168 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
169 {
170 U16 fid;
171 U16 maxcode;
172 U8 flags;
173 swf_SetTagPos(t, 0);
174
175 fid = swf_GetU16(t);
176 if (fid == id) {
177 U8 l = swf_GetU8(t);
178 int i;
179
180 if (f->version > 1) {
181 /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
182 too. However, they only add little information to what's already
183 inside the DefineFont2 tag */
184 return id;
185 }
186
187 if (f->name)
188 rfx_free(f->name);
189
190 f->name = (U8 *) rfx_alloc(l + 1);
191 swf_GetBlock(t, f->name, l);
192 f->name[l] = 0;
193
194 flags = swf_GetU8(t);
195 if (flags & 2)
196 f->style |= FONT_STYLE_BOLD;
197 if (flags & 4)
198 f->style |= FONT_STYLE_ITALIC;
199 if (flags & 8)
200 f->encoding |= FONT_ENCODING_ANSI;
201 if (flags & 16)
202 f->encoding |= FONT_ENCODING_SHIFTJIS;
203 if (flags & 32)
204 f->encoding |= FONT_ENCODING_UNICODE;
205
206 if (t->id == ST_DEFINEFONTINFO2) {
207 f->language = swf_GetU8(t);
208 }
209
210 f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
211 maxcode = 0;
212 for (i = 0; i < f->numchars; i++) {
213 f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
214 if (f->glyph2ascii[i] > maxcode)
215 maxcode = f->glyph2ascii[i];
216 }
217 maxcode++;
218 if (maxcode < 256)
219 maxcode = 256;
220 f->maxascii = maxcode;
221 f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
222 memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
223
224 for (i = 0; i < f->numchars; i++)
225 f->ascii2glyph[f->glyph2ascii[i]] = i;
226 }
227 return id;
228 }
229
swf_FontExtract_GlyphNames(int id,SWFFONT * f,TAG * tag)230 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
231 {
232 U16 fid;
233 swf_SetTagPos(tag, 0);
234
235 fid = swf_GetU16(tag);
236
237 if (fid == id) {
238 int num = swf_GetU16(tag);
239 int t;
240 f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num);
241 for (t = 0; t < num; t++) {
242 f->glyphnames[t] = strdup(swf_GetString(tag));
243 }
244 }
245 return id;
246 }
247
248
swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag)249 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
250 {
251 int t, glyphcount;
252 int maxcode;
253 int fid;
254 U32 offset_start;
255 U32 *offset;
256 U8 flags1, langcode, namelen;
257 swf_SetTagPos(tag, 0);
258 font->version = tag->id==ST_DEFINEFONT3?3:2;
259 fid = swf_GetU16(tag);
260 if (id && id != fid)
261 return id;
262 font->id = fid;
263 flags1 = swf_GetU8(tag);
264 langcode = swf_GetU8(tag); //reserved flags
265
266 if (flags1 & 1)
267 font->style |= FONT_STYLE_BOLD;
268 if (flags1 & 2)
269 font->style |= FONT_STYLE_ITALIC;
270 if (flags1 & 16)
271 font->encoding |= FONT_ENCODING_ANSI;
272 if (flags1 & 32)
273 font->encoding |= FONT_ENCODING_UNICODE;
274 if (flags1 & 64)
275 font->encoding |= FONT_ENCODING_SHIFTJIS;
276
277 namelen = swf_GetU8(tag);
278 font->name = (U8 *) rfx_alloc(namelen + 1);
279 font->name[namelen] = 0;
280 swf_GetBlock(tag, font->name, namelen);
281 glyphcount = swf_GetU16(tag);
282 font->numchars = glyphcount;
283
284 font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
285 font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
286
287 offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
288 offset_start = tag->pos;
289
290 if (flags1 & 8) { // wide offsets
291 for (t = 0; t < glyphcount; t++)
292 offset[t] = swf_GetU32(tag); //offset[t]
293
294 if (glyphcount) /* this _if_ is not in the specs */
295 offset[glyphcount] = swf_GetU32(tag); // fontcodeoffset
296 else
297 offset[glyphcount] = tag->pos;
298 } else {
299 for (t = 0; t < glyphcount; t++)
300 offset[t] = swf_GetU16(tag); //offset[t]
301
302 if (glyphcount) /* this _if_ is not in the specs */
303 offset[glyphcount] = swf_GetU16(tag); // fontcodeoffset
304 else
305 offset[glyphcount] = tag->pos;
306 }
307 for (t = 0; t < glyphcount; t++) {
308 swf_SetTagPos(tag, offset[t]+offset_start);
309 swf_GetSimpleShape(tag, &(font->glyph[t].shape));
310 }
311
312 if(glyphcount)
313 swf_SetTagPos(tag, offset[glyphcount]+offset_start);
314
315 free(offset);
316
317 maxcode = 0;
318 for (t = 0; t < glyphcount; t++) {
319 int code;
320 if (flags1 & 4) // wide codes (always on for definefont3)
321 code = swf_GetU16(tag);
322 else
323 code = swf_GetU8(tag);
324 font->glyph2ascii[t] = code;
325 if (code > maxcode)
326 maxcode = code;
327 }
328 maxcode++;
329 if (maxcode < 256)
330 maxcode = 256;
331 font->maxascii = maxcode;
332 font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
333 memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
334 for (t = 0; t < glyphcount; t++) {
335 font->ascii2glyph[font->glyph2ascii[t]] = t;
336 }
337
338 if (flags1 & 128) { // has layout
339 U16 kerningcount;
340 font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
341 font->layout->ascent = swf_GetU16(tag);
342 font->layout->descent = swf_GetU16(tag);
343 font->layout->leading = swf_GetU16(tag);
344 for (t = 0; t < glyphcount; t++) {
345 S16 advance = swf_GetS16(tag);
346 font->glyph[t].advance = advance;
347 }
348 font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
349 for (t = 0; t < glyphcount; t++) {
350 swf_ResetReadBits(tag);
351 swf_GetRect(tag, &font->layout->bounds[t]);
352 SRECT b = font->layout->bounds[t];
353 if((b.xmin|b.xmax|b.ymin|b.ymax) == 0) {
354 // recalculate bounding box
355 SHAPE2 *shape2 = swf_ShapeToShape2(font->glyph[t].shape);
356 font->layout->bounds[t] = swf_GetShapeBoundingBox(shape2);
357 swf_Shape2Free(shape2);free(shape2);
358 }
359 }
360
361 kerningcount = swf_GetU16(tag);
362 font->layout->kerningcount = kerningcount;
363
364 font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
365 if (kerningcount) {
366 font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
367 for (t = 0; t < kerningcount; t++) {
368 if (flags1 & 4) { // wide codes
369 font->layout->kerning[t].char1 = swf_GetU16(tag);
370 font->layout->kerning[t].char2 = swf_GetU16(tag);
371 } else {
372 font->layout->kerning[t].char1 = swf_GetU8(tag);
373 font->layout->kerning[t].char2 = swf_GetU8(tag);
374 }
375 font->layout->kerning[t].adjustment = swf_GetS16(tag);
376 }
377 }
378 }
379 return font->id;
380 }
381
swf_FontExtract_DefineFontAlignZones(int id,SWFFONT * font,TAG * tag)382 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
383 {
384 U16 fid;
385 swf_SetTagPos(tag, 0);
386 fid = swf_GetU16(tag);
387
388 if (fid == id) {
389 font->alignzone_flags = swf_GetU8(tag);
390 font->alignzones = rfx_calloc(sizeof(ALIGNZONE)*font->numchars);
391 int i=0;
392 while(tag->pos < tag->len) {
393 if(i>=font->numchars)
394 break;
395 int nr = swf_GetU8(tag); // should be 2
396 if(nr!=1 && nr!=2) {
397 fprintf(stderr, "rfxswf: Can't parse alignzone tags with %d zones", nr);
398 break;
399 }
400 U16 x = swf_GetU16(tag);
401 U16 y = swf_GetU16(tag);
402 U16 dx = (nr==2)?swf_GetU16(tag):0xffff;
403 U16 dy = (nr==2)?swf_GetU16(tag):0xffff;
404 U8 xy = swf_GetU8(tag);
405
406 #ifdef DEBUG_RFXSWF
407 if((!(xy&1) && (x!=0 || (dx!=0 && dx!=0xffff))) ||
408 (!(xy&2) && (y!=0 || (dy!=0 && dy!=0xffff)))) {
409 fprintf(stderr, "Warning: weird combination of alignzone bits and values (%d x:%04x-%04x y:%04x-%04x)\n", xy,
410 x,dx,y,dy);
411 }
412 #endif
413 if(!(xy&1)) {
414 x = 0xffff;
415 dx = 0xffff;
416 } else if(!(xy&2)) {
417 y = 0xffff;
418 dy = 0xffff;
419 }
420 font->alignzones[i].x = x;
421 font->alignzones[i].y = y;
422 font->alignzones[i].dx = dx;
423 font->alignzones[i].dy = dy;
424 i++;
425 }
426 }
427 return id;
428 }
429
430
431 #define FEDTJ_PRINT 0x01
432 #define FEDTJ_MODIFY 0x02
433 #define FEDTJ_CALLBACK 0x04
434
435 static int
swf_FontExtract_DefineTextCallback(int id,SWFFONT * f,TAG * t,int jobs,void (* callback)(void * self,int * chars,int * xpos,int nr,int fontid,int fontsize,int xstart,int ystart,RGBA * color),void * self)436 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
437 void (*callback) (void *self,
438 int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
439 {
440 U16 cid;
441 SRECT r;
442 MATRIX m;
443 U8 gbits, abits;
444 int fid = -1;
445 RGBA color;
446 int x = 0, y = 0;
447 int fontsize = 0;
448
449 memset(&color, 0, sizeof(color));
450
451 swf_SetTagPos(t, 0);
452
453 cid = swf_GetU16(t);
454 swf_GetRect(t, &r);
455 swf_GetMatrix(t, &m);
456 gbits = swf_GetU8(t);
457 abits = swf_GetU8(t);
458
459 while (1) {
460 int flags, num;
461 flags = swf_GetU8(t);
462 if (!flags)
463 break;
464
465 if (flags & TF_TEXTCONTROL) {
466 if (flags & TF_HASFONT)
467 fid = swf_GetU16(t);
468 if (flags & TF_HASCOLOR) {
469 color.r = swf_GetU8(t); // rgb
470 color.g = swf_GetU8(t);
471 color.b = swf_GetU8(t);
472 if (swf_GetTagID(t) == ST_DEFINETEXT2)
473 color.a = swf_GetU8(t);
474 else
475 color.a = 255;
476 }
477 if (flags & TF_HASXOFFSET)
478 x = swf_GetS16(t);
479 if (flags & TF_HASYOFFSET)
480 y = swf_GetS16(t);
481 if (flags & TF_HASFONT)
482 fontsize = swf_GetU16(t);
483 }
484
485 num = swf_GetU8(t);
486 if (!num)
487 break;
488
489 {
490 int i;
491 int buf[256];
492 int advance[256];
493 int xpos = 0;
494 for (i = 0; i < num; i++) {
495 int glyph;
496 int adv = 0;
497 advance[i] = xpos;
498 glyph = swf_GetBits(t, gbits);
499 adv = swf_GetBits(t, abits);
500 xpos += adv;
501
502 if (id == fid) {
503 if (jobs & FEDTJ_PRINT) {
504 int code = f->glyph2ascii[glyph];
505 printf("%lc", code);
506 }
507 if (jobs & FEDTJ_MODIFY)
508 f->glyph[glyph].advance = adv * 20; //?
509 }
510
511 buf[i] = glyph;
512 }
513 if ((id == fid) && (jobs & FEDTJ_PRINT))
514 printf("\n");
515 if (jobs & FEDTJ_CALLBACK)
516 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
517 x += xpos;
518 }
519 }
520
521 return id;
522 }
523
swf_ParseDefineText(TAG * tag,void (* callback)(void * self,int * chars,int * xpos,int nr,int fontid,int fontsize,int xstart,int ystart,RGBA * color),void * self)524 int swf_ParseDefineText(TAG * tag,
525 void (*callback) (void *self, int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
526 {
527 return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
528 }
529
swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)530 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
531 {
532 return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
533 }
534
535 typedef struct _usagetmp {
536 SWFFONT*font;
537 int lastx,lasty;
538 int last;
539 } usagetmp_t;
updateusage(void * self,int * chars,int * xpos,int nr,int fontid,int fontsize,int xstart,int ystart,RGBA * color)540 static void updateusage(void *self, int *chars, int *xpos, int nr,
541 int fontid, int fontsize, int xstart, int ystart, RGBA * color)
542 {
543 usagetmp_t*u = (usagetmp_t*)self;
544 if(!u->font->use) {
545 swf_FontInitUsage(u->font);
546 }
547 if(fontid!=u->font->id)
548 return;
549
550 int t;
551 for(t=0;t<nr;t++) {
552 int x=xpos[t];
553 int y=ystart;
554 int c = chars[t];
555 if(c<0 || c>u->font->numchars)
556 continue;
557 swf_FontUseGlyph(u->font, c, fontsize);
558 if(u->lasty == y && x>=u->lastx-200 && abs(u->lastx-x)<200 &&
559 u->last!=c && !swf_ShapeIsEmpty(u->font->glyph[u->last].shape) &&
560 !swf_ShapeIsEmpty(u->font->glyph[c].shape))
561 {
562 swf_FontUsePair(u->font, u->last, c);
563 }
564 u->lasty = y;
565 /* FIXME: do we still need to divide advance by 20 for definefont3? */
566 u->lastx = x + (u->font->glyph[c].advance*fontsize/20480);
567 u->last = c;
568 }
569 }
570
swf_FontUpdateUsage(SWFFONT * f,TAG * tag)571 void swf_FontUpdateUsage(SWFFONT*f, TAG* tag)
572 {
573 usagetmp_t u;
574 u.font = f;
575 u.lastx = -0x80000000;
576 u.lasty = -0x80000000;
577 u.last = 0;
578 swf_ParseDefineText(tag, updateusage, &u);
579 }
580
swf_FontExtract(SWF * swf,int id,SWFFONT ** font)581 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
582 {
583 TAG *t;
584 SWFFONT *f;
585
586 if ((!swf) || (!font))
587 return -1;
588
589 f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
590
591 t = swf->firstTag;
592
593 while (t) {
594 int nid = 0;
595 switch (swf_GetTagID(t)) {
596 case ST_DEFINEFONT:
597 nid = swf_FontExtract_DefineFont(id, f, t);
598 break;
599
600 case ST_DEFINEFONT2:
601 case ST_DEFINEFONT3:
602 nid = swf_FontExtract_DefineFont2(id, f, t);
603 break;
604
605 case ST_DEFINEFONTALIGNZONES:
606 nid = swf_FontExtract_DefineFontAlignZones(id, f, t);
607 break;
608
609 case ST_DEFINEFONTINFO:
610 case ST_DEFINEFONTINFO2:
611 nid = swf_FontExtract_DefineFontInfo(id, f, t);
612 break;
613
614 case ST_DEFINETEXT:
615 case ST_DEFINETEXT2:
616 if(!f->layout) {
617 nid = swf_FontExtract_DefineText(id, f, t, FEDTJ_MODIFY);
618 }
619 if(f->version>=3 && f->layout)
620 swf_FontUpdateUsage(f, t);
621 break;
622
623 case ST_GLYPHNAMES:
624 nid = swf_FontExtract_GlyphNames(id, f, t);
625 break;
626 }
627 if (nid > 0)
628 id = nid;
629 t = swf_NextTag(t);
630 }
631 if (f->id != id) {
632 rfx_free(f);
633 f = 0;
634 }
635 font[0] = f;
636 return 0;
637 }
638
swf_FontSetID(SWFFONT * f,U16 id)639 int swf_FontSetID(SWFFONT * f, U16 id)
640 {
641 if (!f)
642 return -1;
643 f->id = id;
644 return 0;
645 }
646
swf_LayoutFree(SWFLAYOUT * l)647 void swf_LayoutFree(SWFLAYOUT * l)
648 {
649 if (l) {
650 if (l->kerning)
651 rfx_free(l->kerning);
652 l->kerning = NULL;
653 if (l->bounds)
654 rfx_free(l->bounds);
655 l->bounds = NULL;
656 }
657 rfx_free(l);
658 }
659
660
font_freeglyphnames(SWFFONT * f)661 static void font_freeglyphnames(SWFFONT*f)
662 {
663 if (f->glyphnames)
664 {
665 int t;
666 for (t = 0; t < f->numchars; t++)
667 {
668 if (f->glyphnames[t])
669 {
670 rfx_free(f->glyphnames[t]);
671 f->glyphnames[t] = 0;
672 }
673 }
674 rfx_free(f->glyphnames);
675 f->glyphnames = 0;
676 }
677 }
font_freeusage(SWFFONT * f)678 static void font_freeusage(SWFFONT*f)
679 {
680 if (f->use) {
681 if(f->use->chars) {
682 rfx_free(f->use->chars);f->use->chars = 0;
683 }
684 if(f->use->neighbors) {
685 rfx_free(f->use->neighbors);f->use->neighbors = 0;
686 }
687 if(f->use->neighbors_hash) {
688 rfx_free(f->use->neighbors_hash);f->use->neighbors_hash = 0;
689 }
690 rfx_free(f->use); f->use = 0;
691 }
692 }
font_freelayout(SWFFONT * f)693 static void font_freelayout(SWFFONT*f)
694 {
695 if (f->layout) {
696 swf_LayoutFree(f->layout);
697 f->layout = 0;
698 }
699 }
font_freename(SWFFONT * f)700 static void font_freename(SWFFONT*f)
701 {
702 if (f->name) {
703 rfx_free(f->name);
704 f->name = 0;
705 }
706 }
707
swf_FontReduce_old(SWFFONT * f)708 int swf_FontReduce_old(SWFFONT * f)
709 {
710 int i, j;
711 int max_unicode = 0;
712 if ((!f) || (!f->use) || f->use->is_reduced)
713 return -1;
714
715 j = 0;
716
717 for (i = 0; i < f->numchars; i++) {
718 if (f->glyph[i].shape && f->use->chars[i]) {
719 f->glyph2ascii[j] = f->glyph2ascii[i];
720 f->glyph[j] = f->glyph[i];
721 f->use->chars[i] = j;
722 j++;
723 } else {
724 f->glyph2ascii[i] = 0;
725 if(f->glyph[i].shape) {
726 swf_ShapeFree(f->glyph[i].shape);
727 f->glyph[i].shape = 0;
728 f->glyph[i].advance = 0;
729 }
730 f->use->chars[i] = -1;
731 j++; //TODO: remove
732 }
733 }
734 for (i = 0; i < f->maxascii; i++) {
735 if(f->use->chars[f->ascii2glyph[i]]<0) {
736 f->ascii2glyph[i] = -1;
737 } else {
738 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
739 max_unicode = i;
740 }
741 }
742 f->maxascii = max_unicode;
743 f->use->is_reduced = 1;
744 f->numchars = j;
745 font_freelayout(f);
746 font_freeglyphnames(f);
747 font_freename(f);
748 return j;
749 }
750
swf_FontReduce_swfc(SWFFONT * f)751 int swf_FontReduce_swfc(SWFFONT * f)
752 {
753 int i, j;
754 int max_unicode = 0;
755 if ((!f) || (!f->use) || f->use->is_reduced)
756 return -1;
757
758 font_freeglyphnames(f);
759
760 j = 0;
761 for (i = 0; i < f->numchars; i++) {
762 if (f->glyph[i].shape && f->use->chars[i]) {
763 f->glyph2ascii[j] = f->glyph2ascii[i];
764 if (f->layout)
765 f->layout->bounds[j] = f->layout->bounds[i];
766 f->glyph[j] = f->glyph[i];
767 f->use->chars[i] = j;
768 j++;
769 } else {
770 f->glyph2ascii[i] = 0;
771 if(f->glyph[i].shape) {
772 swf_ShapeFree(f->glyph[i].shape);
773 f->glyph[i].shape = 0;
774 f->glyph[i].advance = 0;
775 }
776 f->use->chars[i] = -1;
777 }
778 }
779 f->use->used_glyphs = j;
780 for (i = 0; i < f->maxascii; i++) {
781 if(f->ascii2glyph[i] > -1) {
782 if (f->use->chars[f->ascii2glyph[i]]<0) {
783 f->use->chars[f->ascii2glyph[i]] = 0;
784 f->ascii2glyph[i] = -1;
785 } else {
786 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
787 f->use->chars[f->ascii2glyph[i]] = 1;
788 max_unicode = i + 1;
789 }
790 }
791 }
792 f->maxascii = max_unicode;
793 f->use->is_reduced = 1;
794 f->numchars = j;
795 font_freename(f);
796 return j;
797 }
798
swf_FontReduce(SWFFONT * f)799 int swf_FontReduce(SWFFONT * f)
800 {
801 int i;
802 int max_unicode = 0;
803 int max_glyph = 0;
804 if ((!f) || (!f->use) || f->use->is_reduced)
805 return -1;
806
807 font_freelayout(f);
808 font_freeglyphnames(f);
809
810 f->use->used_glyphs= 0;
811 for (i = 0; i < f->numchars; i++) {
812 if(!f->use->chars[i]) {
813 if(f->glyph2ascii) {
814 f->glyph2ascii[i] = 0;
815 }
816 if(f->glyph[i].shape) {
817 swf_ShapeFree(f->glyph[i].shape);
818 f->glyph[i].shape = 0;
819 f->glyph[i].advance = 0;
820 }
821 // f->use->used_glyphs++;
822 } else {
823 f->use->used_glyphs++;
824 max_glyph = i+1;
825 }
826 }
827 for (i = 0; i < f->maxascii; i++) {
828 if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
829 if(f->ascii2glyph) {
830 f->ascii2glyph[i] = -1;
831 }
832 } else {
833 max_unicode = i+1;
834 }
835 }
836 f->maxascii = max_unicode;
837 f->numchars = max_glyph;
838 font_freename(f);
839 return 0;
840 }
841
842 static SWFFONT* font_to_sort;
cmp_chars(const void * a,const void * b)843 int cmp_chars(const void*a, const void*b)
844 {
845 int x = *(const int*)a;
846 int y = *(const int*)b;
847 return 0;
848 }
849
swf_FontSort(SWFFONT * font)850 void swf_FontSort(SWFFONT * font)
851 {
852 int i, j;
853 int *newplace;
854 int *newpos;
855 if (!font)
856 return;
857
858 newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
859
860 for (i = 0; i < font->numchars; i++) {
861 newplace[i] = i;
862 }
863 //qsort(newplace, sizeof(newplace[0]), font->numchars, cmp_chars);
864
865 for (i = 0; i < font->numchars; i++)
866 for (j = 0; j < i; j++) {
867 if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
868 int n1, n2;
869 char *c1, *c2;
870 SWFGLYPH g1, g2;
871 SRECT r1, r2;
872 n1 = newplace[i];
873 n2 = newplace[j];
874 newplace[j] = n1;
875 newplace[i] = n2;
876 n1 = font->glyph2ascii[i];
877 n2 = font->glyph2ascii[j];
878 font->glyph2ascii[j] = n1;
879 font->glyph2ascii[i] = n2;
880 g1 = font->glyph[i];
881 g2 = font->glyph[j];
882 font->glyph[j] = g1;
883 font->glyph[i] = g2;
884 if (font->glyphnames) {
885 c1 = font->glyphnames[i];
886 c2 = font->glyphnames[j];
887 font->glyphnames[j] = c1;
888 font->glyphnames[i] = c2;
889 }
890 if (font->layout) {
891 r1 = font->layout->bounds[i];
892 r2 = font->layout->bounds[j];
893 font->layout->bounds[j] = r1;
894 font->layout->bounds[i] = r2;
895 }
896 }
897 }
898 newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
899 for (i = 0; i < font->numchars; i++) {
900 newpos[newplace[i]] = i;
901 }
902 for (i = 0; i < font->maxascii; i++) {
903 if (font->ascii2glyph[i] >= 0)
904 font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
905 }
906
907 rfx_free(newplace);
908 font->glyph2glyph = newpos;
909 }
910
swf_FontPrepareForEditText(SWFFONT * font)911 void swf_FontPrepareForEditText(SWFFONT * font)
912 {
913 if (!font->layout)
914 swf_FontCreateLayout(font);
915 swf_FontSort(font);
916 }
917
swf_FontInitUsage(SWFFONT * f)918 int swf_FontInitUsage(SWFFONT * f)
919 {
920 if (!f)
921 return -1;
922 if(f->use) {
923 fprintf(stderr, "Usage initialized twice");
924 return -1;
925 }
926 f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE));
927 f->use->smallest_size = 0xffff;
928 f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
929 return 0;
930 }
931
swf_FontClearUsage(SWFFONT * f)932 void swf_FontClearUsage(SWFFONT * f)
933 {
934 if (!f || !f->use)
935 return;
936 rfx_free(f->use->chars); f->use->chars = 0;
937 rfx_free(f->use); f->use = 0;
938 }
939
swf_FontUse(SWFFONT * f,U8 * s)940 int swf_FontUse(SWFFONT * f, U8 * s)
941 {
942 if( (!s))
943 return -1;
944 while (*s) {
945 if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
946 swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
947 s++;
948 }
949 return 0;
950 }
951
swf_FontUseUTF8(SWFFONT * f,const U8 * s,U16 size)952 int swf_FontUseUTF8(SWFFONT * f, const U8 * s, U16 size)
953 {
954 if( (!s))
955 return -1;
956 int ascii;
957 while (*s)
958 {
959 ascii = readUTF8char((U8**)&s);
960 if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
961 swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
962 }
963 return 0;
964 }
965
swf_FontUseAll(SWFFONT * f)966 int swf_FontUseAll(SWFFONT* f)
967 {
968 int i;
969
970 if (!f->use)
971 swf_FontInitUsage(f);
972 for (i = 0; i < f->numchars; i++)
973 f->use->chars[i] = 1;
974 f->use->used_glyphs = f->numchars;
975 return 0;
976 }
977
hash2(int char1,int char2)978 static unsigned hash2(int char1, int char2)
979 {
980 unsigned hash = char1^(char2<<8);
981 hash += (hash << 3);
982 hash ^= (hash >> 11);
983 hash += (hash << 15);
984 return hash;
985 }
hashadd(FONTUSAGE * u,int char1,int char2,int nr)986 static void hashadd(FONTUSAGE*u, int char1, int char2, int nr)
987 {
988 unsigned hash = hash2(char1, char2);
989 while(1) {
990 hash = hash%u->neighbors_hash_size;
991 if(!u->neighbors_hash[hash]) {
992 u->neighbors_hash[hash] = nr+1;
993 return;
994 }
995 hash++;
996 }
997 }
swf_FontUseGetPair(SWFFONT * f,int char1,int char2)998 int swf_FontUseGetPair(SWFFONT * f, int char1, int char2)
999 {
1000 FONTUSAGE*u = f->use;
1001 if(!u || !u->neighbors_hash_size)
1002 return 0;
1003 unsigned hash = hash2(char1, char2);
1004 while(1) {
1005 hash = hash%u->neighbors_hash_size;
1006 int pos = u->neighbors_hash[hash];
1007 if(!pos)
1008 return 0;
1009 if(pos &&
1010 u->neighbors[pos-1].char1 == char1 &&
1011 u->neighbors[pos-1].char2 == char2) {
1012 return pos;
1013 }
1014 hash++;
1015 }
1016
1017 }
swf_FontUsePair(SWFFONT * f,int char1,int char2)1018 void swf_FontUsePair(SWFFONT * f, int char1, int char2)
1019 {
1020 if (!f->use)
1021 swf_FontInitUsage(f);
1022 FONTUSAGE*u = f->use;
1023
1024 if(u->num_neighbors*3 >= u->neighbors_hash_size*2) {
1025 if(u->neighbors_hash) {
1026 free(u->neighbors_hash);
1027 }
1028 u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024;
1029 u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int));
1030 int t;
1031 for(t=0;t<u->num_neighbors;t++) {
1032 hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t);
1033 }
1034 }
1035
1036 int nr = swf_FontUseGetPair(f, char1, char2);
1037 if(!nr) {
1038 if(u->num_neighbors == u->neighbors_size) {
1039 u->neighbors_size += 4096;
1040 u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
1041 }
1042 u->neighbors[u->num_neighbors].char1 = char1;
1043 u->neighbors[u->num_neighbors].char2 = char2;
1044 u->neighbors[u->num_neighbors].num = 1;
1045 hashadd(u, char1, char2, u->num_neighbors);
1046 u->num_neighbors++;
1047 } else {
1048 u->neighbors[nr-1].num++;
1049 }
1050 }
1051
swf_FontUseGlyph(SWFFONT * f,int glyph,U16 size)1052 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
1053 {
1054 if (!f->use)
1055 swf_FontInitUsage(f);
1056 if(glyph < 0 || glyph >= f->numchars)
1057 return -1;
1058 if(!f->use->chars[glyph])
1059 f->use->used_glyphs++;
1060 f->use->chars[glyph] = 1;
1061 if(size && size < f->use->smallest_size)
1062 f->use->smallest_size = size;
1063 return 0;
1064 }
1065
swf_FontSetDefine(TAG * t,SWFFONT * f)1066 int swf_FontSetDefine(TAG * t, SWFFONT * f)
1067 {
1068 U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
1069 int p, i, j;
1070
1071 if ((!t) || (!f))
1072 return -1;
1073 swf_ResetWriteBits(t);
1074 swf_SetU16(t, f->id);
1075
1076 p = 0;
1077 j = 0;
1078 for (i = 0; i < f->numchars; i++)
1079 if (f->glyph[i].shape) {
1080 ofs[j++] = p;
1081 p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
1082 }
1083
1084 for (i = 0; i < j; i++)
1085 swf_SetU16(t, ofs[i] + j * 2);
1086 if (!j) {
1087 fprintf(stderr, "rfxswf: warning: Font is empty\n");
1088 swf_SetU16(t, 0);
1089 }
1090
1091 for (i = 0; i < f->numchars; i++)
1092 if (f->glyph[i].shape)
1093 swf_SetSimpleShape(t, f->glyph[i].shape);
1094
1095 swf_ResetWriteBits(t);
1096 rfx_free(ofs);
1097 return 0;
1098 }
1099
fontSize(SWFFONT * font)1100 static inline int fontSize(SWFFONT * font)
1101 {
1102 int t;
1103 int size = 0;
1104 for (t = 0; t < font->numchars; t++) {
1105 int l = 0;
1106 if(font->glyph[t].shape)
1107 l = (font->glyph[t].shape->bitlen + 7) / 8;
1108 else
1109 l = 8;
1110 size += l + 1;
1111 }
1112 return size + (font->numchars + 1) * 2;
1113 }
1114
swf_FontSetDefine2(TAG * tag,SWFFONT * f)1115 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
1116 {
1117 U8 flags = 0;
1118 int t;
1119 int pos;
1120 swf_SetU16(tag, f->id);
1121
1122 if (f->layout) flags |= 128; // haslayout
1123 if (f->numchars > 256)
1124 flags |= 4; // widecodes
1125 if (f->style & FONT_STYLE_BOLD)
1126 flags |= 1; // bold
1127 if (f->style & FONT_STYLE_ITALIC)
1128 flags |= 2; // italic
1129 if (f->maxascii >= 256)
1130 flags |= 4; //wide codecs
1131 if (fontSize(f) > 65535)
1132 flags |= 8; //wide offsets
1133 flags |= 8 | 4; //FIXME: the above check doesn't work
1134
1135 if (f->encoding & FONT_ENCODING_ANSI)
1136 flags |= 16; // ansi
1137 if (f->encoding & FONT_ENCODING_UNICODE)
1138 flags |= 32; // unicode
1139 if (f->encoding & FONT_ENCODING_SHIFTJIS)
1140 flags |= 64; // shiftjis
1141
1142 swf_SetU8(tag, flags);
1143 swf_SetU8(tag, 0); //reserved flags
1144 if (f->name) {
1145 /* font name */
1146 swf_SetU8(tag, strlen((const char*)f->name)+1);
1147 swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1148 } else {
1149 /* font name (="") */
1150 swf_SetU8(tag, 1);
1151 swf_SetU8(tag, 0);
1152 }
1153 /* number of glyphs */
1154 swf_SetU16(tag, f->numchars);
1155 /* font offset table */
1156 pos = tag->len;
1157 for (t = 0; t <= f->numchars; t++) {
1158 if (flags & 8)
1159 swf_SetU32(tag, /* fontoffset */ 0); /*placeholder */
1160 else
1161 swf_SetU16(tag, /* fontoffset */ 0); /*placeholder */
1162 }
1163
1164 for (t = 0; t <= f->numchars; t++) {
1165 if (flags & 8) {
1166 tag->data[pos + t * 4] = (tag->len - pos);
1167 tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1168 tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1169 tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1170 } else {
1171 if (tag->len - pos > 65535) {
1172 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1173 exit(1);
1174 }
1175 tag->data[pos + t * 2] = (tag->len - pos);
1176 tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1177 }
1178 if (t < f->numchars) {
1179 if(f->glyph[t].shape) {
1180 swf_SetSimpleShape(tag, f->glyph[t].shape);
1181 } else {
1182 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1183 }
1184 }
1185 }
1186
1187
1188 /* font code table */
1189 for (t = 0; t < f->numchars; t++) {
1190 if (flags & 4) { /* wide codes */
1191 if(f->glyph2ascii[t]) {
1192 swf_SetU16(tag, f->glyph2ascii[t]);
1193 } else {
1194 swf_SetU16(tag, 0);
1195 }
1196 } else {
1197 if(f->glyph2ascii[t]) {
1198 swf_SetU8(tag, f->glyph2ascii[t]);
1199 } else {
1200 swf_SetU8(tag, 0);
1201 }
1202 }
1203 }
1204
1205 if (f->layout) {
1206 swf_SetU16(tag, f->layout->ascent);
1207 swf_SetU16(tag, f->layout->descent);
1208 swf_SetU16(tag, 0); // flash ignores leading
1209
1210 for (t = 0; t < f->numchars; t++)
1211 swf_SetU16(tag, f->glyph[t].advance);
1212 for (t = 0; t < f->numchars; t++) {
1213 swf_ResetWriteBits(tag);
1214 /* not used by flash, so leave this empty */
1215 SRECT b = {0,0,0,0};
1216 swf_SetRect(tag, &b);
1217 }
1218 swf_SetU16(tag, f->layout->kerningcount);
1219 for (t = 0; t < f->layout->kerningcount; t++) {
1220 if (flags & 4) { /* wide codes */
1221 swf_SetU16(tag, f->layout->kerning[t].char1);
1222 swf_SetU16(tag, f->layout->kerning[t].char2);
1223 } else {
1224 swf_SetU8(tag, f->layout->kerning[t].char1);
1225 swf_SetU8(tag, f->layout->kerning[t].char2);
1226 }
1227 swf_SetU16(tag, f->layout->kerning[t].adjustment);
1228 }
1229 }
1230 return 0;
1231 }
1232
swf_FontAddLayout(SWFFONT * f,int ascent,int descent,int leading)1233 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1234 {
1235 f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1236 f->layout->ascent = ascent;
1237 f->layout->descent = descent;
1238 f->layout->leading = leading;
1239 f->layout->kerningcount = 0;
1240 f->layout->kerning = 0;
1241 f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1242 }
1243
swf_FontSetInfo(TAG * t,SWFFONT * f)1244 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1245 {
1246 int l, i;
1247 U8 wide = 0;
1248 U8 flags = 0;
1249 if ((!t) || (!f))
1250 return -1;
1251 swf_ResetWriteBits(t);
1252 swf_SetU16(t, f->id);
1253 l = f->name ? strlen((const char *)f->name) : 0;
1254 if (l > 255)
1255 l = 255;
1256 swf_SetU8(t, l);
1257 if (l)
1258 swf_SetBlock(t, f->name, l);
1259 if (f->numchars >= 256)
1260 wide = 1;
1261
1262 if (f->style & FONT_STYLE_BOLD)
1263 flags |= 2;
1264 if (f->style & FONT_STYLE_ITALIC)
1265 flags |= 4;
1266 if (f->style & FONT_ENCODING_ANSI)
1267 flags |= 8;
1268 if (f->style & FONT_ENCODING_SHIFTJIS)
1269 flags |= 16;
1270 if (f->style & FONT_ENCODING_UNICODE)
1271 flags |= 32;
1272
1273 swf_SetU8(t, (flags & 0xfe) | wide);
1274
1275 for (i = 0; i < f->numchars; i++) {
1276 if (f->glyph[i].shape) {
1277 int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1278 wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1279 }
1280 }
1281
1282 return 0;
1283 }
1284
swf_TextPrintDefineText(TAG * t,SWFFONT * f)1285 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1286 {
1287 int id = swf_GetTagID(t);
1288 if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1289 swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1290 else
1291 return -1;
1292 return 0;
1293 }
1294
font_freealignzones(SWFFONT * f)1295 static void font_freealignzones(SWFFONT * f)
1296 {
1297 if(f->alignzones)
1298 free(f->alignzones);
1299 f->alignzones = 0;
1300 }
1301
swf_FontFree(SWFFONT * f)1302 void swf_FontFree(SWFFONT * f)
1303 {
1304 int i;
1305 if (!f)
1306 return;
1307
1308 if (f->glyph)
1309 {
1310 for (i = 0; i < f->numchars; i++)
1311 if (f->glyph[i].shape)
1312 {
1313 swf_ShapeFree(f->glyph[i].shape);
1314 f->glyph[i].shape = NULL;
1315 }
1316 rfx_free(f->glyph);
1317 f->glyph = NULL;
1318 }
1319 if (f->ascii2glyph)
1320 {
1321 rfx_free(f->ascii2glyph);
1322 f->ascii2glyph = NULL;
1323 }
1324 if (f->glyph2ascii)
1325 {
1326 rfx_free(f->glyph2ascii);
1327 f->glyph2ascii = NULL;
1328 }
1329 if (f->glyph2glyph) {
1330 rfx_free(f->glyph2glyph);
1331 f->glyph2glyph = NULL;
1332 }
1333 font_freename(f);
1334 font_freelayout(f);
1335 font_freeglyphnames(f);
1336 font_freeusage(f);
1337 font_freealignzones(f);
1338
1339 rfx_free(f);
1340 }
1341
swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,int x,int y)1342 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1343 {
1344 U8 flags;
1345 if (!t)
1346 return -1;
1347
1348 flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1349 | (y ? TF_HASYOFFSET : 0);
1350
1351 swf_SetU8(t, flags);
1352 if (font)
1353 swf_SetU16(t, font->id);
1354 if (color) {
1355 if (swf_GetTagID(t) == ST_DEFINETEXT2)
1356 swf_SetRGBA(t, color);
1357 else
1358 swf_SetRGB(t, color);
1359 }
1360 if (x) {
1361 if(x != SET_TO_ZERO) {
1362 if(x>32767 || x<-32768)
1363 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1364 swf_SetS16(t, x);
1365 } else {
1366 swf_SetS16(t, 0);
1367 }
1368 }
1369 if (y) {
1370 if(y != SET_TO_ZERO) {
1371 if(y>32767 || y<-32768)
1372 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1373 swf_SetS16(t, y);
1374 } else {
1375 swf_SetS16(t, 0);
1376 }
1377 }
1378 if (font)
1379 swf_SetU16(t, size);
1380
1381 return 0;
1382 }
1383
swf_TextCountBits2(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits,char * encoding)1384 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1385 {
1386 U16 g, a;
1387 char utf8 = 0;
1388 if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1389 return -1;
1390 g = a = 0;
1391
1392 if (!strcmp(encoding, "UTF8"))
1393 utf8 = 1;
1394 else if (!strcmp(encoding, "iso-8859-1"))
1395 utf8 = 0;
1396 else
1397 fprintf(stderr, "Unknown encoding: %s", encoding);
1398
1399 while (*s) {
1400 int glyph = -1, c;
1401
1402 if (!utf8)
1403 c = *s++;
1404 else
1405 c = readUTF8char(&s);
1406
1407 if (c < font->maxascii)
1408 glyph = font->ascii2glyph[c];
1409 if (glyph >= 0) {
1410 g = swf_CountUBits(glyph, g);
1411 a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1412 }
1413 }
1414
1415 if (gbits)
1416 gbits[0] = (U8) g;
1417 if (abits)
1418 abits[0] = (U8) a;
1419 return 0;
1420 }
1421
swf_TextSetCharRecord2(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits,char * encoding)1422 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1423 {
1424 int l = 0, pos;
1425 char utf8 = 0;
1426
1427 if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1428 return -1;
1429
1430 if (!strcmp(encoding, "UTF8"))
1431 utf8 = 1;
1432 else if (!strcmp(encoding, "iso-8859-1"))
1433 utf8 = 0;
1434 else
1435 fprintf(stderr, "Unknown encoding: %s", encoding);
1436
1437 pos = t->len;
1438 swf_SetU8(t, l); //placeholder
1439
1440 while (*s) {
1441 int g = -1, c;
1442
1443 if (!utf8)
1444 c = *s++;
1445 else
1446 c = readUTF8char(&s);
1447
1448 if (c < font->maxascii)
1449 g = font->ascii2glyph[c];
1450 if (g >= 0) {
1451 swf_SetBits(t, g, gbits);
1452 swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1453 l++;
1454 /* We split into 127 characters per text field.
1455 We could do 255, by the (formerly wrong) flash specification,
1456 but some SWF parsing code out there still assumes that char blocks
1457 are at max 127 characters, and it would save only a few bits.
1458 */
1459 if (l == 0x7f)
1460 break;
1461 }
1462 }
1463
1464 PUT8(&t->data[pos], l);
1465
1466 swf_ResetWriteBits(t);
1467 return 0;
1468 }
1469
swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)1470 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1471 {
1472 return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1473 }
1474
swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)1475 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1476 {
1477 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1478 }
1479
swf_TextCountBitsUTF8(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)1480 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1481 {
1482 return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1483 }
1484
swf_TextSetCharRecordUTF8(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)1485 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1486 {
1487 return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1488 }
1489
swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)1490 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1491 {
1492 U32 res = 0;
1493
1494 if (font && s) {
1495 while (s[0]) {
1496 int g = -1;
1497 if (*s < font->maxascii)
1498 g = font->ascii2glyph[*s];
1499 if (g >= 0)
1500 res += font->glyph[g].advance / 20;
1501 s++;
1502 }
1503 if (scale)
1504 res = (res * scale) / 100;
1505 }
1506 return res;
1507 }
1508
swf_TextCalculateBBoxUTF8(SWFFONT * font,U8 * s,int scale)1509 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1510 {
1511 int xpos = 0;
1512 int ypos = 0;
1513 SRECT r;
1514 swf_GetRect(0, &r);
1515 while (*s) {
1516 int c = readUTF8char(&s);
1517 if(c==13 || c==10) {
1518 if(s[0] == 10) {
1519 s++;
1520 }
1521 xpos=0;
1522 ypos+=font->layout->leading;
1523 continue;
1524 }
1525 if (c < font->maxascii) {
1526 int g = font->ascii2glyph[c];
1527 if (g >= 0) {
1528 SRECT rn = font->layout->bounds[g];
1529 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1530 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1531 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1532 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1533 swf_ExpandRect2(&r, &rn);
1534 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1535 }
1536 }
1537 }
1538 return r;
1539 }
1540
1541
swf_ReadFont(const char * filename)1542 SWFFONT *swf_ReadFont(const char *filename)
1543 {
1544 int f;
1545 SWF swf;
1546 if (!filename)
1547 return 0;
1548 f = open(filename, O_RDONLY|O_BINARY);
1549
1550 if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1551 fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1552 close(f);
1553 return 0;
1554 } else {
1555 SWFFONT *font;
1556 close(f);
1557 if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1558 return 0;
1559 swf_FreeTags(&swf);
1560 return font;
1561 }
1562 }
1563
swf_SetEditText(TAG * tag,U16 flags,SRECT r,const char * text,RGBA * color,int maxlength,U16 font,U16 height,EditTextLayout * layout,const char * variable)1564 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, const char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, const char *variable)
1565 {
1566 swf_SetRect(tag, &r);
1567 swf_ResetWriteBits(tag);
1568
1569 flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1570 if (text)
1571 flags |= ET_HASTEXT;
1572 if (color)
1573 flags |= ET_HASTEXTCOLOR;
1574 if (maxlength)
1575 flags |= ET_HASMAXLENGTH;
1576 if (font)
1577 flags |= ET_HASFONT;
1578 if (layout)
1579 flags |= ET_HASLAYOUT;
1580
1581 swf_SetBits(tag, flags, 16);
1582
1583 if (flags & ET_HASFONT) {
1584 swf_SetU16(tag, font); //font
1585 swf_SetU16(tag, height); //fontheight
1586 }
1587 if (flags & ET_HASTEXTCOLOR) {
1588 swf_SetRGBA(tag, color);
1589 }
1590 if (flags & ET_HASMAXLENGTH) {
1591 swf_SetU16(tag, maxlength); //maxlength
1592 }
1593 if (flags & ET_HASLAYOUT) {
1594 swf_SetU8(tag, layout->align); //align
1595 swf_SetU16(tag, layout->leftmargin); //left margin
1596 swf_SetU16(tag, layout->rightmargin); //right margin
1597 swf_SetU16(tag, layout->indent); //indent
1598 swf_SetU16(tag, layout->leading); //leading
1599 }
1600 swf_SetString(tag, variable);
1601 if (flags & ET_HASTEXT)
1602 swf_SetString(tag, text);
1603 }
1604
swf_SetDefineText(TAG * tag,SWFFONT * font,RGBA * rgb,const char * text,int scale)1605 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1606 {
1607 SRECT r;
1608 U8 gbits, abits;
1609 U8 *utext = (U8 *) strdup(text);
1610 U8 *upos = utext;
1611 int x = 0, y = 0;
1612 int pos = 0;
1613 int ystep = 0;
1614 if (font->layout) {
1615 r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1616 ystep = font->layout->leading;
1617 } else {
1618 fprintf(stderr, "No layout information- can't compute text bbox accurately");
1619 /* Hm, without layout information, we can't compute a bounding
1620 box. We could call swf_FontCreateLayout to create a layout,
1621 but the caller probably doesn't want us to mess up his font
1622 structure.
1623 */
1624 r.xmin = r.ymin = 0;
1625 r.xmax = r.ymax = 1024 * 20;
1626 ystep = 100;
1627 }
1628
1629 swf_SetRect(tag, &r);
1630
1631 /* The text matrix is pretty boring, as it doesn't apply to
1632 individual characters, but rather whole text objects (or
1633 at least whole char records- haven't tested).
1634 So it can't do anything which we can't already do with
1635 the placeobject tag we use for placing the text on the scene.
1636 */
1637 swf_SetMatrix(tag, 0);
1638
1639 swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1640 swf_SetU8(tag, gbits);
1641 swf_SetU8(tag, abits);
1642
1643 while(*upos) {
1644 U8*next = upos;
1645 int count = 0;
1646
1647 swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y); //scale
1648 x = 0;
1649
1650 while(*next && *next!=13 && *next!=10 && count<127) {
1651 readUTF8char(&next);
1652 count++;
1653 }
1654 if(next[0] == 13 || next[0] == 10) {
1655 x = SET_TO_ZERO;
1656 y += ystep;
1657 }
1658
1659 if(next[0] == 13 && next[1] == 10)
1660 next++;
1661
1662 if(next[0] == 13 || next[0] == 10) {
1663 *next = 0;
1664 next++;
1665 }
1666
1667 /* now set the text params- notice that a font size of
1668 1024 (or 1024*20 for definefont3) means that the glyphs will
1669 be displayed exactly as they would be in/with a defineshape.
1670 This is not documented in the specs.
1671 */
1672
1673 /* set the actual text- notice that we just pass our scale
1674 parameter over, as TextSetCharRecord calculates with
1675 percent, too */
1676 swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1677
1678 upos= next;
1679 }
1680 free(utext);
1681
1682 swf_SetU8(tag, 0);
1683 return r;
1684 }
1685
swf_FontCreateLayout(SWFFONT * f)1686 void swf_FontCreateLayout(SWFFONT * f)
1687 {
1688 S16 leading = 0;
1689 int t;
1690 if (f->layout)
1691 return;
1692 if (!f->numchars)
1693 return;
1694
1695 f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1696 f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1697 f->layout->ascent = 0;
1698 f->layout->descent = 0;
1699
1700 for (t = 0; t < f->numchars; t++) {
1701 SHAPE2 *shape2;
1702 SRECT bbox;
1703 int width;
1704 shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1705 if (!shape2) {
1706 fprintf(stderr, "Shape parse error\n");
1707 exit(1);
1708 }
1709 bbox = swf_GetShapeBoundingBox(shape2);
1710 swf_Shape2Free(shape2);
1711 f->layout->bounds[t] = bbox;
1712
1713 width = (bbox.xmax);
1714
1715 /* The following is a heuristic- it may be that extractfont_DefineText
1716 has already found out some widths for individual characters (from the way
1717 they are used)- we now have to guess whether that width might be possible,
1718 which is the case if it isn't either much too big or much too small */
1719 if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1720 f->glyph[t].advance = width;
1721
1722 if (-bbox.ymin > f->layout->ascent)
1723 f->layout->ascent = -bbox.ymin;
1724 if (bbox.ymax > f->layout->descent)
1725 f->layout->descent = bbox.ymax;
1726 }
1727 }
1728
swf_DrawText(drawer_t * draw,SWFFONT * font,int size,const char * text)1729 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1730 {
1731 U8 *s = (U8 *) text;
1732 int advance = 0;
1733 while (*s) {
1734 SHAPE *shape;
1735 SHAPE2 *shape2;
1736 SHAPELINE *l;
1737 U32 c = readUTF8char(&s);
1738 int g = font->ascii2glyph[c];
1739 shape = font->glyph[g].shape;
1740 if (((int) g) < 0) {
1741 fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1742 continue;
1743 }
1744 shape2 = swf_ShapeToShape2(shape);
1745 l = shape2->lines;
1746 while (l) {
1747 if (l->type == moveTo) {
1748 FPOINT to;
1749 to.x = l->x * size / 100.0 / 20.0 + advance;
1750 to.y = l->y * size / 100.0 / 20.0;
1751 draw->moveTo(draw, &to);
1752 } else if (l->type == lineTo) {
1753 FPOINT to;
1754 to.x = l->x * size / 100.0 / 20.0 + advance;
1755 to.y = l->y * size / 100.0 / 20.0;
1756 draw->lineTo(draw, &to);
1757 } else if (l->type == splineTo) {
1758 FPOINT mid, to;
1759 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1760 mid.y = l->sy * size / 100.0 / 20.0;
1761 to.x = l->x * size / 100.0 / 20.0 + advance;
1762 to.y = l->y * size / 100.0 / 20.0;
1763 draw->splineTo(draw, &mid, &to);
1764 }
1765 l = l->next;
1766 }
1767 swf_Shape2Free(shape2);
1768 advance += font->glyph[g].advance * size / 100.0 / 20.0;
1769 }
1770 }
1771
swf_WriteFont_AS3(SWFFONT * font,char * filename)1772 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1773 {
1774 if(!font->layout)
1775 swf_FontCreateLayout(font);
1776
1777 SWF swf;
1778 memset(&swf, 0, sizeof(SWF));
1779 swf.fileVersion = 9;
1780 swf.frameRate = 0x4000;
1781 swf.movieSize.xmax = 200;
1782 swf.movieSize.ymax = 200;
1783
1784 if(!font->id) font->id=1;
1785
1786 TAG *tag;
1787 swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1788 swf_FontSetDefine2(tag, font);
1789
1790 char*name = font->name?(char*)font->name:"font";
1791
1792 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1793 swf_SetU16(tag, font->id);
1794 swf_SetString(tag, name);
1795 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1796 swf_SetU16(tag, 1);
1797 swf_SetU16(tag, font->id);
1798 swf_SetString(tag, name);
1799 tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1800
1801 tag = swf_InsertTag(tag, ST_END);
1802 swf_SaveSWF(&swf, filename);
1803 swf_FreeTags(&swf);
1804 }
1805
swf_WriteFont(SWFFONT * font,char * filename)1806 void swf_WriteFont(SWFFONT * font, char *filename)
1807 {
1808 if(!font->layout)
1809 swf_FontCreateLayout(font);
1810
1811 char viewer = 1;
1812 U16 id = 1;
1813 U16 depth = 1;
1814
1815 font->id = id++;
1816
1817 SWF swf;
1818 memset(&swf, 0, sizeof(SWF));
1819 swf.fileVersion = 8;
1820 swf.frameRate = 0x4000;
1821 swf.movieSize.xmax = 1024*20;
1822 swf.movieSize.ymax = 768*20;
1823
1824 TAG *tag;
1825 swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1826 swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1827
1828 tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1829 swf_FontSetDefine2(tag, font);
1830
1831 if(font->glyphnames) {
1832 int c;
1833 tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1834 swf_SetU16(tag, font->id);
1835 swf_SetU16(tag, font->numchars);
1836 for (c = 0; c < font->numchars; c++) {
1837 if (font->glyphnames[c])
1838 swf_SetString(tag, font->glyphnames[c]);
1839 else
1840 swf_SetString(tag, "");
1841 }
1842 }
1843
1844 if(viewer)
1845 {
1846 RGBA white = {255,255,255,255};
1847 RGBA black = {255,0,0,0};
1848 RGBA gray50 = {255,128,128,128};
1849 RGBA green = {255,0,255,0};
1850 int t;
1851 SCOORD miny = SCOORD_MAX;
1852 SCOORD maxy = SCOORD_MIN;
1853 double width = 0;
1854 U16 max_advance = 0;
1855 char*flags = rfx_calloc(font->numchars);
1856 double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1857 double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1858 int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1859 for(t=0;t<font->numchars;t++) {
1860 SHAPE*s = font->glyph[t].shape;
1861 SHAPE2*s2 = swf_ShapeToShape2(s);
1862 SRECT r = swf_GetShapeBoundingBox(s2);
1863
1864 // inside a definefont3, everything is 20x the resolution:
1865 double rx1 = r.xmin / 20.0;
1866 double ry1 = r.ymin / 20.0;
1867 double rx2 = r.xmax / 20.0;
1868 double ry2 = r.ymax / 20.0;
1869
1870 xmin[t]= rx1;
1871 xmax[t]= rx2;
1872
1873 if(ry1<miny) {miny=ry1;}
1874 if(ry2>maxy) {maxy=ry2;}
1875 swf_Shape2Free(s2);free(s2);
1876 width += font->glyph[t].advance;
1877 if(font->glyph[t].advance>max_advance)
1878 max_advance = font->glyph[t].advance;
1879 }
1880
1881 if(miny==SCOORD_MAX) miny=maxy=0;
1882 if(miny==maxy) maxy=miny+1;
1883
1884 /* scale the font so that it's 256 pixels high */
1885 double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1886 double overlarge_factor;
1887 int fontsize;
1888 if(scale > 32767) {
1889 fontsize = 32767;
1890 overlarge_factor = scale / 32767.0;
1891 } else {
1892 fontsize = scale;
1893 overlarge_factor = 1.0;
1894 }
1895
1896 int textid = id++;
1897 int spriteid = id++;
1898 SRECT r;
1899 r.xmin = 0;
1900 r.ymin = miny*fontsize/1024;
1901 r.xmax = width*fontsize/20480;
1902 r.ymax = maxy*fontsize/1024;
1903 tag = swf_InsertTag(tag, ST_DEFINETEXT);
1904 swf_SetU16(tag, textid);
1905 swf_SetRect(tag, &r);
1906 swf_SetMatrix(tag, NULL);
1907
1908 U8 abits = 15;
1909 U8 gbits = swf_CountBits(font->numchars, 0);
1910 swf_SetU8(tag, gbits);
1911 swf_SetU8(tag, abits);
1912
1913 RGBA rgb = {255,0,0,0};
1914
1915 swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1916 ActionTAG*array = 0;
1917 double x=0;
1918 array = action_PushString(array, "xpos");
1919 for(t=0;t<font->numchars;t++) {
1920 swf_SetU8(tag, 1);
1921 int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1922 array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1923 x += width * overlarge_factor;
1924 swf_SetBits(tag, t, gbits);
1925 swf_SetBits(tag, width, abits);
1926 swf_SetU8(tag, 128);
1927 }
1928 array = action_PushInt(array, x/20);
1929 array = action_PushInt(array, font->numchars+1);
1930 array = action_InitArray(array);
1931 array = action_SetVariable(array);
1932 swf_SetU8(tag, 0);
1933
1934 if(font->layout) {
1935 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1936 SHAPE* s;
1937 swf_ShapeNew(&s);
1938 int ls = swf_ShapeAddLineStyle(s,20,&white);
1939 int shapeid = id++;
1940 swf_SetU16(tag,shapeid);
1941 SRECT r;
1942 r.xmin = 0;
1943 r.xmax = 1024*20;
1944 r.ymin = 0;
1945 r.ymax = 256*20;
1946 swf_SetRect(tag,&r);
1947 swf_SetShapeHeader(tag,s);
1948 swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1949
1950 /* � and � are good chars to test ascent/descent extend */
1951 int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1952 int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1953
1954 swf_ShapeSetMove(tag,s,0,y1);
1955 swf_ShapeSetLine(tag,s,width,0);
1956 swf_ShapeSetMove(tag,s,0,y2);
1957 swf_ShapeSetLine(tag,s,width,0);
1958
1959 swf_ShapeSetEnd(tag);
1960 swf_ShapeFree(s);
1961 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1962 swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1963 }
1964
1965 /* shapes */
1966
1967 for(t=0;t<font->numchars;t++) {
1968 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1969 SHAPE* s;
1970 swf_ShapeNew(&s);
1971 int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1972 int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1973 int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1974 int shapeid = id++;
1975 swf_SetU16(tag,shapeid);
1976 SRECT r;
1977 r.xmin = 0;
1978 r.xmax = 1024*20;
1979 r.ymin = 0;
1980 r.ymax = 512*20;
1981 swf_SetRect(tag,&r);
1982 swf_SetShapeHeader(tag,s);
1983 swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1984 SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1985 SHAPELINE*l = s2->lines;
1986 int lastx=0,lasty=0;
1987
1988 double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1989 double y1 = -miny*20*scale*2/20480.0;
1990 double scalex = scale*2/20480.0;
1991 double scaley = scale*2/20480.0;
1992
1993 while(l) {
1994 int lx = (l->x)*scalex+x1;
1995 int ly = (l->y)*scaley+y1;
1996 int sx = (l->sx)*scalex+x1;
1997 int sy = (l->sy)*scaley+y1;
1998 if(l->type == moveTo) {
1999 swf_ShapeSetMove(tag,s,lx,ly);
2000 } else if(l->type == lineTo) {
2001 swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
2002 } else if(l->type == splineTo) {
2003 swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
2004 }
2005 lastx = lx;
2006 lasty = ly;
2007 l = l->next;
2008 }
2009
2010 if(font->alignzones) {
2011 ALIGNZONE*zone = &font->alignzones[t];
2012 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
2013 if((zone->x&zone->dx)!=0xffff) {
2014 double x = F16toFloat(zone->x)*20480.0*scalex+x1;
2015 double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
2016 swf_ShapeSetMove(tag,s,x,0);
2017 swf_ShapeSetLine(tag,s,0,1024*20);
2018 swf_ShapeSetMove(tag,s,dx,0);
2019 swf_ShapeSetLine(tag,s,0,1024*20);
2020 }
2021 if((zone->y&zone->dy)!=0xffff) {
2022 double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
2023 double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
2024 swf_ShapeSetMove(tag,s,0,y);
2025 swf_ShapeSetLine(tag,s,1024*20,0);
2026 swf_ShapeSetMove(tag,s,0,dy);
2027 swf_ShapeSetLine(tag,s,1024*20,0);
2028 }
2029 }
2030
2031 swf_ShapeSetEnd(tag);
2032 swf_ShapeFree(s);
2033
2034 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2035 U16 spriteid=id++;
2036 swf_SetU16(tag, spriteid);
2037 swf_SetU16(tag, 1);
2038 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2039 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2040 tag = swf_InsertTag(tag, ST_END);
2041 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2042 MATRIX m;
2043 swf_GetMatrix(0, &m);
2044 m.ty = 20000;
2045 char txt[80];
2046 sprintf(txt, "char%d", font->numchars-t);
2047 swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
2048 }
2049
2050 /* marker */
2051 tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
2052 int shapeid=id++;
2053 RGBA blue = {0xff,0xc0,0xc0,0xff};
2054 swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
2055 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2056 U16 spriteid2=id++;
2057 swf_SetU16(tag, spriteid2);
2058 swf_SetU16(tag, 1);
2059 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2060 swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
2061 tag = swf_InsertTag(tag, ST_END);
2062 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2063 swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
2064
2065 /* textbar */
2066 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2067 swf_SetU16(tag, spriteid);
2068 swf_SetU16(tag, 1);
2069 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2070 MATRIX m;
2071 swf_GetMatrix(0, &m);
2072 m.sx = 65536 * overlarge_factor;
2073 m.sy = 65536 * overlarge_factor;
2074 m.tx = 0;
2075 m.ty = -miny*256*20/(maxy-miny);
2076 swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
2077 tag = swf_InsertTag(tag, ST_END);
2078 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2079 swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
2080
2081 /* marker2 */
2082 RGBA blue2 = {0x80,0x80,0xff,0x80};
2083 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
2084 int shapeid2=id++;
2085 swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
2086 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2087 U16 spriteid3=id++;
2088 swf_SetU16(tag, spriteid3);
2089 swf_SetU16(tag, 1);
2090 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2091 swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
2092 tag = swf_InsertTag(tag, ST_END);
2093 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2094 swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
2095
2096
2097 char*data =
2098 " var mouseListener = new Object();"
2099 " var speed = 0;"
2100 " var myx = 0;"
2101 " var currentMouseOver, currentChar;"
2102 " mouseListener.onMouseDown = function() { "
2103 " eval(\"_root.char\"+currentChar)._y = 20000;"
2104 " currentChar = currentMouseOver;"
2105 " var i = currentMouseOver;"
2106 " eval(\"_root.char\"+i)._y = 256;"
2107 " _root.marker2._yscale=256*100;"
2108 " _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
2109 " _root.marker2._x=xpos[i]+myx;"
2110 " };"
2111 " mouseListener.onMouseMove = function() { "
2112 " if(_ymouse<256) {"
2113 " speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
2114 " } else {"
2115 " speed = 0;"
2116 " }; "
2117 " }; "
2118 " setInterval( function(){ "
2119 " if(_ymouse<256) {"
2120 " var i, x=_xmouse-_root.textbar._x;"
2121 " for(i=xpos.length-1;i>0;i--) {"
2122 " if(x<xpos[i-1]) break;"
2123 " }"
2124 " currentMouseOver = i;"
2125 " _root.marker._yscale=256*100;"
2126 " _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
2127 " _root.marker._x=xpos[i]+myx;"
2128 " _root.textbar._x += 0.05;"
2129 " }"
2130 " if(myx+speed>0) {"
2131 " speed=0;"
2132 " } else if(myx+speed<-xpos[0]+1024) {"
2133 " speed=0;"
2134 " }"
2135 " myx+=speed;"
2136 " _root.textbar._x = myx;"
2137 " _root.marker._x += speed;"
2138 " _root.marker2._x += speed;"
2139 " }, 20);"
2140 " Mouse.addListener(mouseListener);"
2141 ;
2142 ActionTAG* atag = swf_ActionCompile(data, 6);
2143
2144 tag = swf_InsertTag(tag, ST_DOACTION);
2145 swf_ActionSet(tag, array);
2146 swf_ActionSet(tag, atag);
2147 swf_SetU8(tag, 0);
2148 swf_ActionFree(atag);
2149
2150 tag = swf_InsertTag(tag, ST_SHOWFRAME);
2151
2152 free(flags);
2153 free(xmin);
2154 free(xmax);
2155 }
2156
2157 tag = swf_InsertTag(tag, ST_END);
2158
2159 swf.compressed = -1;
2160 swf_SaveSWF(&swf, filename);
2161 swf_FreeTags(&swf);
2162 }
2163