X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fmodules%2Fswftext.c;h=ad17f1c4997e43b3d577964eb52e09f569de8df4;hb=d0884f3fcd06d63b52834d48076a100d0a4e9557;hp=3d6a49be8f9da61e988e868d9ab0f8b6758c887a;hpb=7155f27b636876b1b3c2c9f39c6393b9b5ce0f8d;p=swftools.git diff --git a/lib/modules/swftext.c b/lib/modules/swftext.c index 3d6a49b..ad17f1c 100644 --- a/lib/modules/swftext.c +++ b/lib/modules/swftext.c @@ -22,6 +22,50 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +static U32 readUTF8char(U8**text) +{ + U32 c = 0; + if(!(*(*text) & 0x80)) + return *((*text)++); + + /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */ + if(((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) + { + c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f); + (*text) += 2; + return c; + } + /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */ + if(((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) + { + c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f); + (*text) += 3; + return c; + } + /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if(((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2] && (*text)[3] ) + { + c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f)<<6 | ((*text)[3] & 0x3f); + (*text) += 4; + return c; + } + /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if(((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4]) + { + c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f)<<12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f); + (*text) += 5; + return c; + } + /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */ + if(((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4] && (*text)[5]) + { + c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 | ((*text)[2] & 0x3f)<<18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6; + (*text) += 6; + return c; + } + return *((*text)++); +} + #define TF_TEXTCONTROL 0x80 #define TF_HASFONT 0x08 #define TF_HASCOLOR 0x04 @@ -475,6 +519,7 @@ int swf_FontReduce(SWFFONT * f,FONTUSAGE * use) { int i,j; if ((!f)||(!use)) return -1; + /* TODO: layout, glyphnames */ j = 0; for (i=0;inumchars;i++) if (f->glyph[i].shape) @@ -498,6 +543,68 @@ int swf_FontReduce(SWFFONT * f,FONTUSAGE * use) return j; } +void swf_FontSort(SWFFONT * font) +{ + if(!font) return; + int i,j,k; + int* newplace = malloc(sizeof(int)*font->numchars); + int* newpos; + + for(i=0;inumchars;i++) { + newplace[i] = i; + } + for(i=0;inumchars;i++) + for(j=0;jglyph2ascii[i] < font->glyph2ascii[j]) { + int n1,n2; + char* c1,*c2; + SWFGLYPH g1,g2; + SRECT r1,r2; + n1=newplace[i]; + n2=newplace[j]; + newplace[j] = n1; + newplace[i] = n2; + n1=font->glyph2ascii[i]; + n2=font->glyph2ascii[j]; + font->glyph2ascii[j] = n1; + font->glyph2ascii[i] = n2; + g1=font->glyph[i]; + g2=font->glyph[j]; + font->glyph[j] = g1; + font->glyph[i] = g2; + if(font->glyphnames) { + c1 = font->glyphnames[i]; + c2 = font->glyphnames[j]; + font->glyphnames[j] = c1; + font->glyphnames[i] = c2; + } + if(font->layout) { + r1 = font->layout->bounds[i]; + r2 = font->layout->bounds[j]; + font->layout->bounds[j] = r1; + font->layout->bounds[i] = r2; + } + } + } + newpos = malloc(sizeof(int)*font->numchars); + for(i=0;inumchars;i++) { + newpos[newplace[i]] = i; + } + for(i=0;imaxascii;i++) { + if(font->ascii2glyph[i]>=0) + font->ascii2glyph[i] = newpos[font->ascii2glyph[i]]; + } + + free(newpos); + free(newplace); +} + +void swf_FontPrepareForEditText(SWFFONT * font) +{ + if(!font->layout) + swf_FontCreateLayout(font); + swf_FontSort(font); +} int swf_FontInitUsage(SWFFONT* f, FONTUSAGE * use) { if (!use) return -1; @@ -581,7 +688,7 @@ int swf_FontSetDefine2(TAG *tag, SWFFONT * f) flags |= 4; //wide codecs if(fontSize(f)>65535) flags |= 8; //wide offsets - flags |= 8; //FIXME: the above check doesn't work + flags |= 8|4; //FIXME: the above check doesn't work if(f->encoding & FONT_ENCODING_ANSI) flags |= 16; // ansi @@ -633,7 +740,7 @@ int swf_FontSetDefine2(TAG *tag, SWFFONT * f) /* font code table */ if(flags & 4) /* wide codes */ { - for(t=0;tnumchars;t++) { + for(t=0;tnumchars;t++) { swf_SetU16(tag,f->glyph2ascii[t]); } } else { @@ -706,9 +813,10 @@ int swf_FontSetInfo(TAG * t,SWFFONT * f) swf_SetU8(t,(flags&0xfe)|wide); for (i=0;inumchars;i++) { - if (f->glyph[i].shape) - wide?swf_SetU16(t,f->glyph2ascii[i]): - swf_SetU8(t,f->glyph2ascii[i]); + if (f->glyph[i].shape) { + int g2a = f->glyph2ascii[i]; + wide?swf_SetU16(t,g2a):swf_SetU8(t,g2a); + } } return 0; @@ -761,7 +869,8 @@ void swf_FontFree(SWFFONT * f) if(f->glyphnames) { int t; for(t=0;tnumchars;t++) { - free(f->glyphnames[t]); + if(f->glyphnames[t]) + free(f->glyphnames[t]); } free(f->glyphnames); } @@ -788,42 +897,58 @@ int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,int dx,in return 0; } -int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) +static int swf_TextCountBits2(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits, char*encoding) { U16 g,a; + char utf8=0; if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1; g = a = 0; - while(s[0]) + if(!strcmp(encoding, "UTF8")) utf8=1; + else if(!strcmp(encoding, "iso-8859-1")) utf8=0; + else fprintf(stderr, "Unknown encoding: %s", encoding); + + while(*s) { - int glyph = -1; - if(s[0] < font->maxascii) - glyph = font->ascii2glyph[s[0]]; + int glyph = -1,c; + + if(!utf8) c = *s++; + else c = readUTF8char(&s); + + if(c < font->maxascii) + glyph = font->ascii2glyph[c]; if(glyph>=0) { g = swf_CountUBits(glyph,g); a = swf_CountBits(((((U32)font->glyph[glyph].advance)*scale)/20)/100,a); } - s++; } if (gbits) gbits[0] = (U8)g; if (abits) abits[0] = (U8)a; - return 0; } -int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) -{ int l=0,i,pos; +static int swf_TextSetCharRecord2(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits, char*encoding) +{ int l=0,pos; + char utf8=0; if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1; + + if(!strcmp(encoding, "UTF8")) utf8=1; + else if(!strcmp(encoding, "iso-8859-1")) utf8=0; + else fprintf(stderr, "Unknown encoding: %s", encoding); pos = t->len; swf_SetU8(t, l); //placeholder - for (i=0;s[i];i++) + while(*s) { - int g = -1; - if(s[i] < font->maxascii) - g = font->ascii2glyph[s[i]]; + int g = -1,c; + + if(!utf8) c = *s++; + else c = readUTF8char(&s); + + if(c < font->maxascii) + g = font->ascii2glyph[c]; if(g>=0) { swf_SetBits(t,g,gbits); swf_SetBits(t,((((U32)font->glyph[g].advance)*scale)/20)/100,abits); @@ -839,6 +964,19 @@ int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 ab return 0; } +int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) { + return swf_TextCountBits2(font,s,scale,gbits,abits,"iso-8859-1"); +} +int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) { + return swf_TextSetCharRecord2(t,font,s,scale,gbits,abits,"iso-8859-1"); +} +int swf_TextCountBitsUTF8(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) { + return swf_TextCountBits2(font,s,scale,gbits,abits,"UTF8"); +} +int swf_TextSetCharRecordUTF8(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) { + return swf_TextSetCharRecord2(t,font,s,scale,gbits,abits,"UTF8"); +} + U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale) { U32 res = 0; @@ -857,6 +995,31 @@ U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale) return res; } +SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font,U8 * s,int scale) +{ + int pos=0; + SRECT r; + swf_GetRect(0, &r); + while(*s) { + int c = readUTF8char(&s); + if(c < font->maxascii) { + int g = font->ascii2glyph[c]; + if(g>=0) { + SRECT rn = font->layout->bounds[g]; + rn.xmin = (rn.xmin * scale)/20/100 + pos; + rn.xmax = (rn.xmax * scale)/20/100 + pos; + rn.ymin = (rn.ymin * scale)/20/100; + rn.ymax = (rn.ymax * scale)/20/100; + swf_ExpandRect2(&r, &rn); + pos += (font->glyph[g].advance*scale)/20/100; + } + } + c++; + } + return r; +} + + SWFFONT* swf_ReadFont(char* filename) { int f; @@ -927,10 +1090,13 @@ void swf_WriteFont(SWFFONT*font, char* filename) { int c; t = swf_InsertTag(t,ST_GLYPHNAMES); - swf_SetU16(t, font->id); + swf_SetU16(t, WRITEFONTID); swf_SetU16(t, font->numchars); for(c=0;cnumchars;c++) { - swf_SetString(t, font->glyphnames[c]); + if(font->glyphnames[c]) + swf_SetString(t, font->glyphnames[c]); + else + swf_SetString(t, ""); } } @@ -943,9 +1109,14 @@ void swf_WriteFont(SWFFONT*font, char* filename) int ypos = 1; U8 gbits,abits; int x,y,c; + int range = font->maxascii; c=0; - for(s=0;smaxascii;s++) + if(useDefineFont2 && range > 256) { + range = 256; + } + + for(s=0;sascii2glyph[s]; if(g>=0) { @@ -989,11 +1160,11 @@ void swf_WriteFont(SWFFONT*font, char* filename) rgb.g = 0x00; rgb.b = 0x00; ypos = 1; - for(y=0;y<((font->maxascii+15)/16);y++) + for(y=0;y<((range+15)/16);y++) { int c=0,lastx=-1; for(x=0;x<16;x++) { - int g = (y*16+xmaxascii)?font->ascii2glyph[y*16+x]:-1; + int g = (y*16+xascii2glyph[y*16+x]:-1; if(g>=0 && font->glyph[g].shape) { c++; if(lastx<0) @@ -1004,7 +1175,7 @@ void swf_WriteFont(SWFFONT*font, char* filename) swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*ypos*2); for(x=0;x<16;x++) { - int g = (y*16+xmaxascii)?font->ascii2glyph[y*16+x]:-1; + int g = (y*16+xascii2glyph[y*16+x]:-1; if(g>=0 && font->glyph[g].shape) { if(lastx != x*xmax) { swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0); @@ -1083,24 +1254,10 @@ SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale) U8 gbits, abits; U8*c = (U8*)text; int pos = 0; - swf_GetRect(0, &r); if(font->layout) { - while(*c) { - if(*c < font->maxascii) { - int g = font->ascii2glyph[*c]; - if(g>=0) { - SRECT rn = font->layout->bounds[g]; - rn.xmin = (rn.xmin * scale)/100 + pos; - rn.xmax = (rn.xmax * scale)/100 + pos; - rn.ymin = (rn.ymin * scale)/100; - rn.ymax = (rn.ymax * scale)/100; - swf_ExpandRect2(&r, &rn); - pos += (font->glyph[g].advance*scale)/100; - } - } - c++; - } + r = swf_TextCalculateBBoxUTF8(font,text,scale*20); } else { + fprintf(stderr, "No layout information- can't compute text bbox accurately"); /* Hm, without layout information, we can't compute a bounding box. We could call swf_FontCreateLayout to create a layout, but the caller probably doesn't want us to mess up his font @@ -1111,8 +1268,16 @@ SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale) } swf_SetRect(tag,&r); - swf_SetMatrix(tag,NULL); - swf_TextCountBits(font,text,scale*20,&gbits,&abits); + + /* The text matrix is pretty boring, as it doesn't apply to + individual characters, but rather whole text objects (or + at least whole char records- haven't tested). + So it can't do anything which we can't already do with + the placeobject tag we use for placing the text on the scene. + */ + swf_SetMatrix(tag,0); + + swf_TextCountBitsUTF8(font,text,scale*20,&gbits,&abits); swf_SetU8(tag,gbits); swf_SetU8(tag,abits); @@ -1126,7 +1291,7 @@ SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale) /* set the actual text- notice that we just pass our scale parameter over, as TextSetCharRecord calculates with percent, too */ - swf_TextSetCharRecord(tag,font,text,scale*20,gbits,abits); + swf_TextSetCharRecordUTF8(tag,font,text,scale*20,gbits,abits); swf_SetU8(tag,0); return r; @@ -1166,7 +1331,7 @@ void swf_FontCreateLayout(SWFFONT*f) they are used)- we now have to guess whether that width might be possible, which is the case if it isn't either much too big or much too small */ if(width > f->glyph[t].advance*3/2 || - width*2 < f->glyph[t].advance) + width < f->glyph[t].advance/2) f->glyph[t].advance = width; if(-bbox.ymin > f->layout->ascent) @@ -1176,53 +1341,9 @@ void swf_FontCreateLayout(SWFFONT*f) } } -static U32 readUTF8char(char**text) +void swf_DrawText(drawer_t*draw, SWFFONT*font, int size, char*text) { - U32 c = 0; - if(!(*(*text) & 0x80)) - return *((*text)++); - - /* 0000 0080-0000 07FF 110xxxxx 10xxxxxx */ - if(((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) - { - c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f); - (*text) += 2; - return c; - } - /* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx */ - if(((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) - { - c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f); - (*text) += 3; - return c; - } - /* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if(((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2] && (*text)[3] ) - { - c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f)<<6 | ((*text)[3] & 0x3f); - (*text) += 4; - return c; - } - /* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if(((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4]) - { - c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f)<<12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f); - (*text) += 5; - return c; - } - /* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx */ - if(((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4] && (*text)[5]) - { - c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 | ((*text)[2] & 0x3f)<<18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6; - (*text) += 6; - return c; - } - return *((*text)++); -} - -void swf_DrawText(drawer_t*draw, SWFFONT*font, char*text) -{ - char*s = text; + U8*s = (U8*)text; int advance = 0; while(*s) { SHAPE*shape; @@ -1231,31 +1352,35 @@ void swf_DrawText(drawer_t*draw, SWFFONT*font, char*text) U32 c = readUTF8char(&s); int g = font->ascii2glyph[c]; shape = font->glyph[g].shape; + if(((int)g)<0) { + fprintf(stderr, "No char %d in font %s\n", c, font->name?(char*)font->name:"?"); + continue; + } shape2 = swf_ShapeToShape2(shape); l = shape2->lines; while(l) { if(l->type == moveTo) { FPOINT to; - to.x = l->x/20.0+advance; - to.y = l->y/20.0; + to.x = l->x*size/100.0/20.0+advance; + to.y = l->y*size/100.0/20.0; draw->moveTo(draw, &to); } else if(l->type == lineTo) { FPOINT to; - to.x = l->x/20.0+advance; - to.y = l->y/20.0; + to.x = l->x*size/100.0/20.0+advance; + to.y = l->y*size/100.0/20.0; draw->lineTo(draw, &to); } else if(l->type == splineTo) { FPOINT mid,to; - mid.x = l->sx/20.0+advance; - mid.y = l->sy/20.0; - to.x = l->x/20.0+advance; - to.y = l->y/20.0; + mid.x = l->sx*size/100.0/20.0+advance; + mid.y = l->sy*size/100.0/20.0; + to.x = l->x*size/100.0/20.0+advance; + to.y = l->y*size/100.0/20.0; draw->splineTo(draw, &mid, &to); } l = l->next; } swf_Shape2Free(shape2); - advance += font->glyph[g].advance/20.0; + advance += font->glyph[g].advance*size/100.0/20.0; } }