diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index ab0fcf6b994..fbc0d70fa22 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -56,6 +56,10 @@ int mat_to_sel(void); void font_duplilist(struct Object *par); int getselection(int *start, int *end); +void chtoutf8(unsigned long c, char *o); +void wcs2utf8s(char *dst, wchar_t *src); +int wcsleninu8(wchar_t *src); +int utf8towchar_(wchar_t *w, char *c); #endif diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 5ea8b398363..2335510ac2d 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -117,6 +117,11 @@ typedef struct Global { /* Rob's variables */ int have_quicktime; int ui_international; + int charstart; + int charmin; + int charmax; + struct VFont *selfont; + struct ListBase ttfdata; /* this variable is written to / read from FileGlobal->fileflags */ int fileflags; diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index b08b99a4010..2fca941a651 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -217,6 +217,10 @@ void initglobals(void) #endif clear_workob(); /* object.c */ + + G.charstart = 0x0000; + G.charmin = 0x0000; + G.charmax = 0xffff; } /***/ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index af7a94e079e..500fed8831a 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include @@ -80,19 +81,151 @@ struct chartrans { char dobreak; }; +/* UTF-8 <-> wchar transformations */ +void +chtoutf8(unsigned long c, char *o) +{ + // Variables and initialization + memset(o, 0, 16); + + // Create the utf-8 string + if (c < 0x80) + { + o[0] = (char) c; + } + else if (c < 0x800) + { + o[0] = (0xC0 | (c>>6)); + o[1] = (0x80 | (c & 0x3f)); + } + else if (c < 0x10000) + { + o[0] = (0xe0 | (c >> 12)); + o[1] = (0x80 | (c >>6 & 0x3f)); + o[2] = (0x80 | (c & 0x3f)); + } + else if (c < 0x200000) + { + o[0] = (0xf0 | (c>>18)); + o[1] = (0x80 | (c >>12 & 0x3f)); + o[2] = (0x80 | (c >> 6 & 0x3f)); + o[3] = (0x80 | (c & 0x3f)); + } +} + +void +wcs2utf8s(char *dst, wchar_t *src) +{ + char ch[5]; + + while(*src) + { + memset(ch, 0, 5); + chtoutf8(*src++, ch); + strcat(dst, ch); + } +} + +int +wcsleninu8(wchar_t *src) +{ + char ch[16]; + int len = 0; + + while(*src) + { + memset(ch, 0, 16); + chtoutf8(*src++, ch); + len = len + strlen(ch); + } + + return len; +} + +int +utf8slen(char *src) +{ + int size = 0, index = 0; + unsigned char c; + + c = src[index++]; + while(c) + { + if((c & 0x80) == 0) + { + index += 0; + } + else if((c & 0xe0) == 0xe0) + { + index += 2; + } + else + { + index += 1; + } + size += 1; + c = src[index++]; + } + + return size; +} + +int utf8towchar_(wchar_t *w, char *c) +{ + int len=0; + if(w==NULL || c==NULL) return(0); + //printf("%s\n",c); + while(*c) + { + if(*c & 0x80) + { + if(*c & 0x40) + { + if(*c & 0x20) + { + if(*c & 0x10) + { + *w=(c[0] & 0x0f)<<18 | (c[1]&0x1f)<<12 | (c[2]&0x3f)<<6 | (c[3]&0x7f); + c++; + } + else + *w=(c[0] & 0x1f)<<12 | (c[1]&0x3f)<<6 | (c[2]&0x7f); + c++; + } + else + *w=(((c[0] &0x3f)<<6) | (c[1]&0x7f)); + c++; + } + else + *w=(c[0] & 0x7f); + } + else + *w=(c[0] & 0x7f); + + c++; + w++; + len++; + } + return len; +} + +/* The vfont code */ void free_vfont(struct VFont *vf) { - int i; - if (vf == 0) return; if (vf->data) { - for (i = 0; i < MAX_VF_CHARS; i++){ - while (vf->data->nurbsbase[i].first) { - Nurb *nu = vf->data->nurbsbase[i].first; + while(vf->data->characters.first) + { + VChar *che = vf->data->characters.first; + + while (che->nurbsbase.first) { + Nurb *nu = che->nurbsbase.first; if (nu->bezt) MEM_freeN(nu->bezt); - BLI_freelinkN(&vf->data->nurbsbase[i], nu); + BLI_freelinkN(&che->nurbsbase, nu); } + + BLI_freelinkN(&vf->data->characters, che); } MEM_freeN(vf->data); @@ -131,6 +264,20 @@ static PackedFile *get_builtin_packedfile(void) static VFontData *vfont_get_data(VFont *vfont) { + struct TmpFont *tmpfnt = NULL; + PackedFile *tpf; + + // Try finding the font from font list + tmpfnt = G.ttfdata.first; + + while(tmpfnt) + { + if(tmpfnt->vfont == vfont) + break; + tmpfnt = tmpfnt->next; + } + + // And then set the data if (!vfont->data) { PackedFile *pf; @@ -139,8 +286,34 @@ static VFontData *vfont_get_data(VFont *vfont) } else { if (vfont->packedfile) { pf= vfont->packedfile; + + // We need to copy a tmp font to memory unless it is already there + if(!tmpfnt) + { + tpf= MEM_callocN(sizeof(*tpf), "PackedFile"); + tpf->data= MEM_mallocN(pf->size, "packFile"); + tpf->size= pf->size; + memcpy(tpf->data, pf->data, pf->size); + + // Add temporary packed file to globals + tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); + tmpfnt->pf= tpf; + tmpfnt->vfont= vfont; + BLI_addtail(&G.ttfdata, tmpfnt); + } } else { pf= newPackedFile(vfont->name); + + if(!tmpfnt) + { + tpf= newPackedFile(vfont->name); + + // Add temporary packed file to globals + tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); + tmpfnt->pf= tpf; + tmpfnt->vfont= vfont; + BLI_addtail(&G.ttfdata, tmpfnt); + } } if(!pf) { printf("Font file doesn't exist: %s\n", vfont->name); @@ -170,7 +343,9 @@ VFont *load_vfont(char *name) char filename[FILE_MAXFILE]; VFont *vfont= NULL; PackedFile *pf; + PackedFile *tpf = NULL; int is_builtin; + struct TmpFont *tmpfnt; if (BLI_streq(name, "")) { strcpy(filename, name); @@ -184,6 +359,8 @@ VFont *load_vfont(char *name) BLI_splitdirstring(dir, filename); pf= newPackedFile(name); + tpf= newPackedFile(name); + is_builtin= 0; } @@ -196,7 +373,7 @@ VFont *load_vfont(char *name) vfd= BLI_vfontdata_from_freetypefont(pf); #else vfd= BLI_vfontdata_from_psfont(pf); -#endif +#endif if (vfd) { vfont = alloc_libblock(&G.main->vfont, ID_VF, filename); @@ -208,7 +385,18 @@ VFont *load_vfont(char *name) if (!is_builtin && (G.fileflags & G_AUTOPACK)) { vfont->packedfile = pf; } + + // Do not add to temporary listbase + if(strcmp(filename, "")) + { + tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); + tmpfnt->pf= tpf; + tmpfnt->vfont= vfont; + BLI_addtail(&G.ttfdata, tmpfnt); + } } + + // Free the packed file if (!vfont || vfont->packedfile != pf) { freePackedFile(pf); } @@ -281,12 +469,13 @@ static void build_underline(Curve *cu, float x1, float y1, float x2, float y2, i } -static void buildchar(Curve *cu, unsigned char ascii, CharInfo *info, float ofsx, float ofsy, float rot, int charidx) +static void buildchar(Curve *cu, unsigned long character, CharInfo *info, float ofsx, float ofsy, float rot, int charidx) { BezTriple *bezt1, *bezt2; - Nurb *nu1, *nu2; + Nurb *nu1 = NULL, *nu2 = NULL; float *fp, fsize, shear, x, si, co; - VFontData *vfd; + VFontData *vfd = NULL; + VChar *che = NULL; int i, sel=0; vfd= vfont_get_data(which_vfont(cu, info)); @@ -307,7 +496,20 @@ static void buildchar(Curve *cu, unsigned char ascii, CharInfo *info, float ofsx si= (float)sin(rot); co= (float)cos(rot); - nu1 = vfd->nurbsbase[ascii].first; + // Find the correct character from the font + che = vfd->characters.first; + while(che) + { + if(che->index == character) + break; + che = che->next; + } + + // Select the glyph data + if(che) + nu1 = che->nurbsbase.first; + + // Create the character while(nu1) { bezt1 = nu1->bezt; @@ -419,7 +621,7 @@ struct chartrans *text_to_curve(Object *ob, int mode) float *f, maxlen=0, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4; int i, slen, oldflag, j; short cnr=0, lnr=0, wsnr= 0; - char ascii, *mem; + wchar_t *mem, *tmp, ascii; int outta; float vecyo[3], curofs; CharInfo *info; @@ -429,22 +631,39 @@ struct chartrans *text_to_curve(Object *ob, int mode) int curbox; int selstart, selend; SelBox *sb= NULL; /* to please gcc */ + VChar *che; + float twidth; + int utf8len; /* renark: do calculations including the trailing '\0' of a string because the cursor can be at that location */ if(ob->type!=OB_FONT) return 0; - cu= ob->data; - mem= cu->str; - slen = strlen(mem); + // Set font data + cu= (Curve *) ob->data; + vfont= cu->vfont; + + if(cu->str == 0) return 0; + if(vfont == 0) return 0; + + // Create unicode string + utf8len = utf8slen(cu->str); + tmp = mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem"); + + utf8towchar_(mem, cu->str); + + // Count the wchar_t string length + slen = wcslen(mem); if (cu->ulheight == 0.0) cu->ulheight = 0.05; - if (cu->str==0) return 0; if (cu->strinfo==NULL) { /* old file */ cu->strinfo = MEM_callocN((slen+1) * sizeof(CharInfo), "strinfo compat"); } + vfd= vfont_get_data(vfont); + if(!vfd) goto errcse; + /* calc offset and rotation of each char */ ct = chartransdata = (struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext"); @@ -476,23 +695,65 @@ struct chartrans *text_to_curve(Object *ob, int mode) curbox= 0; for (i = 0 ; i<=slen ; i++) { makebreak: - ascii = cu->str[i]; + // Characters in the list + che = vfd->characters.first; + ascii = mem[i]; info = &(cu->strinfo[i]); vfont = which_vfont(cu, info); - if (vfont==0) return 0; + + // Find the character + while(che) + { + if(che->index == ascii) + break; + che = che->next; + } + +#ifdef WITH_FREETYPE2 + // The character wasn't in the current curve base so load it + // But if the font is then do not try loading since whole font is in the memory already + if(che == NULL && strcmp(vfont->name, "")) + { + BLI_vfontchar_from_freetypefont(vfont, ascii); + } + + // Try getting the character again from the list + che = vfd->characters.first; + while(che) + { + if(che->index == ascii) + break; + che = che->next; + } +#endif + + + if (vfont==0) goto errcse; if (vfont != oldvfont) { vfd= vfont_get_data(vfont); oldvfont = vfont; } - if (!vfd) return 0; - if((tb->w != 0.0) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+vfd->width[ascii])*cu->fsize) > tb->w) { -// fprintf(stderr, "linewidth exceeded: %c%c%c...\n", cu->str[i], cu->str[i+1], cu->str[i+2]); - for (j=i; j && (cu->str[j] != '\n') && (cu->str[j] != '\r') && (chartransdata[j].dobreak==0); j--) { - if (cu->str[j]==' ' || cu->str[j]=='-') { + if (!vfd) goto errcse; + + // The character wasn't found, propably ascii = 0, then the width shall be 0 as well + if(!che) + { + twidth = 0; + } + else + { + twidth = che->width; + } + + // Calculate positions + if((tb->w != 0.0) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+twidth)*cu->fsize) > tb->w) { +// fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]); + for (j=i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak==0); j--) { + if (mem[j]==' ' || mem[j]=='-') { ct -= (i-(j-1)); cnr -= (i-(j-1)); - if (cu->str[j] == ' ') wsnr--; - if (cu->str[j] == '-') wsnr++; + if (mem[j] == ' ') wsnr--; + if (mem[j] == '-') wsnr++; i = j-1; xof = ct->xof; ct[1].dobreak = 1; @@ -500,7 +761,7 @@ struct chartrans *text_to_curve(Object *ob, int mode) goto makebreak; } if (chartransdata[j].dobreak) { -// fprintf(stderr, "word too long: %c%c%c...\n", cu->str[j], cu->str[j+1], cu->str[j+2]); +// fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]); ct->dobreak= 1; cu->strinfo[i+1].flag |= CU_WRAP; ct -= 1; @@ -533,7 +794,12 @@ struct chartrans *text_to_curve(Object *ob, int mode) curbox++; yof= cu->yof + tb->y/cu->fsize; } - + + if(ascii == '\n' || ascii == '\r') + xof = cu->xof; + else + xof= cu->xof + (tb->x/cu->fsize); + xof= cu->xof + (tb->x/cu->fsize); lnr++; cnr= 0; @@ -566,7 +832,16 @@ struct chartrans *text_to_curve(Object *ob, int mode) wsfac = cu->wordspace; wsnr++; } else wsfac = 1.0; - xof += (vfd->width[ascii]*wsfac*(1.0+(info->kern/40.0)) ) + xtrax; + // Set the width of the character + if(!che) + { + twidth = 0; + } + else + { + twidth = che->width; + } + xof += (twidth*wsfac*(1.0+(info->kern/40.0)) ) + xtrax; if (selboxes && (i>=selstart) && (i<=selend)) sb->w = (xof*cu->fsize) - sb->w; } @@ -577,8 +852,9 @@ struct chartrans *text_to_curve(Object *ob, int mode) cu->lines= 1; ct= chartransdata; - for (i= 0; i<=slen; i++, mem++, ct++) { - ascii = *mem; + tmp = mem; + for (i= 0; i<=slen; i++, tmp++, ct++) { + ascii = *tmp; if(ascii== '\n' || ascii== '\r' || ct->dobreak) cu->lines++; } @@ -608,9 +884,9 @@ struct chartrans *text_to_curve(Object *ob, int mode) if(linedata2[i]>1) linedata[i]= (linedata3[i]-linedata[i])/(linedata2[i]-1); for (i=0; i<=slen; i++) { - for (j=i; (cu->str[j]) && (cu->str[j]!='\n') && - (cu->str[j]!='\r') && (chartransdata[j].dobreak==0) && (jstr[j]!='\r') && (cu->str[j]!='\n') && (cu->str[j])) { + for (j=i; (mem[j]) && (mem[j]!='\n') && + (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (jxof+= ct->charnr*linedata[ct->linenr]; // } ct++; @@ -619,14 +895,14 @@ struct chartrans *text_to_curve(Object *ob, int mode) (cu->tb[0].w != 0.0)) { curofs= 0; for (i=0; i<=slen; i++) { - for (j=i; (cu->str[j]) && (cu->str[j]!='\n') && - (cu->str[j]!='\r') && (chartransdata[j].dobreak==0) && (jstr[j]!='\r') && (cu->str[j]!='\n') && + for (j=i; (mem[j]) && (mem[j]!='\n') && + (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (jstr[i]==' ') curofs += (linedata3[ct->linenr]-linedata[ct->linenr])/linedata4[ct->linenr]; + if (mem[i]==' ') curofs += (linedata3[ct->linenr]-linedata[ct->linenr])/linedata4[ct->linenr]; ct->xof+= curofs; } - if (cu->str[i]=='\n' || cu->str[i]=='\r' || chartransdata[i].dobreak) curofs= 0; + if (mem[i]=='\n' || mem[i]=='\r' || chartransdata[i].dobreak) curofs= 0; ct++; } } @@ -685,9 +961,28 @@ struct chartrans *text_to_curve(Object *ob, int mode) for (i=0; i<=slen; i++, ct++) { /* rotate around centre character */ - ascii = cu->str[i]; - dtime= distfac*0.35f*vfd->width[ascii]; /* why not 0.5? */ - dtime= distfac*0.0f*vfd->width[ascii]; /* why not 0.5? */ + ascii = mem[i]; + + // Find the character + che = vfd->characters.first; + while(che) + { + if(che->index == ascii) + break; + che = che->next; + } + + if(che) + { + twidth = che->width; + } + else + { + twidth = 0; + } + + dtime= distfac*0.35f*twidth; /* why not 0.5? */ + dtime= distfac*0.0f*twidth; /* why not 0.5? */ ctime= timeofs + distfac*( ct->xof - minx); CLAMP(ctime, 0.0, 1.0); @@ -782,32 +1077,47 @@ struct chartrans *text_to_curve(Object *ob, int mode) if (mode == FO_SELCHANGE) { MEM_freeN(chartransdata); + MEM_freeN(mem); return NULL; } if(mode==0) { /* make nurbdata */ - + unsigned long cha; + freeNurblist(&cu->nurb); ct= chartransdata; if (cu->sepchar==0) { for (i= 0; istr[i]; + cha = (unsigned long) mem[i]; info = &(cu->strinfo[i]); if (info->mat_nr > (ob->totcol)) { printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); info->mat_nr = 0; } - buildchar(cu, ascii, info, ct->xof, ct->yof, ct->rot, i); - if ((info->flag & CU_UNDERLINE) && (ascii != '\n') && (ascii != '\r')) { + // We do not want to see any character for \n or \r + if(cha != '\n' && cha != '\r') + buildchar(cu, cha, info, ct->xof, ct->yof, ct->rot, i); + if ((info->flag & CU_UNDERLINE) && (cha != '\n') && (cha != '\r')) { uloverlap = 0; - if ( (i<(slen-1)) && (cu->str[i+1] != '\n') && (cu->str[i+1] != '\r') && - ((cu->str[i+1] != ' ') || (cu->strinfo[i+1].flag & CU_UNDERLINE)) && ((cu->strinfo[i+1].flag & CU_WRAP)==0) + if ( (i<(slen-1)) && (mem[i+1] != '\n') && (mem[i+1] != '\r') && + ((mem[i+1] != ' ') || (cu->strinfo[i+1].flag & CU_UNDERLINE)) && ((cu->strinfo[i+1].flag & CU_WRAP)==0) ) { uloverlap = xtrax + 0.1; } - ulwidth = cu->fsize * ((vfd->width[ascii]* (1.0+(info->kern/40.0)))+uloverlap); + // Find the character, the characters has to be in the memory already + // since character checking has been done earlier already. + che = vfd->characters.first; + while(che) + { + if(che->index == cha) + break; + che = che->next; + } + + if(!che) twidth =0; else twidth=che->width; + ulwidth = cu->fsize * ((twidth* (1.0+(info->kern/40.0)))+uloverlap); build_underline(cu, ct->xof*cu->fsize, ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize, ct->xof*cu->fsize + ulwidth, ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize - cu->ulheight*cu->fsize, @@ -819,11 +1129,11 @@ struct chartrans *text_to_curve(Object *ob, int mode) else { outta = 0; for (i= 0; (istr[i]; + ascii = mem[i]; info = &(cu->strinfo[i]); if (cu->sepchar == (i+1)) { - cu->str[0] = ascii; - cu->str[1] = 0; + mem[0] = ascii; + mem[1] = 0; cu->strinfo[0]= *info; cu->pos = 1; cu->len = 1; @@ -841,9 +1151,14 @@ struct chartrans *text_to_curve(Object *ob, int mode) } if(mode==FO_DUPLI) { + MEM_freeN(mem); return chartransdata; } +errcse: + if(mem) + MEM_freeN(mem); + MEM_freeN(chartransdata); return 0; } diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenlib/BLI_vfontdata.h index 516bfb15f3f..1ebcd80b22b 100644 --- a/source/blender/blenlib/BLI_vfontdata.h +++ b/source/blender/blenlib/BLI_vfontdata.h @@ -41,17 +41,36 @@ #include "DNA_listBase.h" struct PackedFile; +struct VFont; #define MAX_VF_CHARS 256 typedef struct VFontData { - ListBase nurbsbase[MAX_VF_CHARS]; - float resol[MAX_VF_CHARS]; - float width[MAX_VF_CHARS]; - float *points[MAX_VF_CHARS]; - char name[128]; + ListBase characters; + // ListBase nurbsbase[MAX_VF_CHARS]; + // float resol[MAX_VF_CHARS]; + // float width[MAX_VF_CHARS]; + // float *points[MAX_VF_CHARS]; + char name[128]; } VFontData; +typedef struct VChar { + struct VChar *next, *prev; + ListBase nurbsbase; + unsigned long index; + float resol; + float width; + float *points; +} VChar; + +struct TmpFont +{ + struct TmpFont *next, *prev; + struct PackedFile *pf; + struct VFont *vfont; +}; + + /** * Construct a new VFontData structure from * PostScript font data in a PackedFile. @@ -75,5 +94,10 @@ BLI_vfontdata_from_psfont( VFontData* BLI_vfontdata_from_freetypefont( struct PackedFile *pf); + + int +BLI_vfontchar_from_freetypefont( + struct VFont *vfont, unsigned long character); + #endif diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c index 5e1300e9cdf..f20be8ce828 100644 --- a/source/blender/blenlib/intern/freetypefont.c +++ b/source/blender/blenlib/intern/freetypefont.c @@ -54,8 +54,10 @@ #include "BIF_toolbox.h" +#include "BKE_global.h" #include "BKE_utildefines.h" +#include "DNA_vfont_types.h" #include "DNA_packedFile_types.h" #include "DNA_curve_types.h" @@ -67,18 +69,265 @@ static FT_Library library; static FT_Error err; -static VFontData *objfnt_to_ftvfontdata(PackedFile * pf) +void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) { // Blender - VFontData *vfd; struct Nurb *nu; + struct VChar *che; struct BezTriple *bezt; - + // Freetype2 - FT_Face face; - FT_GlyphSlot glyph; - FT_UInt glyph_index; - FT_Outline ftoutline; + FT_GlyphSlot glyph; + FT_UInt glyph_index; + FT_Outline ftoutline; + const char *fontname; + float scale, height; + float dx, dy; + int i,j,k,l,m=0; + + // Variables + int *npoints; + int *onpoints; + + // adjust font size + height= ((double) face->bbox.yMax - (double) face->bbox.yMin); + if(height != 0.0) + scale = 1.0 / height; + else + scale = 1.0 / 1000.0; + + // + // Generate the character 3D data + // + // Get the FT Glyph index and load the Glyph + glyph_index= FT_Get_Char_Index(face, charcode); + err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); + + // If loading succeeded, convert the FT glyph to the internal format + if(!err) + { + // First we create entry for the new character to the character list + che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char"); + BLI_addtail(&vfd->characters, che); + + // Take some data for modifying purposes + glyph= face->glyph; + ftoutline= glyph->outline; + + // Set the width and character code + che->index= charcode; + che->width= glyph->advance.x * scale; + + // Start converting the FT data + npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ; + onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ; + + // calculate total points of each contour + for(j = 0; j < ftoutline.n_contours; j++) { + if(j == 0) + npoints[j] = ftoutline.contours[j] + 1; + else + npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1]; + } + + // get number of on-curve points for beziertriples (including conic virtual on-points) + for(j = 0; j < ftoutline.n_contours; j++) { + l = 0; + for(k = 0; k < npoints[j]; k++) { + if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; + if(ftoutline.tags[l] == FT_Curve_Tag_On) + onpoints[j]++; + + if(k < npoints[j] - 1 ) + if( ftoutline.tags[l] == FT_Curve_Tag_Conic && + ftoutline.tags[l+1] == FT_Curve_Tag_Conic) + onpoints[j]++; + } + } + + //contour loop, bezier & conic styles merged + for(j = 0; j < ftoutline.n_contours; j++) { + // add new curve + nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb"); + bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ; + BLI_addtail(&che->nurbsbase, nu); + + nu->type= CU_BEZIER+CU_2D; + nu->pntsu = onpoints[j]; + nu->resolu= 8; + nu->flagu= 1; + nu->bezt = bezt; + + //individual curve loop, start-end + for(k = 0; k < npoints[j]; k++) { + if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; + if(k == 0) m = l; + + //virtual conic on-curve points + if(k < npoints[j] - 1 ) + { + if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { + dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0; + dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0; + + //left handle + bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0; + bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0; + + //midpoint (virtual on-curve point) + bezt->vec[1][0] = dx; + bezt->vec[1][1] = dy; + + //right handle + bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0; + bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0; + + bezt->h1= bezt->h2= HD_ALIGN; + bezt++; + } + } + + //on-curve points + if(ftoutline.tags[l] == FT_Curve_Tag_On) { + //left handle + if(k > 0) { + if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) { + bezt->vec[0][0] = ftoutline.points[l-1].x* scale; + bezt->vec[0][1] = ftoutline.points[l-1].y* scale; + bezt->h1= HD_FREE; + } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) { + bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0; + bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0; + bezt->h1= HD_FREE; + } else { + bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0; + bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0; + bezt->h1= HD_VECT; + } + } else { //first point on curve + if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) { + bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale; + bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale; + bezt->h1= HD_FREE; + } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) { + bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ; + bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ; + bezt->h1= HD_FREE; + } else { + bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0; + bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0; + bezt->h1= HD_VECT; + } + } + + //midpoint (on-curve point) + bezt->vec[1][0] = ftoutline.points[l].x* scale; + bezt->vec[1][1] = ftoutline.points[l].y* scale; + + //right handle + if(k < (npoints[j] - 1)) { + if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) { + bezt->vec[2][0] = ftoutline.points[l+1].x* scale; + bezt->vec[2][1] = ftoutline.points[l+1].y* scale; + bezt->h2= HD_FREE; + } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { + bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0; + bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0; + bezt->h2= HD_FREE; + } else { + bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0; + bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0; + bezt->h2= HD_VECT; + } + } else { //last point on curve + if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) { + bezt->vec[2][0] = ftoutline.points[m].x* scale; + bezt->vec[2][1] = ftoutline.points[m].y* scale; + bezt->h2= HD_FREE; + } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) { + bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ; + bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ; + bezt->h2= HD_FREE; + } else { + bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0; + bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0; + bezt->h2= HD_VECT; + } + } + + // get the handles that are aligned, tricky... + // DistVL2Dfl, check if the three beztriple points are on one line + // VecLenf, see if there's a distance between the three points + // VecLenf again, to check the angle between the handles + // finally, check if one of them is a vector handle + if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) && + (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) && + (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) && + (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) && + (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) && + bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) + { + bezt->h1= bezt->h2= HD_ALIGN; + } + bezt++; + } + } + } + } + + if(npoints) MEM_freeN(npoints); + if(onpoints) MEM_freeN(onpoints); +} + +int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode) +{ + // Freetype2 + FT_Face face; + FT_UInt glyph_index; + struct TmpFont *tf; + + // Find the correct FreeType font + tf= G.ttfdata.first; + while(tf) + { + if(tf->vfont == vfont) + break; + tf= tf->next; + } + + // What, no font found. Something strange here + if(!tf) return FALSE; + + // Load the font to memory + if(tf->pf) + { + err= FT_New_Memory_Face( library, + tf->pf->data, + tf->pf->size, + 0, + &face); + } + else + err= TRUE; + + // Read the char + freetypechar_to_vchar(face, charcode, vfont->data); + + // And everything went ok + return TRUE; +} + + +static VFontData *objfnt_to_ftvfontdata(PackedFile * pf) +{ + // Variables + FT_Face face; + FT_ULong charcode = 0, lcode; + FT_UInt glyph_index; + FT_UInt temp; + const char *fontname; + VFontData *vfd; + /* FT_CharMap found = 0; FT_CharMap charmap; @@ -86,10 +335,6 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf) FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS; int n; */ - const char *fontname; - float scale, height; - float dx, dy; - int i, j, k, l, m =0; // load the freetype font err = FT_New_Memory_Face( library, @@ -125,187 +370,52 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf) fontname = FT_Get_Postscript_Name(face); strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname); - // adjust font size - height = ((double) face->bbox.yMax - (double) face->bbox.yMin); + // Extract the first 256 character from TTF + lcode= charcode= FT_Get_First_Char(face, &glyph_index); - if(height != 0.0) - scale = 1.0 / height; - else - scale = 1.0 / 1000.0; + // No charmap found from the ttf so we need to figure it out + if(glyph_index == 0) + { + FT_CharMap found = 0; + FT_CharMap charmap; + int n; - // extract generic ascii character range - for(i = myMIN_ASCII; i <= myMAX_ASCII; i++) { - int *npoints = NULL; //total points of each contour - int *onpoints = NULL; //num points on curve - - glyph_index = FT_Get_Char_Index( face, i ); - err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); - - if(!err) { - glyph = face->glyph; - ftoutline = glyph->outline; - - vfd->width[i] = glyph->advance.x* scale; - - npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ; - onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ; - - // calculate total points of each contour - for(j = 0; j < ftoutline.n_contours; j++) { - if(j == 0) - npoints[j] = ftoutline.contours[j] + 1; - else - npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1]; - } - - // get number of on-curve points for beziertriples (including conic virtual on-points) - for(j = 0; j < ftoutline.n_contours; j++) { - l = 0; - for(k = 0; k < npoints[j]; k++) { - if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; - - if(ftoutline.tags[l] == FT_Curve_Tag_On) - onpoints[j]++; - - if(k < npoints[j] - 1 ) - if( ftoutline.tags[l] == FT_Curve_Tag_Conic && - ftoutline.tags[l+1] == FT_Curve_Tag_Conic) - onpoints[j]++; - } - } - - //contour loop, bezier & conic styles merged - for(j = 0; j < ftoutline.n_contours; j++) { - // add new curve - nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb"); - bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ; - BLI_addtail(&vfd->nurbsbase[i], nu); - - nu->type= CU_BEZIER+CU_2D; - nu->pntsu = onpoints[j]; - nu->resolu= 8; - nu->flagu= 1; - nu->bezt = bezt; - - //individual curve loop, start-end - for(k = 0; k < npoints[j]; k++) { - if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; - if(k == 0) m = l; - - //virtual conic on-curve points - if(k < npoints[j] - 1 ) - if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { - dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0; - dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0; - - //left handle - bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0; - bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0; - - //midpoint (virtual on-curve point) - bezt->vec[1][0] = dx; - bezt->vec[1][1] = dy; - - //right handle - bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0; - bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0; - - bezt->h1= bezt->h2= HD_ALIGN; - bezt++; - } - - //on-curve points - if(ftoutline.tags[l] == FT_Curve_Tag_On) { - //left handle - if(k > 0) { - if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) { - bezt->vec[0][0] = ftoutline.points[l-1].x* scale; - bezt->vec[0][1] = ftoutline.points[l-1].y* scale; - bezt->h1= HD_FREE; - } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) { - bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0; - bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0; - bezt->h1= HD_FREE; - } else { - bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0; - bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0; - bezt->h1= HD_VECT; - } - } else { //first point on curve - if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) { - bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale; - bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale; - bezt->h1= HD_FREE; - } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) { - bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ; - bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ; - bezt->h1= HD_FREE; - } else { - bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0; - bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0; - bezt->h1= HD_VECT; - } - } - - //midpoint (on-curve point) - bezt->vec[1][0] = ftoutline.points[l].x* scale; - bezt->vec[1][1] = ftoutline.points[l].y* scale; - - //right handle - if(k < (npoints[j] - 1)) { - if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) { - bezt->vec[2][0] = ftoutline.points[l+1].x* scale; - bezt->vec[2][1] = ftoutline.points[l+1].y* scale; - bezt->h2= HD_FREE; - } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { - bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0; - bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0; - bezt->h2= HD_FREE; - } else { - bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0; - bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0; - bezt->h2= HD_VECT; - } - } else { //last point on curve - if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) { - bezt->vec[2][0] = ftoutline.points[m].x* scale; - bezt->vec[2][1] = ftoutline.points[m].y* scale; - bezt->h2= HD_FREE; - } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) { - bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ; - bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ; - bezt->h2= HD_FREE; - } else { - bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0; - bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0; - bezt->h2= HD_VECT; - } - } - - // get the handles that are aligned, tricky... - // DistVL2Dfl, check if the three beztriple points are on one line - // VecLenf, see if there's a distance between the three points - // VecLenf again, to check the angle between the handles - // finally, check if one of them is a vector handle - if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) && - (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) && - (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) && - (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) && - (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) && - bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) - { - bezt->h1= bezt->h2= HD_ALIGN; - } - bezt++; - } - } + for ( n = 0; n < face->num_charmaps; n++ ) + { + charmap = face->charmaps[n]; + if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) + { + found = charmap; + break; } } - if(npoints) MEM_freeN(npoints); - if(onpoints) MEM_freeN(onpoints); + err = FT_Set_Charmap( face, found ); + + if( err ) + return NULL; + + lcode= charcode= FT_Get_First_Char(face, &glyph_index); } - return vfd; + + // Load characters + while(charcode < 256) + { + // Generate the font data + freetypechar_to_vchar(face, charcode, vfd); + + // Next glyph + charcode = FT_Get_Next_Char(face, charcode, &glyph_index); + + // Check that we won't start infinite loop + if(charcode <= lcode) + break; + lcode = charcode; + } + + err = FT_Set_Charmap( face, FT_ENCODING_UNICODE ); + + return vfd; } @@ -393,6 +503,30 @@ VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf) return vfd; } +int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character) +{ + int success = FALSE; + + if(!vfont) return FALSE; + + // Init Freetype + err = FT_Init_FreeType(&library); + if(err) { + error("Failed to load the Freetype font library"); + return 0; + } + + // Load the character + success = objchr_to_ftvfontdata(vfont, character); + if(success == FALSE) return FALSE; + + // Free Freetype + FT_Done_FreeType(library); + + // Ahh everything ok + return TRUE; +} + #endif // WITH_FREETYPE2 diff --git a/source/blender/blenlib/intern/psfont.c b/source/blender/blenlib/intern/psfont.c index f7fbf7e3d16..2fccf09805b 100644 --- a/source/blender/blenlib/intern/psfont.c +++ b/source/blender/blenlib/intern/psfont.c @@ -1956,6 +1956,7 @@ static VFontData *objfnt_to_vfontdata(objfnt *fnt) struct Nurb *nu; struct BezTriple *bezt, *bez2; float scale, dx, dy; + struct VChar *che; if (!fnt || (fnt->type!=SP_TYPE)) { return NULL; @@ -1967,7 +1968,10 @@ static VFontData *objfnt_to_vfontdata(objfnt *fnt) for (i = 0; i < MAX_VF_CHARS; i++) { cd = getchardesc(fnt, i); if (cd && cd->data && cd->datalen) { - vfd->width[i] = scale * cd->movex; + che = (VChar *) MEM_callocN(sizeof(VChar), "objfnt_char"); + BLI_addtail(&vfd->characters, che); + che->index = i; + che->width = scale * cd->movex; _data = data = cd->data; @@ -2015,7 +2019,7 @@ static VFontData *objfnt_to_vfontdata(objfnt *fnt) nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb"); bezt = (BezTriple*)MEM_callocN((count)* sizeof(BezTriple),"objfnt_bezt") ; if (nu != 0 && bezt != 0) { - BLI_addtail(&vfd->nurbsbase[i], nu); + BLI_addtail(&che->nurbsbase, nu); nu->type= CU_BEZIER+CU_2D; nu->pntsu = count; nu->resolu= 8; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 57c5c90555e..c54363e692a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -848,6 +848,13 @@ static void write_mballs(WriteData *wd, ListBase *idbase) } } +int amount_of_chars(char *str) +{ + // Since the data is saved as UTF-8 to the cu->str + // The cu->len is not same as the strlen(cu->str) + return strlen(str); +} + static void write_curves(WriteData *wd, ListBase *idbase) { Curve *cu; @@ -863,7 +870,7 @@ static void write_curves(WriteData *wd, ListBase *idbase) writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat); if(cu->vfont) { - writedata(wd, DATA, cu->len+1, cu->str); + writedata(wd, DATA, amount_of_chars(cu->str)+1, cu->str); writestruct(wd, DATA, "CharInfo", cu->len, cu->strinfo); writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb); } diff --git a/source/blender/include/BIF_editfont.h b/source/blender/include/BIF_editfont.h index 372630da8e2..081bea67145 100644 --- a/source/blender/include/BIF_editfont.h +++ b/source/blender/include/BIF_editfont.h @@ -30,16 +30,26 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ +#include + #ifndef BIF_EDITFONT_H #define BIF_EDITFONT_H struct Text; extern char *BIF_lorem; -extern char *copybuf; -extern char *copybufinfo; +extern wchar_t *copybuf; +extern wchar_t *copybufinfo; -void do_textedit(unsigned short event, short val, char _ascii); +typedef struct unicodect +{ + char *name; + char *longname; + int start; + int end; +} unicodect; + +void do_textedit(unsigned short event, short val, unsigned long _ascii); void make_editText(void); void load_editText(void); void remake_editText(void); diff --git a/source/blender/include/BIF_interface.h b/source/blender/include/BIF_interface.h index 875bdbf3564..753bda9a9d3 100644 --- a/source/blender/include/BIF_interface.h +++ b/source/blender/include/BIF_interface.h @@ -151,6 +151,7 @@ struct ScrArea; #define HSVCUBE (26<<9) #define PULLDOWN (27<<9) #define ROUNDBOX (28<<9) +#define CHARTAB (29<<9) #define BUTTYPE (31<<9) diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index eff682e4116..011c13eb0db 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -408,6 +408,12 @@ enum { #define B_STYLETOSELU 2213 #define B_STYLETOSELI 2214 +#define B_SETCHAR 2215 +#define B_SETUPCHAR 2216 +#define B_SETDOWNCHAR 2217 +#define B_SETCAT 2218 +#define B_SETUNITEXT 2219 + /* *********************** */ #define B_ARMBUTS 2400 diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 6e21aa2ccdb..c44d5d9b023 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -86,6 +86,7 @@ #include "BLI_arithb.h" #include "BLI_vfontdata.h" #include "BLI_editVert.h" +#include "BLI_dynstr.h" #include "BSE_filesel.h" @@ -159,6 +160,202 @@ short uv_calc_mapdir= 1, uv_calc_mapalign= 1, facesel_draw_edges= 0; extern ListBase editNurb; +/* *************************** Unicode Character Groups ****************** */ +unicodect uctabname[125] = { + {"All", "All", 0x0000, 0xffff}, + {"Basic Latin", "Basic Latin", 0x0000, 0x007f}, + {"Latin 1 Supp", "Latin-1 Supplement", 0x0080, 0x00ff}, + + {"Latin Ext. A.", "Latin Extended-A", 0x0100, 0x017F}, + {"Latin Ext. B.", "Latin Extended-B", 0x0180,0x024F}, + {"Latin Ext. Add.", "Latin Extended Additional", 0x1e00, 0x1eff}, + + {"IPA Ext", "IPA Extensions", 0x0250, 0x02AF}, + {"Spacing Mod.", "Spacing Modifier Letters", 0x02b0, 0x02ff}, + + {"Comb. Dia.", "Combining Diacritical Marks", 0x0300, 0x036F}, + {"Greek, Coptic", "Greek and Coptic", 0x0370, 0x03ff}, + {"Greek Ext.", "Greek Extended", 0x1f00, 0x1fff}, + + {"Cyrillic", "Cyrillic", 0x0400, 0x04ff}, + {"Cyrillic Supp.", "Cyrillic Supplementary", 0x0500, 0x052f}, + + {"Armenian", "Armenian", 0x0530, 0x058f}, + {"Hebrew", "Hebrew", 0x0590, 0x05ff}, + + + {"Arabic", "Arabic", 0x0600, 0x06ff}, + {"Syriac", "Syriac", 0x0700, 0x074f}, + + {"Thaana", "Thaana", 0x0780, 0x07bf}, + {"Devanagari", "Devanagari", 0x0900, 0x097f}, + + {"Bengali", "Bengali", 0x0980, 0x09ff}, + {"Gurmukhi", "Gurmukhi", 0x0a00, 0x0a7f}, + + {"Gujarati", "Gujarati", 0x0a80, 0x0aff}, + {"Oriya", "Oriya", 0x0b00, 0x0b7f}, + + {"Tamil", "Tamil", 0x0b80, 0x0bff}, + {"Tegulu", "Tegulu", 0x0c00, 0x0c7f}, + + {"Kannada", "Kannada", 0x0c80, 0x0cff}, + {"Malayalam", "Malayalam", 0x0d00, 0x0d7f}, + + {"Sinhala", "Sinhala", 0x0d80, 0x0dff}, + {"Thai", "Thai", 0x0e00, 0x0e7f}, + + {"Lao", "Lao", 0x0e80, 0x0eff}, + {"Tibetan", "Tibetan", 0x0f00, 0x0fff}, + + {"Myanmar", "Myanmar", 0x1000, 0x109f}, + {"Georgian", "Georgian", 0x10a0, 0x10ff}, + + {"Ethiopic", "Ethiopic", 0x1200, 0x137f}, + + {"Cherokee", "Cherokee", 0x13a0, 0x13ff}, + {"Unif. Canadian", "Unified Canadian Aboriginal Syllabics", 0x1400, 0x167f}, + + {"Ogham", "Ogham", 0x1680, 0x169f}, + {"Runic", "Runic", 0x16a0, 0x16ff}, + + {"Tagalog", "Tagalog", 0x1700, 0x171f}, + {"Hanunoo", "Hanunoo", 0x1720, 0x173f}, + + {"Buhid", "Buhid", 0x1740, 0x175f}, + {"Tagbanwa", "Tagbanwa", 0x1760, 0x177f}, + + {"Khmer", "Khmer", 0x1780, 0x17ff}, + {"Khmer Symb", "Khmer Symbols", 0x19e0, 0x19ff}, + + {"Mongolian", "Mongolian", 0x1800, 0x18af}, + + {"Limbu", "Limbu", 0x1900, 0x194f}, + {"Tai Le", "Tai Le", 0x1950, 0x197f}, + + {"Phon. Ext.", "Phonetic Extensions", 0x1d00, 0x1d7f}, + + + {"Gen. Punct.", "General Punctutation", 0x2000, 0x206f}, + {"Super, Sub", "Superscripts and Subscripts", 0x2070, 0x209f}, + + {"Curr. Symb.", "Currency Symbols", 0x20a0, 0x20cf}, + {"Comb. Diacrit.", "Combining Diacritical Marks for Symbols", 0x20d0, 0x20ff}, + + {"Letter Symb", "Letterlike Symbols", 0x2100, 0x214f}, + {"Numb. Forms", "Number Forms", 0x2150, 0x218f}, + + {"Arrows", "Arrows", 0x2190, 0x21ff}, + {"Math Oper.", "Mathematical Operators", 0x2200, 0x22ff}, + + {"Misc. Tech.", "Miscellaneous Technical", 0x2300, 0x23ff}, + {"Ctrl. Pict.", "Control Pictures", 0x2400, 0x243f}, + + {"OCR", "Optical Character Recognition", 0x2440, 0x245f}, + {"Enc. Alpha", "Enclosed Alphanumerics", 0x2460, 0x24ff}, + + {"Bow Drawing", "Box Drawing", 0x2500, 0x257f}, + {"BLock Elem.", "Block Elements", 0x2580, 0x259f}, + + {"Geom. Shapes", "Geometric Shapes", 0x25a0, 0x25ff}, + {"Misc. Symb.", "Miscellaneous Symbols", 0x2600, 0x26ff}, + + {"Dingbats", "Dingbats", 0x2700, 0x27bf}, + {"Misc. Math A", "Miscellaneous Mathematical Symbols-A", 0x27c0, 0x27ef}, + + {"Supp. Arrows-A", "Supplemental Arrows-A", 0x27f0, 0x27ff}, + {"Braille Pat.", "Braille Patterns", 0x2800, 0x28ff}, + + {"Supp. Arrows-B", "Supplemental Arrows-B", 0x2900, 0x297f}, + {"Misc. Math B", "Miscellaneous Mathematical Symbols-B", 0x2980, 0x29ff}, + + {"Supp. Math Op.", "Supplemental Mathematical Operators", 0x2a00, 0x2aff}, + {"Misc. Symb.", "Miscellaneous Symbols and Arrows", 0x2b00, 0x2bff}, + + {"Kangxi Rad.", "Kangxi Radicals", 0x2f00, 0x2fdf}, + + {"Ideographic", "Ideographic Description Characters", 0x2ff0, 0x2fff}, + + {"Hiragana", "Hiragana", 0x3040, 0x309f}, + {"Katakana", "Katakana", 0x30a0, 0x30ff}, + {"Katakana Ext.", "Katakana Phonetic Extensions", 0x31f0, 0x31ff}, + + {"Bopomofo", "Bopomofo", 0x3100, 0x312f}, + {"Bopomofo Ext.", "Bopomofo Extended", 0x31a0, 0x31bf}, + + {"Hangul", "Hangul Jamo", 0x1100, 0x11ff}, + {"Hangul Comp.", "Hangul Compatibility Jamo", 0x3130, 0x318f}, + {"Hangul Syll.", "Hangul Syllables", 0xac00, 0xd7af}, + + {"Kanbun", "Kanbun", 0x3190, 0x319f}, + + + + {"Yijing Hex.", "Yijing Hexagram Symbols", 0x4dc0, 0x4dff}, + + {"Yi Syllables", "Yi Syllables", 0xa000, 0xa48f}, + {"Yi Radicals", "Yi Radicals", 0xa490, 0xa4cf}, + + {"High Surr.", "High Surrogate Area", 0xd800, 0xdbff}, + + {"Low Surr.", "Low Surrogates", 0xdc00, 0xdfff}, + {"Priv. Use Area", "Private Use Area", 0xe000, 0xf8ff}, + + {"CJK Rad. Supp.", "CJK Radicals Supplement", 0x2e80, 0x2eff}, + {"CJK Ideographs", "CJK Unified Ideographs", 0x4e00, 0x9faf}, + {"CJK Ideog. Ext. A", "CJK Unified Ideographs Extension A", 0x3400, 0x4dbf}, + {"CJK Ideog. Ext. B", "CJK Unified Ideographs Extension B", 0x20000, 0x2a6df}, + {"CJK Symbols.", "CJK Symbols and Punctuation", 0x3000, 0x303f}, + {"Enclosed CJK", "Enclosed CJK Letters and Months", 0x3200, 0x32ff}, + {"CJK Comp.", "CJK Compatibility", 0x3300, 0x33ff}, + {"CJK Comp. Ideog.", "CJK Compatibility Ideographs", 0xf900, 0xfaff}, + {"CJK Comp. Forms", "CJK Compatibility Forms", 0xfe30, 0xfe4f}, + {"CJK Comp. Supp.", "CJK Compatibility Ideographs Supplement", 0x2f800, 0x2fa1f}, + + {"Alpha. Pres. Forms", "Alphabetic Presentation Forms", 0xfb00, 0xfb4f}, + + {"Arabic Pres. A", "Arabic Presentation Forms-A", 0xfb50, 0xfdff}, + {"Arabic Pres. B", "Arabic Presentation Forms-B", 0xfe70, 0xfeff}, + + {"Var. Sel.", "Variation Selectors", 0xfe00, 0xfe0f}, + + {"Comb. Half", "Combining Half Marks", 0xfe20, 0xfe2f}, + + {"Sml. From Var.", "Small Form Variants", 0xfe50, 0xfe6f}, + + {"Half, Full Forms", "Halfwidth and Fullwidth Forms", 0xff00, 0xffef}, + {"Specials", "Specials", 0xfff0, 0xffff}, + + {"Lin. B Syllab.", "Linear B Syllabary", 0x10000, 0x1007f}, + {"Lin. B Idog.", "Linear B Ideograms", 0x10080, 0x100ff}, + + {"Aegean Num.", "Aegean Numbers", 0x10100, 0x1013f}, + {"Old Italic", "Old Italic", 0x10300, 0x1032f}, + + {"Gothic", "Gothic", 0x10330, 0x1034f}, + {"Ugaritic", "Ugaritic", 0x10380, 0x1039f}, + + {"Deseret", "Deseret", 0x10400, 0x1044f}, + {"Shavian", "Shavian", 0x10450, 0x1047f}, + + {"Osmanya", "Osmanya", 0x10480, 0x104af}, + {"Cypriot Syll", "Cypriot Syllabary", 0x10800, 0x1083f}, + + {"Bysantine Mus.", "Bysantine Musical Symbols", 0x1d000, 0x1d0ff}, + {"Music Symb.", "Musical Symbols", 0x1d100, 0x1d1ff}, + + {"Tai Xuan Symb", "Tai Xuan Jing Symbols", 0x1d300, 0x1d35f}, + {"Math. Alpha Symb.", "Mathematical Alpanumeric Symbols", 0x1d400, 0x1d7ff}, + + + {"Tags", "Tags", 0xe0000, 0xe007f}, + {"Var. Supp", "Variation Selectors Supplement", 0xe0100, 0xe01ef}, + + {"Supp. Priv. A", "Supplementary Private Use Area-A", 0xf0000, 0xffffd}, + {"Supp. Priv. B", "Supplementary Private Use Area-B", 0x100000, 0x10fffd} + +}; + /* *************************** static functions prototypes ****************** */ VFont *exist_vfont(char *str); @@ -1268,6 +1465,11 @@ static void load_buts_vfont(char *name) allqueue(REDRAWBUTSEDIT, 0); } +static void set_unicode_text_fs(char *file) +{ + if (file > 0) paste_unicodeText(file); +} + void do_fontbuts(unsigned short event) { Curve *cu; @@ -1275,6 +1477,9 @@ void do_fontbuts(unsigned short event) Object *ob; ScrArea *sa; char str[80]; + int ctevt; + char *ctmenu; + DynStr *ds; int i, style=0; ob= OBACT; @@ -1422,6 +1627,74 @@ void do_fontbuts(unsigned short event) } } break; + + case B_SETCHAR: + G.charmin = 0x0000; + G.charmax = 0xffff; + if(G.charstart < 0) + G.charstart = 0; + if(G.charstart > (0xffff - 12*6)) + G.charstart = 0xffff - (12*6); + allqueue(REDRAWBUTSEDIT, 0); + break; + + case B_SETUPCHAR: + G.charstart = G.charstart - (12*6); + if(G.charstart < 0) + G.charstart = 0; + if(G.charstart < G.charmin) + G.charstart = G.charmin; + allqueue(REDRAWBUTSEDIT, 0); + break; + + case B_SETCAT: + // Create new dynamic string + ds = BLI_dynstr_new(); + + // Fill the dynamic string with entries + for(i=0;i<104;i++) + { + BLI_dynstr_append(ds, "|"); + BLI_dynstr_append(ds, uctabname[i].name); + } + + // Create the menu string from dyn string + ctmenu = BLI_dynstr_get_cstring(ds); + + // Call the popup menu + ctevt = pupmenu_col(ctmenu, 40); + G.charstart = uctabname[ctevt-1].start; + G.charmin = uctabname[ctevt-1].start; + G.charmax = uctabname[ctevt-1].end; + + // Free all data + BLI_dynstr_free(ds); + MEM_freeN(ctmenu); + + // And refresh + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + + break; + + case B_SETDOWNCHAR: + G.charstart = G.charstart + (12*6); + if(G.charstart > (0xffff - 12*6)) + G.charstart = 0xffff - (12*6); + if(G.charstart > G.charmax - 12*6) + G.charstart = G.charmax - 12*6; + allqueue(REDRAWBUTSEDIT, 0); + break; + + case B_SETUNITEXT: + sa= closest_bigger_area(); + areawinset(sa->win); + + if(ob==G.obedit) { + activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, set_unicode_text_fs); + } + break; + case B_TEXTONCURVE: if(ob) { cu= ob->data; @@ -1437,6 +1710,32 @@ void do_fontbuts(unsigned short event) } } +static void editing_panel_char_type(Object *ob, Curve *cu) +{ + uiBlock *block; + + block= uiNewBlock(&curarea->uiblocks, "editing_panel_char_type", UI_EMBOSS, UI_HELV, curarea->win); + uiNewPanelTabbed("Font", "Editing"); + if(uiNewPanel(curarea, block, "Char", "Editing", 640, 0, 318, 204)==0) + return; + + // Set the selected font + G.selfont = cu->vfont; + + uiDefIconBut(block, BUT, B_SETUNITEXT, ICON_TEXT, 0,210,20,20, 0, 0, 0, 0, 0, "Load Unicode Text file"); + + // Unicode categorization selection button + uiDefBut(block, BUT, B_SETCAT, "Unicode Table", 22,210,226,20, 0, 0, 0, 0, 0, "Select Unicode Table"); + uiDefButI(block, NUM, /*B_SETUPCHAR*/ 0, "", 250,210,50,20, &G.charstart, 0, 0xffff, 0, 0, "UT"); + + // Character selection button + uiDefBut(block, CHARTAB, B_SETCHAR, "", 0, 0, 264, 200, 0, 0, 0, 0, 0, "Select character"); + + // Buttons to change the max, min + uiDefButI(block, BUT, B_SETUPCHAR, "U", 280, 185, 15, 15, &G.charstart, 0, 0xffff, 0, 0, "Scroll character table up"); + uiDefButI(block, BUT, B_SETDOWNCHAR, "D", 280, 0, 15, 15, &G.charstart, 0, 0xffff, 0, 0, "Scroll character table down"); +} + static void editing_panel_font_type(Object *ob, Curve *cu) { uiBlock *block; @@ -3354,6 +3653,13 @@ void editing_panels() editing_panel_links(ob); // no editmode! editing_panel_curve_type(ob, cu); editing_panel_font_type(ob, cu); + +#ifdef INTERNATIONAL + if(G.obedit) + { + editing_panel_char_type(ob, cu); + } +#endif editing_panel_modifiers(ob); break; diff --git a/source/blender/src/editfont.c b/source/blender/src/editfont.c index 278c70eb15f..4e2857a76bb 100644 --- a/source/blender/src/editfont.c +++ b/source/blender/src/editfont.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include @@ -86,7 +87,7 @@ int textediting=0; extern struct SelBox *selboxes; /* from blenkernel/font.c */ -static char findaccent(char char1, char code) +static char findaccent(char char1, unsigned int code) { char new= 0; @@ -217,15 +218,25 @@ static char findaccent(char char1, char code) else return char1; } -char *copybuf=NULL; -char *copybufinfo=NULL; +wchar_t *copybuf=NULL; +wchar_t *copybufinfo=NULL; -static char *textbuf=NULL; +static wchar_t *textbuf=NULL; static CharInfo *textbufinfo=NULL; -static char *oldstr=NULL; +static wchar_t *oldstr=NULL; static CharInfo *oldstrinfo=NULL; -static int insert_into_textbuf(Curve *cu, char c) +void update_string(Curve *cu) +{ + int len; + + MEM_freeN(cu->str); + len = wcsleninu8(textbuf); + cu->str = MEM_callocN(len + sizeof(wchar_t), "str"); + wcs2utf8s(cu->str, textbuf); +} + +static int insert_into_textbuf(Curve *cu, unsigned long c) { if (cu->lenlen++; textbuf[cu->len]='\0'; + update_string(cu); + return 1; } else { return 0; @@ -280,16 +293,36 @@ void add_lorem(void) void load_3dtext_fs(char *file) { FILE *fp; - int c; + int filelen; + char *strp; + Curve *cu=G.obedit->data; fp= fopen(file, "r"); if (!fp) return; - - while (!feof(fp)) { - c = fgetc(fp); - if (c!=EOF) insert_into_textbuf(OBACT->data, c); - } + + fseek(fp, 0L, SEEK_END); + filelen = ftell(fp); + fseek(fp, 0L, SEEK_SET); + + strp = MEM_callocN(filelen+4, "tempstr"); + + filelen = fread(strp, 1, filelen, fp); fclose(fp); + strp[filelen]= 0; + + if(cu->len+filelenlen += tmplen; + cu->pos= cu->len; + } + MEM_freeN(strp); + + update_string(cu); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); @@ -479,6 +512,7 @@ static int killselection(int ins) /* 1 == new character */ direction = getselection(&selstart, &selend); if (direction) { + int size; if (ins) offset = 1; if (cu->pos >= selstart) cu->pos = selstart+offset; if ((direction == -1) && ins) { @@ -487,7 +521,8 @@ static int killselection(int ins) /* 1 == new character */ } getfrom = selend+offset; if (ins==0) getfrom++; - memmove(textbuf+selstart, textbuf+getfrom, (cu->len-selstart)+offset); + size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t)); + memmove(textbuf+selstart, textbuf+getfrom, size); memmove(textbufinfo+selstart, textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo)); cu->len -= (selend-selstart)+offset; cu->selstart = cu->selend = 0; @@ -500,7 +535,7 @@ static void copyselection(void) int selstart, selend; if (getselection(&selstart, &selend)) { - memcpy(copybuf, textbuf+selstart, (selend-selstart)+1); + memcpy(copybuf, textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t)); copybuf[(selend-selstart)+1]=0; memcpy(copybufinfo, textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo)); } @@ -509,11 +544,12 @@ static void copyselection(void) static void pasteselection(void) { Curve *cu= G.obedit->data; - int len= strlen(copybuf); + int len= wcslen(copybuf); if (len) { - memmove(textbuf+cu->pos+len, textbuf+cu->pos, cu->len-cu->pos+1); - memcpy(textbuf+cu->pos, copybuf, len); + int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t); + memmove(textbuf+cu->pos+len, textbuf+cu->pos, size); + memcpy(textbuf+cu->pos, copybuf, len * sizeof(wchar_t)); memmove(textbufinfo+cu->pos+len, textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo)); memcpy(textbufinfo+cu->pos, copybufinfo, len*sizeof(CharInfo)); @@ -564,12 +600,12 @@ int mat_to_sel(void) { return 0; } -void do_textedit(unsigned short event, short val, char _ascii) +void do_textedit(unsigned short event, short val, unsigned long _ascii) { Curve *cu; static int accentcode= 0; int x, doit=0, cursmove=0; - int ascii = _ascii; + unsigned long ascii = _ascii; short kern; cu= G.obedit->data; @@ -608,7 +644,6 @@ void do_textedit(unsigned short event, short val, char _ascii) else if(ascii=='>') ascii= 187; else if(ascii=='<') ascii= 171; } - if(ascii==1001) { int file, filelen; char *strp; @@ -627,9 +662,14 @@ void do_textedit(unsigned short event, short val, char _ascii) read(file, strp, filelen); close(file); strp[filelen]= 0; + if(cu->len+filelenlen= strlen(textbuf); + int tmplen; + wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary"); + tmplen = utf8towchar_(mem, strp); + wcscat(textbuf, mem); + MEM_freeN(mem); + cu->len += tmplen; cu->pos= cu->len; } MEM_freeN(strp); @@ -644,6 +684,11 @@ void do_textedit(unsigned short event, short val, char _ascii) doit= 1; } + else + { + insert_into_textbuf(cu, ascii); + doit = 1; + } } else if(val) { cursmove= 0; @@ -841,6 +886,7 @@ void do_textedit(unsigned short event, short val, char _ascii) if ((G.qual & LR_SHIFTKEY)==0) { if (cu->selstart) { cu->selstart = cu->selend = 0; + update_string(cu); text_to_curve(G.obedit, FO_SELCHANGE); allqueue(REDRAWVIEW3D, 0); } @@ -860,6 +906,7 @@ void do_textedit(unsigned short event, short val, char _ascii) G.obedit->actcol = textbufinfo[cu->pos-1].mat_nr; } allqueue(REDRAWBUTSEDIT, 0); + update_string(cu); text_to_curve(G.obedit, cursmove); if (cursmove && (G.qual & LR_SHIFTKEY)) { cu->selend = cu->pos; @@ -874,16 +921,64 @@ void do_textedit(unsigned short event, short val, char _ascii) } } +void paste_unicodeText(char *filename) +{ + Curve *cu; + int filelen, doit= 0; + char *strp; + FILE *fp = NULL; + + fp= fopen(filename, "r"); + + if(fp) { + cu= G.obedit->data; + + fseek( fp, 0L, SEEK_END ); + filelen = ftell( fp ); + fseek( fp, 0L, SEEK_SET ); + + strp= MEM_mallocN(filelen+4, "tempstr"); + //fread() instead of read(), + //because windows read() converts text to DOS \r\n linebreaks + //causing double linebreaks in the 3d text + filelen = fread(strp, 1, filelen, fp); + fclose(fp); + strp[filelen]= 0; + + + if(cu->len+filelenlen = wcslen(textbuf); + cu->len += tmplen; + cu->pos= cu->len; + } + MEM_freeN(strp); + doit = 1; + } + if(doit) { + update_string(cu); + text_to_curve(G.obedit, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + BIF_undo_push("Paste text"); + } +} void paste_editText(void) { Curve *cu; - int file, filelen, doit= 0; + int filelen, doit= 0; char *strp; - + FILE *fp = NULL; #ifdef WIN32 - file= open("C:\\windows\\temp\\cutbuf.txt", O_BINARY|O_RDONLY); + fp= fopen("C:\\windows\\temp\\cutbuf.txt", "r"); // The following is more likely to work on all Win32 installations. // suggested by Douglas Toltzman. Needs windows include files... @@ -900,26 +995,39 @@ void paste_editText(void) } */ #else - file= open("/tmp/.cutbuffer", O_BINARY|O_RDONLY); + fp= fopen("/tmp/.cutbuffer", "r"); #endif - if(file>0) { + if(fp) { cu= G.obedit->data; - filelen = BLI_filesize(file); + + fseek(fp, 0L, SEEK_END); + filelen = ftell( fp ); + fseek(fp, 0L, SEEK_SET); strp= MEM_mallocN(filelen+4, "tempstr"); - read(file, strp, filelen); - close(file); + // fread() instead of read(), + // because windows read() converts text to DOS \r\n linebreaks + // causing double linebreaks in the 3d text + filelen = fread(strp, 1, filelen, fp); + fclose(fp); strp[filelen]= 0; + if(cu->len+filelenlen= strlen(textbuf); - cu->pos= cu->len; + int tmplen; + wchar_t *mem = MEM_callocN((sizeof(wchar_t) * filelen) + (4 * sizeof(wchar_t)), "temporary"); + tmplen = utf8towchar_(mem, strp); + wcscat(textbuf, mem); + MEM_freeN(mem); + cu->len += tmplen; + cu->pos= cu->len; } MEM_freeN(strp); doit = 1; } if(doit) { + update_string(cu); + text_to_curve(G.obedit, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); BIF_undo_push("Paste text"); @@ -930,19 +1038,23 @@ void paste_editText(void) void make_editText(void) { Curve *cu; - cu= G.obedit->data; - if(textbuf==NULL) textbuf= MEM_mallocN(MAXTEXT+4, "texteditbuf"); + + if(textbuf==NULL) textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf"); if(textbufinfo==NULL) textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo"); - if(copybuf==NULL) copybuf= MEM_callocN(MAXTEXT+4, "texteditcopybuf"); + if(copybuf==NULL) copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf"); if(copybufinfo==NULL) copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo"); - BLI_strncpy(textbuf, cu->str, MAXTEXT); - cu->len= strlen(textbuf); + if(oldstr==NULL) oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf"); + + // Convert the original text to wchar_t + utf8towchar_(textbuf, cu->str); + wcscpy(oldstr, textbuf); + + cu->len= wcslen(textbuf); memcpy(textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo)); - oldstr= cu->str; + oldstrinfo= cu->strinfo; - cu->str= textbuf; cu->strinfo= textbufinfo; if(cu->pos>cu->len) cu->pos= cu->len; @@ -951,6 +1063,9 @@ void make_editText(void) cu->curinfo = textbufinfo[cu->pos-1]; } else cu->curinfo = textbufinfo[0]; + // Convert to UTF-8 + update_string(cu); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); textediting= 1; @@ -969,8 +1084,8 @@ void load_editText(void) MEM_freeN(oldstrinfo); oldstrinfo= NULL; - cu->str= MEM_mallocN(cu->len+4, "textedit"); - strcpy(cu->str, textbuf); + update_string(cu); + cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo"); memcpy(cu->strinfo, textbufinfo, (cu->len)*sizeof(CharInfo)); @@ -1000,7 +1115,10 @@ void remake_editText(void) if(okee("Reload original text")==0) return; - BLI_strncpy(textbuf, oldstr, MAXTEXT); + // Copy the oldstr to textbuf temporary global variable + wcscpy(textbuf, oldstr); + + // Set the object length and position cu= G.obedit->data; cu->len= strlen(textbuf); if(cu->pos>cu->len) cu->pos= cu->len; @@ -1055,7 +1173,7 @@ void to_upper(void) { Curve *cu; int len, ok; - char *str; + wchar_t *str; if(G.obedit==0) { return; @@ -1064,8 +1182,8 @@ void to_upper(void) ok= 0; cu= G.obedit->data; - len= strlen(cu->str); - str= cu->str; + len= wcslen(textbuf); + str= textbuf; while(len) { if( *str>=97 && *str<=122) { ok= 1; @@ -1076,8 +1194,8 @@ void to_upper(void) } if(ok==0) { - len= strlen(cu->str); - str= cu->str; + len= wcslen(textbuf); + str= textbuf; while(len) { if( *str>=65 && *str<=90) { *str+= 32; @@ -1089,6 +1207,8 @@ void to_upper(void) DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); BIF_undo_push("To upper"); + + update_string(cu); } @@ -1099,9 +1219,10 @@ static void undoFont_to_editFont(void *strv) Curve *cu= G.obedit->data; char *str= strv; - strncpy(textbuf, str+2, MAXTEXT); + utf8towchar_(textbuf, str); + cu->pos= *((short *)str); - cu->len= strlen(textbuf); + cu->len= wcslen(textbuf); memcpy(textbufinfo, str+2+cu->len+1, cu->len*sizeof(CharInfo)); cu->selstart = cu->selend = 0; @@ -1117,7 +1238,8 @@ static void *editFont_to_undoFont(void) str= MEM_callocN(MAXTEXT+4+(MAXTEXT+4)*sizeof(CharInfo), "string undo"); - strncpy(str+2, textbuf, MAXTEXT); + wcs2utf8s(str, textbuf); + *((short *)str)= cu->pos; memcpy(str+2+cu->len+1, textbufinfo, cu->len*sizeof(CharInfo)); diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c index f914d03562c..c0bd38eb71f 100644 --- a/source/blender/src/interface.c +++ b/source/blender/src/interface.c @@ -68,6 +68,8 @@ #include "DNA_space_types.h" #include "DNA_userdef_types.h" #include "DNA_vec_types.h" +#include "DNA_object_types.h" +#include "DNA_vfont_types.h" #include "BKE_blender.h" #include "BKE_utildefines.h" @@ -2687,6 +2689,56 @@ static int ui_do_but_HSVCUBE(uiBut *but) return but->retval; } +#ifdef INTERNATIONAL + +static int ui_do_but_CHARTAB(uiBut *but) +{ + /* Variables */ + short mval[2]; + float sx, sy, ex, ey; + float width, height; + float butw, buth; + int x, y; + unsigned long cs; + unsigned long che; + + /* Check the position */ + uiGetMouse(mywinget(), mval); + + /* Calculate the size of the button */ + width = abs(but->x2 - but->x1); + height = abs(but->y2 - but->y1); + + butw = floor(width / 12); + buth = floor(height / 6); + + /* Initialize variables */ + sx = but->x1; + ex = but->x1 + butw; + sy = but->y1 + height - buth; + ey = but->y1 + height; + + cs = G.charstart; + + /* And the character is */ + x = (int) ((mval[0] / butw) - 0.5); + y = (int) (6 - ((mval[1] / buth) - 0.5)); + + che = cs + (y*12) + x; + + if(che > G.charmax) + che = 0; + + if(G.obedit) + { + do_textedit(0,0,che); + } + + return but->retval; +} + +#endif + /* ************************************************ */ @@ -2925,6 +2977,12 @@ static int ui_do_button(uiBlock *block, uiBut *but, uiEvent *uevent) case HSVCUBE: retval= ui_do_but_HSVCUBE(but); break; + +#ifdef INTERNATIONAL + case CHARTAB: + retval= ui_do_but_CHARTAB(but); + break; +#endif } block->flag &= ~UI_BLOCK_BUSY; @@ -3383,7 +3441,66 @@ static int ui_do_block(uiBlock *block, uiEvent *uevent) } } break; + + +#ifdef INTERNATIONAL + //HACK to let the chartab button react to the mousewheel and PGUP/PGDN keys + case WHEELUPMOUSE: + case PAGEUPKEY: + for(but= block->buttons.first; but; but= but->next) + { + if(but->type == CHARTAB && (but->flag & UI_MOUSE_OVER)) + { + G.charstart = G.charstart - (12*6); + if(G.charstart < 0) + G.charstart = 0; + if(G.charstart < G.charmin) + G.charstart = G.charmin; + ui_draw_but(but); + + //Really nasty... to update the num button from the same butblock + for(bt= block->buttons.first; bt; bt= bt->next) + { + if(bt->type == NUM) { + ui_check_but(bt); + ui_draw_but(bt); + } + } + retval=UI_CONT; + break; + } + } + break; + case WHEELDOWNMOUSE: + case PAGEDOWNKEY: + for(but= block->buttons.first; but; but= but->next) + { + if(but->type == CHARTAB && (but->flag & UI_MOUSE_OVER)) + { + G.charstart = G.charstart + (12*6); + if(G.charstart > (0xffff - 12*6)) + G.charstart = 0xffff - (12*6); + if(G.charstart > G.charmax - 12*6) + G.charstart = G.charmax - 12*6; + ui_draw_but(but); + + for(bt= block->buttons.first; bt; bt= bt->next) + { + if(bt->type == NUM) { + ui_check_but(bt); + ui_draw_but(bt); + } + } + + but->flag |= UI_ACTIVE; + retval=UI_RETURN_OK; + break; + } + } + break; +#endif + case PADENTER: case RETKEY: // prevent treating this as mousemove. for example when you enter at popup if(block->flag & UI_BLOCK_LOOP) break; diff --git a/source/blender/src/interface_draw.c b/source/blender/src/interface_draw.c index 92f38cbd1e8..4d933abab69 100644 --- a/source/blender/src/interface_draw.c +++ b/source/blender/src/interface_draw.c @@ -1,3 +1,4 @@ + /** * $Id$ * @@ -58,6 +59,8 @@ #include "DNA_space_types.h" #include "DNA_userdef_types.h" #include "DNA_vec_types.h" +#include "DNA_vfont_types.h" +#include "DNA_packedFile_types.h" #include "BKE_blender.h" #include "BKE_utildefines.h" @@ -79,6 +82,8 @@ #include "BSE_view.h" +#include "FTF_Api.h" + #include "mydevice.h" #include "interface.h" #include "blendef.h" @@ -1698,6 +1703,129 @@ static void ui_draw_but_HSVCUBE(uiBut *but) fdrawbox((but->x1), (but->y1), (but->x2), (but->y2)); } +#ifdef INTERNATIONAL +static void ui_draw_but_CHARTAB(uiBut *but) +{ + /* Some local variables */ + float sx, sy, ex, ey; + float width, height; + float butw, buth; + int x, y; + unsigned long cs; + wchar_t wstr[2]; + unsigned char ustr[16]; + PackedFile *pf; + + /* Calculate the size of the button */ + width = abs(but->x2 - but->x1); + height = abs(but->y2 - but->y1); + + butw = floor(width / 12); + buth = floor(height / 6); + + /* Initialize variables */ + sx = but->x1; + ex = but->x1 + butw; + sy = but->y1 + height - buth; + ey = but->y1 + height; + + cs = G.charstart; + + /* Set the font */ + if(G.selfont && strcmp(G.selfont->name, "")) + { + char tmpStr[256]; + + // Is the font file packed, if so then use the packed file + if(G.selfont->packedfile) + { + pf = G.selfont->packedfile; + FTF_SetFont(pf->data, pf->size, 14.0); + } + else + { + int err; + + strcpy(tmpStr, G.selfont->name); + BLI_convertstringcode(tmpStr, G.sce, 0); + err = FTF_SetFont(tmpStr, 0, 14.0); + } + } + + /* Start drawing the button itself */ + glShadeModel(GL_SMOOTH); + + glColor3ub(200, 200, 200); + glRectf((but->x1), (but->y1), (but->x2), (but->y2)); + + glColor3ub(0, 0, 0); + for(y = 0; y < 6; y++) + { + // Do not draw more than the category allows + if(cs > G.charmax) break; + + for(x = 0; x < 12; x++) + { + // Do not draw more than the category allows + if(cs > G.charmax) break; + + // Draw one grid cell + glBegin(GL_LINE_LOOP); + glVertex2f(sx, sy); + glVertex2f(ex, sy); + glVertex2f(ex, ey); + glVertex2f(sx, ey); + glEnd(); + + // Draw character inside the cell + memset(wstr, 0, sizeof(wchar_t)*2); + memset(ustr, 0, 16); + + wstr[0] = cs; + wcs2utf8s(ustr, wstr); + + if(G.selfont && strcmp(G.selfont->name, "")) + { + float wid; + float llx, lly, llz, urx, ury, urz; + float dx, dy; + float px, py; + + // Calculate the position + wid = FTF_GetStringWidth(ustr, FTF_USE_GETTEXT | FTF_INPUT_UTF8); + FTF_GetBoundingBox(ustr, &llx,&lly,&llz,&urx,&ury,&urz, FTF_USE_GETTEXT | FTF_INPUT_UTF8); + dx = urx-llx; + dy = ury-lly; + + // This isn't fully functional since the but->aspect isn't working like I suspected + px = sx + ((butw/but->aspect)-dx)/2; + py = sy + ((buth/but->aspect)-dy)/2; + + // Set the position and draw the character + ui_rasterpos_safe(px, py, but->aspect); + FTF_DrawString(ustr, FTF_USE_GETTEXT | FTF_INPUT_UTF8); + } + else + { + ui_rasterpos_safe(sx + butw/2, sy + buth/2, but->aspect); + BIF_DrawString(but->font, ustr, 0); + } + + // Calculate the next position and character + sx += butw; ex +=butw; + cs++; + } + /* Add the y position and reset x position */ + sy -= buth; + ey -= buth; + sx = but->x1; + ex = but->x1 + butw; + } + glShadeModel(GL_FLAT); +} + +#endif // INTERNATIONAL + static void ui_draw_roundbox(uiBut *but) { BIF_ThemeColorShade(but->themecol, but->a2); @@ -1754,7 +1882,6 @@ void ui_set_embossfunc(uiBut *but, int drawtype) // note: if you want aligning, adapt the call uiBlockEndAlign in interface.c } - void ui_draw_but(uiBut *but) { double value; @@ -1796,6 +1923,13 @@ void ui_draw_but(uiBut *but) ui_draw_but_HSVCUBE(but); // box for colorpicker, three types break; +#ifdef INTERNATIONAL + case CHARTAB: + value= ui_get_but_val(but); + ui_draw_but_CHARTAB(but); + break; +#endif + case LINK: case INLINK: ui_draw_icon(but, but->icon); diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c index 56cb25b5c55..d5b35bdff60 100644 --- a/source/blender/src/usiblender.c +++ b/source/blender/src/usiblender.c @@ -78,6 +78,8 @@ #include "BKE_packedFile.h" #include "BKE_utildefines.h" +#include "BLI_vfontdata.h" + #include "BIF_fsmenu.h" #include "BIF_gl.h" #include "BIF_interface.h" @@ -291,9 +293,20 @@ int BIF_read_homefile(void) char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR]; char *home= BLI_gethome(); int success; + struct TmpFont *tf; BLI_clean(home); + tf= G.ttfdata.first; + while(tf) + { + freePackedFile(tf->pf); + tf->pf = NULL; + tf->vfont = NULL; + tf= tf->next; + } + BLI_freelistN(&G.ttfdata); + #if 0 //#ifdef _WIN32 // FULLSCREEN static int screenmode = -1; @@ -632,6 +645,17 @@ extern ListBase editelems; void exit_usiblender(void) { + struct TmpFont *tf; + tf= G.ttfdata.first; + while(tf) + { + freePackedFile(tf->pf); + tf->pf= NULL; + tf->vfont= NULL; + tf= tf->next; + } + BLI_freelistN(&G.ttfdata); + freeAllRad(); BKE_freecubetable();