Part of the swftools package.
Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
- Copyright (c) 2003,2004 Matthias Kramm
+ Copyright (c) 2003,2004,2005,2006,2007,2008,2009 Matthias Kramm
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
U32 *offset;
U8 flags1, langcode, namelen;
swf_SetTagPos(tag, 0);
- font->version = 2;
+ font->version = tag->id==ST_DEFINEFONT3?3:2;
fid = swf_GetU16(tag);
if (id && id != fid)
return id;
font->name = (U8 *) rfx_alloc(namelen + 1);
font->name[namelen] = 0;
swf_GetBlock(tag, font->name, namelen);
- font->version = 2;
glyphcount = swf_GetU16(tag);
font->numchars = glyphcount;
for (t = 0; t < glyphcount; t++) {
swf_ResetReadBits(tag);
swf_GetRect(tag, &font->layout->bounds[t]);
+ SRECT b = font->layout->bounds[t];
+ if((b.xmin|b.xmax|b.ymin|b.ymax) == 0) {
+ // recalculate bounding box
+ SHAPE2 *shape2 = swf_ShapeToShape2(font->glyph[t].shape);
+ font->layout->bounds[t] = swf_GetShapeBoundingBox(shape2);
+ swf_Shape2Free(shape2);free(shape2);
+ }
}
kerningcount = swf_GetU16(tag);
return font->id;
}
-static float F16toFloat(U16 x)
-{
- TAG t;
- t.data = (void*)&x;
- t.readBit = 0;
- t.pos = 0;
- t.len = 2;
- return swf_GetF16(&t);
-}
-
-static float floatToF16(float f)
-{
- U16 u = 0;
- TAG t;
- t.data = (void*)&u;
- t.len = 0;
- t.memsize = 2;
- t.writeBit = 0;
- swf_SetF16(&t, f);
- return u;
-}
-
int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
{
U16 fid;
}
int swf_ParseDefineText(TAG * tag,
- void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
+ void (*callback) (void *self, int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
{
return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
}
return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
}
+typedef struct _usagetmp {
+ SWFFONT*font;
+ int lastx,lasty;
+ int last;
+} usagetmp_t;
+static void updateusage(void *self, int *chars, int *xpos, int nr,
+ int fontid, int fontsize, int xstart, int ystart, RGBA * color)
+{
+ usagetmp_t*u = (usagetmp_t*)self;
+ if(!u->font->use) {
+ swf_FontInitUsage(u->font);
+ }
+ if(fontid!=u->font->id)
+ return;
+
+ int t;
+ for(t=0;t<nr;t++) {
+ int x=xpos[t];
+ int y=ystart;
+ int c = chars[t];
+ if(c<0 || c>u->font->numchars)
+ continue;
+ swf_FontUseGlyph(u->font, c, fontsize);
+ if(u->lasty == y && x>=u->lastx-200 && abs(u->lastx-x)<200 &&
+ u->last!=c && !swf_ShapeIsEmpty(u->font->glyph[u->last].shape) &&
+ !swf_ShapeIsEmpty(u->font->glyph[c].shape))
+ {
+ swf_FontUsePair(u->font, u->last, c);
+ }
+ u->lasty = y;
+ /* FIXME: do we still need to divide advance by 20 for definefont3? */
+ u->lastx = x + (u->font->glyph[c].advance*fontsize/20480);
+ u->last = c;
+ }
+}
+
+void swf_FontUpdateUsage(SWFFONT*f, TAG* tag)
+{
+ usagetmp_t u;
+ u.font = f;
+ u.lastx = -0x80000000;
+ u.lasty = -0x80000000;
+ u.last = 0;
+ swf_ParseDefineText(tag, updateusage, &u);
+}
+
int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
{
TAG *t;
case ST_DEFINETEXT:
case ST_DEFINETEXT2:
- nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
+ if(!f->layout) {
+ nid = swf_FontExtract_DefineText(id, f, t, FEDTJ_MODIFY);
+ }
+ if(f->version>=3 && f->layout)
+ swf_FontUpdateUsage(f, t);
break;
case ST_GLYPHNAMES:
if(f->use->chars) {
rfx_free(f->use->chars);f->use->chars = 0;
}
+ if(f->use->neighbors) {
+ rfx_free(f->use->neighbors);f->use->neighbors = 0;
+ }
+ if(f->use->neighbors_hash) {
+ rfx_free(f->use->neighbors_hash);f->use->neighbors_hash = 0;
+ }
rfx_free(f->use); f->use = 0;
}
}
return 0;
}
+static SWFFONT* font_to_sort;
+int cmp_chars(const void*a, const void*b)
+{
+ int x = *(const int*)a;
+ int y = *(const int*)b;
+ return 0;
+}
+
void swf_FontSort(SWFFONT * font)
{
int i, j;
for (i = 0; i < font->numchars; i++) {
newplace[i] = i;
}
+ //qsort(newplace, sizeof(newplace[0]), font->numchars, cmp_chars);
+
for (i = 0; i < font->numchars; i++)
for (j = 0; j < i; j++) {
if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
}
- rfx_free(newpos);
rfx_free(newplace);
+ font->glyph2glyph = newpos;
}
void swf_FontPrepareForEditText(SWFFONT * font)
fprintf(stderr, "Usage initialized twice");
return -1;
}
- f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
- f->use->is_reduced = 0;
- f->use->used_glyphs = 0;
+ f->use = (FONTUSAGE*)rfx_calloc(sizeof(FONTUSAGE));
+ f->use->smallest_size = 0xffff;
f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
- f->use->glyphs_specified = 0;
return 0;
}
return -1;
while (*s) {
if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
- swf_FontUseGlyph(f, f->ascii2glyph[*s]);
+ swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
s++;
}
return 0;
}
-int swf_FontUseUTF8(SWFFONT * f, U8 * s)
+int swf_FontUseUTF8(SWFFONT * f, const U8 * s, U16 size)
{
if( (!s))
return -1;
int ascii;
while (*s)
{
- ascii = readUTF8char(&s);
+ ascii = readUTF8char((U8**)&s);
if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
- swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
+ swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
}
return 0;
}
return 0;
}
-int swf_FontUseGlyph(SWFFONT * f, int glyph)
+static unsigned hash2(int char1, int char2)
+{
+ unsigned hash = char1^(char2<<8);
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+ return hash;
+}
+static void hashadd(FONTUSAGE*u, int char1, int char2, int nr)
+{
+ unsigned hash = hash2(char1, char2);
+ while(1) {
+ hash = hash%u->neighbors_hash_size;
+ if(!u->neighbors_hash[hash]) {
+ u->neighbors_hash[hash] = nr+1;
+ return;
+ }
+ hash++;
+ }
+}
+int swf_FontUseGetPair(SWFFONT * f, int char1, int char2)
+{
+ FONTUSAGE*u = f->use;
+ if(!u || !u->neighbors_hash_size)
+ return 0;
+ unsigned hash = hash2(char1, char2);
+ while(1) {
+ hash = hash%u->neighbors_hash_size;
+ int pos = u->neighbors_hash[hash];
+ if(!pos)
+ return 0;
+ if(pos &&
+ u->neighbors[pos-1].char1 == char1 &&
+ u->neighbors[pos-1].char2 == char2) {
+ return pos;
+ }
+ hash++;
+ }
+
+}
+void swf_FontUsePair(SWFFONT * f, int char1, int char2)
+{
+ if (!f->use)
+ swf_FontInitUsage(f);
+ FONTUSAGE*u = f->use;
+
+ if(u->num_neighbors*3 >= u->neighbors_hash_size*2) {
+ if(u->neighbors_hash) {
+ free(u->neighbors_hash);
+ }
+ u->neighbors_hash_size = u->neighbors_hash_size?u->neighbors_hash_size*2:1024;
+ u->neighbors_hash = rfx_calloc(u->neighbors_hash_size*sizeof(int));
+ int t;
+ for(t=0;t<u->num_neighbors;t++) {
+ hashadd(u, u->neighbors[t].char1, u->neighbors[t].char2, t);
+ }
+ }
+
+ int nr = swf_FontUseGetPair(f, char1, char2);
+ if(!nr) {
+ if(u->num_neighbors == u->neighbors_size) {
+ u->neighbors_size += 4096;
+ u->neighbors = rfx_realloc(u->neighbors, sizeof(SWFGLYPHPAIR)*u->neighbors_size);
+ }
+ u->neighbors[u->num_neighbors].char1 = char1;
+ u->neighbors[u->num_neighbors].char2 = char2;
+ u->neighbors[u->num_neighbors].num = 1;
+ hashadd(u, char1, char2, u->num_neighbors);
+ u->num_neighbors++;
+ } else {
+ u->neighbors[nr-1].num++;
+ }
+}
+
+int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
{
if (!f->use)
swf_FontInitUsage(f);
if(!f->use->chars[glyph])
f->use->used_glyphs++;
f->use->chars[glyph] = 1;
+ if(size && size < f->use->smallest_size)
+ f->use->smallest_size = size;
return 0;
}
if (f->layout) {
swf_SetU16(tag, f->layout->ascent);
swf_SetU16(tag, f->layout->descent);
- swf_SetU16(tag, f->layout->leading);
+ swf_SetU16(tag, 0); // flash ignores leading
+
for (t = 0; t < f->numchars; t++)
swf_SetU16(tag, f->glyph[t].advance);
for (t = 0; t < f->numchars; t++) {
swf_ResetWriteBits(tag);
- swf_SetRect(tag, &f->layout->bounds[t]);
+ /* not used by flash, so leave this empty */
+ SRECT b = {0,0,0,0};
+ swf_SetRect(tag, &b);
}
swf_SetU16(tag, f->layout->kerningcount);
for (t = 0; t < f->layout->kerningcount; t++) {
return 0;
}
-void swf_FontSetAlignZones(TAG*t, SWFFONT *f)
-{
- swf_SetU16(t, f->id);
- swf_SetU8(t, f->alignzone_flags);
- int i;
- for(i=0;i<f->numchars;i++) {
- ALIGNZONE*a = &f->alignzones[i];
- U8 flags = 0;
- if((a->x & a->dx)!=0xffff)
- flags |= 1;
- if((a->y & a->dy)!=0xffff)
- flags |= 2;
- swf_SetU8(t, 2);
- if(flags&1) swf_SetU16(t, a->x); else swf_SetU16(t, 0);
- if(flags&2) swf_SetU16(t, a->y); else swf_SetU16(t, 0);
- if((flags&1) && a->dx!=0xffff) swf_SetU16(t, a->dx); else swf_SetU16(t, 0);
- if((flags&2) && a->dy!=0xffff) swf_SetU16(t, a->dy); else swf_SetU16(t, 0);
- swf_SetU8(t, flags);
- }
-}
-
void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
{
f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
return 0;
}
+static void font_freealignzones(SWFFONT * f)
+{
+ if(f->alignzones)
+ free(f->alignzones);
+ f->alignzones = 0;
+}
+
void swf_FontFree(SWFFONT * f)
{
int i;
rfx_free(f->glyph2ascii);
f->glyph2ascii = NULL;
}
+ if (f->glyph2glyph) {
+ rfx_free(f->glyph2glyph);
+ f->glyph2glyph = NULL;
+ }
font_freename(f);
font_freelayout(f);
font_freeglyphnames(f);
font_freeusage(f);
+ font_freealignzones(f);
rfx_free(f);
}
}
}
-#define FONTALIGN_THIN
-#define FONTALIGN_MEDIUM
-#define FONTALIGN_THICK
-
-void swf_FontCreateAlignZones(SWFFONT * f)
-{
- if(f->alignzones)
- return;
-
- f->alignzones = (ALIGNZONE*)rfx_calloc(sizeof(ALIGNZONE)*f->numchars);
- f->alignzone_flags = 0; // thin
-
- if(!f->layout) {
- int t;
- for(t=0;t<f->numchars;t++) {
- // just align the baseline
- f->alignzones[t].x = 0xffff;
- f->alignzones[t].y = 0;
- f->alignzones[t].dx = 0xffff;
- f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
- }
- } else {
- int t;
- for(t=0;t<f->numchars;t++) {
- // just align the baseline
- f->alignzones[t].x = 0xffff;
- f->alignzones[t].y = 0;
- f->alignzones[t].dx = 0xffff;
- f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
- }
- }
-
-/*
- "-^_~\xad\xaf+`\xac\xb7\xf7" //chars for which to detect one y value
- "#=:;\xb1" //chars for which to detect two y values
- "\"\xa8" //chars for which to detect two x values
-*/
-}
-
-
void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
{
U8 *s = (U8 *) text;
swf_SaveSWF(&swf, filename);
swf_FreeTags(&swf);
}
-