6 * ***** BEGIN GPL LICENSE BLOCK *****
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23 * All rights reserved.
25 * The Original Code is: all of this file.
27 * Contributor(s): none yet.
29 * ***** END GPL LICENSE BLOCK *****
32 /** \file blender/blenkernel/intern/font.c
44 #include "MEM_guardedalloc.h"
47 #include "BLI_blenlib.h"
48 #include "BLI_vfontdata.h"
49 #include "BLI_utildefines.h"
51 #include "DNA_packedFile_types.h"
52 #include "DNA_curve_types.h"
53 #include "DNA_vfont_types.h"
54 #include "DNA_scene_types.h"
55 #include "DNA_object_types.h"
57 #include "BKE_utildefines.h"
58 #include "BKE_packedFile.h"
59 #include "BKE_library.h"
61 #include "BKE_global.h"
64 #include "BKE_curve.h"
65 #include "BKE_displist.h"
67 static ListBase ttfdata= {NULL, NULL};
69 /* UTF-8 <-> wchar transformations */
70 size_t chtoutf8(const unsigned long c, char o[4])
72 // Variables and initialization
73 /* memset(o, 0, 4); */
75 // Create the utf-8 string
81 o[0] = (0xC0 | (c>>6));
82 o[1] = (0x80 | (c & 0x3f));
85 else if (c < 0x10000) {
86 o[0] = (0xe0 | (c >> 12));
87 o[1] = (0x80 | (c >>6 & 0x3f));
88 o[2] = (0x80 | (c & 0x3f));
91 else if (c < 0x200000) {
92 o[0] = (0xf0 | (c>>18));
93 o[1] = (0x80 | (c >>12 & 0x3f));
94 o[2] = (0x80 | (c >> 6 & 0x3f));
95 o[3] = (0x80 | (c & 0x3f));
99 /* should we assert here? */
103 void wcs2utf8s(char *dst, const wchar_t *src)
106 dst += chtoutf8(*src++, dst);
112 size_t wcsleninu8(wchar_t *src)
118 len += chtoutf8(*src++, ch_dummy);
124 static size_t utf8slen(const char *strc)
129 if ((*strc & 0xe0) == 0xc0) {
130 if((strc[1] & 0x80) && (strc[1] & 0x40) == 0x00)
132 } else if ((*strc & 0xf0) == 0xe0) {
133 if((strc[1] & strc[2] & 0x80) && ((strc[1] | strc[2]) & 0x40) == 0x00)
135 } else if ((*strc & 0xf8) == 0xf0) {
136 if((strc[1] & strc[2] & strc[3] & 0x80) && ((strc[1] | strc[2] | strc[3]) & 0x40) == 0x00)
148 /* Converts Unicode to wchar
150 According to RFC 3629 "UTF-8, a transformation format of ISO 10646"
151 (http://tools.ietf.org/html/rfc3629), the valid UTF-8 encoding are:
153 Char. number range | UTF-8 octet sequence
154 (hexadecimal) | (binary)
155 --------------------+---------------------------------------------
156 0000 0000-0000 007F | 0xxxxxxx
157 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
158 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
159 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
161 If the encoding incidated by the first character is incorrect (because the
162 1 to 3 following characters do not match 10xxxxxx), the output is a '?' and
163 only a single input character is consumed.
167 size_t utf8towchar(wchar_t *w, const char *c)
171 if(w==NULL || c==NULL) return(0);
174 if ((*c & 0xe0) == 0xc0) {
175 if((c[1] & 0x80) && (c[1] & 0x40) == 0x00) {
176 *w=((c[0] &0x1f)<<6) | (c[1]&0x3f);
181 } else if ((*c & 0xf0) == 0xe0) {
182 if((c[1] & c[2] & 0x80) && ((c[1] | c[2]) & 0x40) == 0x00) {
183 *w=((c[0] & 0x0f)<<12) | ((c[1]&0x3f)<<6) | (c[2]&0x3f);
188 } else if ((*c & 0xf8) == 0xf0) {
189 if((c[1] & c[2] & c[3] & 0x80) && ((c[1] | c[2] | c[3]) & 0x40) == 0x00) {
190 *w=((c[0] & 0x07)<<18) | ((c[1]&0x1f)<<12) | ((c[2]&0x3f)<<6) | (c[3]&0x3f);
206 void free_vfont(struct VFont *vf)
208 if (vf == NULL) return;
211 while(vf->data->characters.first)
213 VChar *che = vf->data->characters.first;
215 while (che->nurbsbase.first) {
216 Nurb *nu = che->nurbsbase.first;
217 if (nu->bezt) MEM_freeN(nu->bezt);
218 BLI_freelinkN(&che->nurbsbase, nu);
221 BLI_freelinkN(&vf->data->characters, che);
228 if (vf->packedfile) {
229 freePackedFile(vf->packedfile);
230 vf->packedfile = NULL;
234 static void *builtin_font_data= NULL;
235 static int builtin_font_size= 0;
237 void BKE_font_register_builtin(void *mem, int size)
239 builtin_font_data= mem;
240 builtin_font_size= size;
243 static PackedFile *get_builtin_packedfile(void)
245 if (!builtin_font_data) {
246 printf("Internal error, builtin font not loaded\n");
250 void *mem= MEM_mallocN(builtin_font_size, "vfd_builtin");
252 memcpy(mem, builtin_font_data, builtin_font_size);
254 return newPackedFileMemory(mem, builtin_font_size);
258 void free_ttfont(void)
262 for(tf= ttfdata.first; tf; tf= tf->next) {
263 if(tf->pf) freePackedFile(tf->pf); /* NULL when the font file can't be found on disk */
267 BLI_freelistN(&ttfdata);
270 struct TmpFont *vfont_find_tmpfont(VFont *vfont)
272 struct TmpFont *tmpfnt = NULL;
274 if(vfont==NULL) return NULL;
276 // Try finding the font from font list
277 tmpfnt = ttfdata.first;
280 if(tmpfnt->vfont == vfont)
282 tmpfnt = tmpfnt->next;
287 static VFontData *vfont_get_data(VFont *vfont)
289 struct TmpFont *tmpfnt = NULL;
292 if(vfont==NULL) return NULL;
294 // Try finding the font from font list
295 tmpfnt = vfont_find_tmpfont(vfont);
297 // And then set the data
301 if (strcmp(vfont->name, FO_BUILTIN_NAME)==0) {
302 pf= get_builtin_packedfile();
304 if (vfont->packedfile) {
305 pf= vfont->packedfile;
307 // We need to copy a tmp font to memory unless it is already there
310 tpf= MEM_callocN(sizeof(*tpf), "PackedFile");
311 tpf->data= MEM_mallocN(pf->size, "packFile");
313 memcpy(tpf->data, pf->data, pf->size);
315 // Add temporary packed file to globals
316 tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
318 tmpfnt->vfont= vfont;
319 BLI_addtail(&ttfdata, tmpfnt);
322 pf= newPackedFile(NULL, vfont->name);
326 tpf= newPackedFile(NULL, vfont->name);
328 // Add temporary packed file to globals
329 tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
331 tmpfnt->vfont= vfont;
332 BLI_addtail(&ttfdata, tmpfnt);
336 printf("Font file doesn't exist: %s\n", vfont->name);
338 strcpy(vfont->name, FO_BUILTIN_NAME);
339 pf= get_builtin_packedfile();
344 vfont->data= BLI_vfontdata_from_freetypefont(pf);
345 if (pf != vfont->packedfile) {
354 VFont *load_vfont(const char *name)
356 char filename[FILE_MAXFILE];
359 PackedFile *tpf = NULL;
361 struct TmpFont *tmpfnt;
363 if (strcmp(name, FO_BUILTIN_NAME)==0) {
364 BLI_strncpy(filename, name, sizeof(filename));
366 pf= get_builtin_packedfile();
369 char dir[FILE_MAXDIR];
371 BLI_strncpy(dir, name, sizeof(dir));
372 BLI_splitdirstring(dir, filename);
374 pf= newPackedFile(NULL, name);
375 tpf= newPackedFile(NULL, name);
383 vfd= BLI_vfontdata_from_freetypefont(pf);
385 vfont = alloc_libblock(&G.main->vfont, ID_VF, filename);
388 /* if there's a font name, use it for the ID name */
389 if (strcmp(vfd->name, "")!=0) {
390 BLI_strncpy(vfont->id.name+2, vfd->name, sizeof(vfont->id.name)-2);
392 BLI_strncpy(vfont->name, name, sizeof(vfont->name));
394 // if autopack is on store the packedfile in de font structure
395 if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
396 vfont->packedfile = pf;
399 // Do not add FO_BUILTIN_NAME to temporary listbase
400 if(strcmp(filename, FO_BUILTIN_NAME))
402 tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
404 tmpfnt->vfont= vfont;
405 BLI_addtail(&ttfdata, tmpfnt);
409 // Free the packed file
410 if (!vfont || vfont->packedfile != pf) {
420 static VFont *which_vfont(Curve *cu, CharInfo *info)
422 switch(info->flag & (CU_CHINFO_BOLD|CU_CHINFO_ITALIC)) {
424 if (cu->vfontb) return(cu->vfontb); else return(cu->vfont);
425 case CU_CHINFO_ITALIC:
426 if (cu->vfonti) return(cu->vfonti); else return(cu->vfont);
427 case (CU_CHINFO_BOLD|CU_CHINFO_ITALIC):
428 if (cu->vfontbi) return(cu->vfontbi); else return(cu->vfont);
434 VFont *get_builtin_font(void)
438 for (vf= G.main->vfont.first; vf; vf= vf->id.next)
439 if (strcmp(vf->name, FO_BUILTIN_NAME)==0)
442 return load_vfont(FO_BUILTIN_NAME);
445 static VChar *find_vfont_char(VFontData *vfd, intptr_t character)
449 for(che = vfd->characters.first; che; che = che->next) {
450 if(che->index == character)
453 return che; /* NULL if not found */
456 static void build_underline(Curve *cu, float x1, float y1, float x2, float y2, int charidx, short mat_nr)
461 nu2 =(Nurb*) MEM_callocN(sizeof(Nurb),"underline_nurb");
462 if (nu2 == NULL) return;
463 nu2->resolu= cu->resolu;
465 nu2->knotsu = nu2->knotsv = NULL;
467 nu2->charidx = charidx+1000;
468 if (mat_nr > 0) nu2->mat_nr= mat_nr-1;
473 nu2->flagu = CU_NURB_CYCLIC;
475 bp = (BPoint*)MEM_callocN(4 * sizeof(BPoint),"underline_bp");
482 nu2->bp[0].vec[0] = x1;
483 nu2->bp[0].vec[1] = y1;
484 nu2->bp[0].vec[2] = 0;
485 nu2->bp[0].vec[3] = 1.0f;
486 nu2->bp[1].vec[0] = x2;
487 nu2->bp[1].vec[1] = y1;
488 nu2->bp[1].vec[2] = 0;
489 nu2->bp[1].vec[3] = 1.0f;
490 nu2->bp[2].vec[0] = x2;
491 nu2->bp[2].vec[1] = y2;
492 nu2->bp[2].vec[2] = 0;
493 nu2->bp[2].vec[3] = 1.0f;
494 nu2->bp[3].vec[0] = x1;
495 nu2->bp[3].vec[1] = y2;
496 nu2->bp[3].vec[2] = 0;
497 nu2->bp[3].vec[3] = 1.0f;
499 BLI_addtail(&(cu->nurb), nu2);
503 static void buildchar(Curve *cu, unsigned long character, CharInfo *info, float ofsx, float ofsy, float rot, int charidx)
505 BezTriple *bezt1, *bezt2;
506 Nurb *nu1 = NULL, *nu2 = NULL;
507 float *fp, fsize, shear, x, si, co;
508 VFontData *vfd = NULL;
512 vfd= vfont_get_data(which_vfont(cu, info));
516 if (cu->selend < cu->selstart) {
517 if ((charidx >= (cu->selend)) && (charidx <= (cu->selstart-2)))
521 if ((charidx >= (cu->selstart-1)) && (charidx <= (cu->selend-1)))
526 /* make a copy at distance ofsx,ofsy with shear*/
532 che= find_vfont_char(vfd, character);
534 // Select the glyph data
536 nu1 = che->nurbsbase.first;
538 // Create the character
543 nu2 =(Nurb*) MEM_mallocN(sizeof(Nurb),"duplichar_nurb");
544 if (nu2 == NULL) break;
545 memcpy(nu2, nu1, sizeof(struct Nurb));
546 nu2->resolu= cu->resolu;
548 nu2->knotsu = nu2->knotsv = NULL;
549 nu2->flag= CU_SMOOTH;
550 nu2->charidx = charidx;
552 nu2->mat_nr= info->mat_nr-1;
557 /* nu2->trim.first = 0; */
558 /* nu2->trim.last = 0; */
561 bezt2 = (BezTriple*)MEM_mallocN(i * sizeof(BezTriple),"duplichar_bezt2");
566 memcpy(bezt2, bezt1, i * sizeof(struct BezTriple));
572 for (i= nu2->pntsu; i > 0; i--) {
573 bezt2->vec[0][0] += shear * bezt2->vec[0][1];
574 bezt2->vec[1][0] += shear * bezt2->vec[1][1];
575 bezt2->vec[2][0] += shear * bezt2->vec[2][1];
581 for (i=nu2->pntsu; i > 0; i--) {
585 fp[0]= co*x + si*fp[1];
586 fp[1]= -si*x + co*fp[1];
588 fp[3]= co*x + si*fp[4];
589 fp[4]= -si*x + co*fp[4];
591 fp[6]= co*x + si*fp[7];
592 fp[7]= -si*x + co*fp[7];
599 if(info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
600 const float sca= cu->smallcaps_scale;
601 for (i= nu2->pntsu; i > 0; i--) {
614 for (i= nu2->pntsu; i > 0; i--) {
616 fp[0]= (fp[0]+ofsx)*fsize;
617 fp[1]= (fp[1]+ofsy)*fsize;
618 fp[3]= (fp[3]+ofsx)*fsize;
619 fp[4]= (fp[4]+ofsy)*fsize;
620 fp[6]= (fp[6]+ofsx)*fsize;
621 fp[7]= (fp[7]+ofsy)*fsize;
625 BLI_addtail(&(cu->nurb), nu2);
632 int BKE_font_getselection(Object *ob, int *start, int *end)
636 if (cu->editfont==NULL || ob->type != OB_FONT) return 0;
638 if (cu->selstart == 0) return 0;
639 if (cu->selstart <= cu->selend) {
640 *start = cu->selstart-1;
646 *end = cu->selstart-2;
651 static float char_width(Curve *cu, VChar *che, CharInfo *info)
653 // The character wasn't found, propably ascii = 0, then the width shall be 0 as well
657 else if(info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
658 return che->width * cu->smallcaps_scale;
665 struct chartrans *BKE_text_to_curve(Scene *scene, Object *ob, int mode)
667 VFont *vfont, *oldvfont;
668 VFontData *vfd= NULL;
670 CharInfo *info = NULL, *custrinfo;
673 struct chartrans *chartransdata=NULL, *ct;
674 float *f, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4;
675 float twidth, maxlen= 0;
678 int selstart, selend;
680 short cnr=0, lnr=0, wsnr= 0;
681 wchar_t *mem, *tmp, ascii;
683 /* renark: do calculations including the trailing '\0' of a string
684 because the cursor can be at that location */
686 if(ob->type!=OB_FONT) return NULL;
689 cu= (Curve *) ob->data;
692 if(cu->str == NULL) return NULL;
693 if(vfont == NULL) return NULL;
695 // Create unicode string
696 utf8len = utf8slen(cu->str);
697 mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem");
699 utf8towchar(mem, cu->str);
701 // Count the wchar_t string length
704 if (cu->ulheight == 0.0f)
705 cu->ulheight = 0.05f;
707 if (cu->strinfo==NULL) /* old file */
708 cu->strinfo = MEM_callocN((slen+4) * sizeof(CharInfo), "strinfo compat");
710 custrinfo= cu->strinfo;
712 custrinfo= cu->editfont->textbufinfo;
715 cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBox compat");
717 vfd= vfont_get_data(vfont);
719 /* The VFont Data can not be found */
726 /* calc offset and rotation of each char */
728 (struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext");
730 /* We assume the worst case: 1 character per line (is freed at end anyway) */
732 linedata= MEM_mallocN(sizeof(float)*(slen*2 + 1),"buildtext2");
733 linedata2= MEM_mallocN(sizeof(float)*(slen*2 + 1),"buildtext3");
734 linedata3= MEM_callocN(sizeof(float)*(slen*2 + 1),"buildtext4");
735 linedata4= MEM_callocN(sizeof(float)*(slen*2 + 1),"buildtext5");
737 linedist= cu->linedist;
739 xof= cu->xof + (cu->tb[0].x/cu->fsize);
740 yof= cu->yof + (cu->tb[0].y/cu->fsize);
742 xtrax= 0.5f*cu->spacing-0.5f;
746 for (i=0; i<slen; i++) custrinfo[i].flag &= ~(CU_CHINFO_WRAP|CU_CHINFO_SMALLCAPS_CHECK);
748 if (cu->selboxes) MEM_freeN(cu->selboxes);
750 if (BKE_font_getselection(ob, &selstart, &selend))
751 cu->selboxes = MEM_callocN((selend-selstart+1)*sizeof(SelBox), "font selboxes");
755 for (i = 0 ; i<=slen ; i++) {
757 // Characters in the list
758 info = &(custrinfo[i]);
760 if(info->flag & CU_CHINFO_SMALLCAPS) {
761 ascii = towupper(ascii);
762 if(mem[i] != ascii) {
764 info->flag |= CU_CHINFO_SMALLCAPS_CHECK;
768 vfont = which_vfont(cu, info);
770 if(vfont==NULL) break;
772 che= find_vfont_char(vfd, ascii);
775 * The character wasn't in the current curve base so load it
776 * But if the font is FO_BUILTIN_NAME then do not try loading since
777 * whole font is in the memory already
779 if(che == NULL && strcmp(vfont->name, FO_BUILTIN_NAME)) {
780 BLI_vfontchar_from_freetypefont(vfont, ascii);
783 /* Try getting the character again from the list */
784 che= find_vfont_char(vfd, ascii);
790 MEM_freeN(chartransdata);
794 if (vfont != oldvfont) {
795 vfd= vfont_get_data(vfont);
799 /* VFont Data for VFont couldn't be found */
803 MEM_freeN(chartransdata);
807 twidth = char_width(cu, che, info);
809 // Calculate positions
810 if((tb->w != 0.0f) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+twidth)*cu->fsize) > tb->w + cu->xof*cu->fsize) {
811 // fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]);
812 for (j=i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak==0); j--) {
813 if (mem[j]==' ' || mem[j]=='-') {
816 if (mem[j] == ' ') wsnr--;
817 if (mem[j] == '-') wsnr++;
821 custrinfo[i+1].flag |= CU_CHINFO_WRAP;
824 if (chartransdata[j].dobreak) {
825 // fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]);
827 custrinfo[i+1].flag |= CU_CHINFO_WRAP;
836 if(ascii== '\n' || ascii== '\r' || ascii==0 || ct->dobreak) {
844 maxlen= MAX2(maxlen, (xof-tb->x/cu->fsize));
845 linedata[lnr]= xof-tb->x/cu->fsize;
847 linedata3[lnr]= tb->w/cu->fsize;
848 linedata4[lnr]= wsnr;
850 if ( (tb->h != 0.0f) &&
851 ((-(yof-(tb->y/cu->fsize))) > ((tb->h/cu->fsize)-(linedist*cu->fsize)) - cu->yof) &&
852 (cu->totbox > (curbox+1)) ) {
856 yof= cu->yof + tb->y/cu->fsize;
859 /* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
861 if(ascii == '\n' || ascii == '\r')
864 xof= cu->xof + (tb->x/cu->fsize);
866 xof= cu->xof + (tb->x/cu->fsize);
872 else if(ascii==9) { /* TAB */
880 tabfac= (xof-cu->xof+0.01f);
881 tabfac= 2.0f*ceilf(tabfac/2.0f);
893 if (cu->selboxes && (i>=selstart) && (i<=selend)) {
894 sb = &(cu->selboxes[i-selstart]);
895 sb->y = yof*cu->fsize-linedist*cu->fsize*0.1f;
896 sb->h = linedist*cu->fsize;
897 sb->w = xof*cu->fsize;
901 wsfac = cu->wordspace;
906 // Set the width of the character
907 twidth = char_width(cu, che, info);
909 xof += (twidth*wsfac*(1.0f+(info->kern/40.0f)) ) + xtrax;
912 sb->w = (xof*cu->fsize) - sb->w;
920 for (i= 0; i<=slen; i++, tmp++, ct++) {
922 if(ascii== '\n' || ascii== '\r' || ct->dobreak) cu->lines++;
925 // linedata is now: width of line
926 // linedata2 is now: number of characters
927 // linedata3 is now: maxlen of that line
928 // linedata4 is now: number of whitespaces of line
930 if(cu->spacemode!=CU_LEFT) {
933 if(cu->spacemode==CU_RIGHT) {
934 for(i=0;i<lnr;i++) linedata[i]= linedata3[i]-linedata[i];
935 for (i=0; i<=slen; i++) {
936 ct->xof+= linedata[ct->linenr];
939 } else if(cu->spacemode==CU_MIDDLE) {
940 for(i=0;i<lnr;i++) linedata[i]= (linedata3[i]-linedata[i])/2;
941 for (i=0; i<=slen; i++) {
942 ct->xof+= linedata[ct->linenr];
945 } else if((cu->spacemode==CU_FLUSH) &&
946 (cu->tb[0].w != 0.0f)) {
949 linedata[i]= (linedata3[i]-linedata[i])/(linedata2[i]-1);
950 for (i=0; i<=slen; i++) {
951 for (j=i; (mem[j]) && (mem[j]!='\n') &&
952 (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
953 // if ((mem[j]!='\r') && (mem[j]!='\n') && (mem[j])) {
954 ct->xof+= ct->charnr*linedata[ct->linenr];
959 else if((cu->spacemode==CU_JUSTIFY) && (cu->tb[0].w != 0.0f)) {
961 for (i=0; i<=slen; i++) {
962 for (j=i; (mem[j]) && (mem[j]!='\n') &&
963 (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
964 if ((mem[j]!='\r') && (mem[j]!='\n') &&
965 ((chartransdata[j].dobreak!=0))) {
966 if (mem[i]==' ') curofs += (linedata3[ct->linenr]-linedata[ct->linenr])/linedata4[ct->linenr];
969 if (mem[i]=='\n' || mem[i]=='\r' || chartransdata[i].dobreak) curofs= 0;
976 /* Note: Only OB_CURVE objects could have a path */
977 if(cu->textoncurve && cu->textoncurve->type==OB_CURVE) {
978 Curve *cucu= cu->textoncurve->data;
979 int oldflag= cucu->flag;
981 cucu->flag |= (CU_PATH+CU_FOLLOW);
983 if(cucu->path==NULL) makeDispListCurveTypes(scene, cu->textoncurve, 0);
985 float distfac, imat[4][4], imat3[3][3], cmat[3][3];
986 float minx, maxx, miny, maxy;
987 float timeofs, sizefac;
989 invert_m4_m4(imat, ob->obmat);
990 copy_m3_m4(imat3, imat);
992 copy_m3_m4(cmat, cu->textoncurve->obmat);
993 mul_m3_m3m3(cmat, cmat, imat3);
994 sizefac= normalize_v3(cmat[0])/cu->fsize;
999 for (i=0; i<=slen; i++, ct++) {
1000 if(minx>ct->xof) minx= ct->xof;
1001 if(maxx<ct->xof) maxx= ct->xof;
1002 if(miny>ct->yof) miny= ct->yof;
1003 if(maxy<ct->yof) maxy= ct->yof;
1006 /* we put the x-coordinaat exact at the curve, the y is rotated */
1008 /* length correction */
1009 distfac= sizefac*cucu->path->totdist/(maxx-minx);
1012 if(distfac > 1.0f) {
1013 /* path longer than text: spacemode involves */
1014 distfac= 1.0f/distfac;
1016 if(cu->spacemode==CU_RIGHT) {
1017 timeofs= 1.0f-distfac;
1019 else if(cu->spacemode==CU_MIDDLE) {
1020 timeofs= (1.0f-distfac)/2.0f;
1022 else if(cu->spacemode==CU_FLUSH) distfac= 1.0f;
1027 distfac/= (maxx-minx);
1029 timeofs+= distfac*cu->xof; /* not cyclic */
1032 for (i=0; i<=slen; i++, ct++) {
1033 float ctime, dtime, vec[4], tvec[4], rotvec[3];
1036 /* rotate around center character */
1039 che= find_vfont_char(vfd, ascii);
1041 twidth = char_width(cu, che, info);
1043 dtime= distfac*0.5f*twidth;
1045 ctime= timeofs + distfac*( ct->xof - minx);
1046 CLAMP(ctime, 0.0f, 1.0f);
1048 /* calc the right loc AND the right rot separately */
1049 /* vec, tvec need 4 items */
1050 where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL);
1051 where_on_path(cu->textoncurve, ctime+dtime, tvec, rotvec, NULL, NULL, NULL);
1053 mul_v3_fl(vec, sizefac);
1055 ct->rot= (float)(M_PI-atan2(rotvec[1], rotvec[0]));
1057 si= (float)sin(ct->rot);
1058 co= (float)cos(ct->rot);
1062 ct->xof= vec[0] + si*yof;
1063 ct->yof= vec[1] + co*yof;
1066 cucu->flag= oldflag;
1072 for (i=0; i<=selend; i++, ct++) {
1074 cu->selboxes[i-selstart].x = ct->xof*cu->fsize;
1075 cu->selboxes[i-selstart].y = ct->yof*cu->fsize;
1080 if(mode==FO_CURSUP || mode==FO_CURSDOWN || mode==FO_PAGEUP || mode==FO_PAGEDOWN) {
1083 ct= chartransdata+cu->pos;
1085 if((mode==FO_CURSUP || mode==FO_PAGEUP) && ct->linenr==0);
1086 else if((mode==FO_CURSDOWN || mode==FO_PAGEDOWN) && ct->linenr==lnr);
1089 case FO_CURSUP: lnr= ct->linenr-1; break;
1090 case FO_CURSDOWN: lnr= ct->linenr+1; break;
1091 case FO_PAGEUP: lnr= ct->linenr-10; break;
1092 case FO_PAGEDOWN: lnr= ct->linenr+10; break;
1095 /* seek for char with lnr en cnr */
1098 for (i= 0; i<slen; i++) {
1099 if(ct->linenr==lnr) {
1100 if(ct->charnr==cnr) break;
1101 if( (ct+1)->charnr==0) break;
1103 else if(ct->linenr>lnr) break;
1114 ct= chartransdata+cu->pos;
1115 si= (float)sin(ct->rot);
1116 co= (float)cos(ct->rot);
1118 f= cu->editfont->textcurs[0];
1120 f[0]= cu->fsize*(-0.1f*co + ct->xof);
1121 f[1]= cu->fsize*(0.1f*si + ct->yof);
1123 f[2]= cu->fsize*(0.1f*co + ct->xof);
1124 f[3]= cu->fsize*(-0.1f*si + ct->yof);
1126 f[4]= cu->fsize*( 0.1f*co + 0.8f*si + ct->xof);
1127 f[5]= cu->fsize*(-0.1f*si + 0.8f*co + ct->yof);
1129 f[6]= cu->fsize*(-0.1f*co + 0.8f*si + ct->xof);
1130 f[7]= cu->fsize*( 0.1f*si + 0.8f*co + ct->yof);
1134 MEM_freeN(linedata);
1135 MEM_freeN(linedata2);
1136 MEM_freeN(linedata3);
1137 MEM_freeN(linedata4);
1139 if (mode == FO_SELCHANGE) {
1140 MEM_freeN(chartransdata);
1145 if(mode == FO_EDIT) {
1147 freeNurblist(&cu->nurb);
1150 if (cu->sepchar==0) {
1151 for (i= 0; i<slen; i++) {
1152 unsigned long cha = (uintptr_t) mem[i];
1153 info = &(custrinfo[i]);
1154 if (info->mat_nr > (ob->totcol)) {
1155 /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */
1158 // We do not want to see any character for \n or \r
1159 if(cha != '\n' && cha != '\r')
1160 buildchar(cu, cha, info, ct->xof, ct->yof, ct->rot, i);
1162 if ((info->flag & CU_CHINFO_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) {
1163 float ulwidth, uloverlap= 0.0f;
1165 if ( (i<(slen-1)) && (mem[i+1] != '\n') && (mem[i+1] != '\r') &&
1166 ((mem[i+1] != ' ') || (custrinfo[i+1].flag & CU_CHINFO_UNDERLINE)) && ((custrinfo[i+1].flag & CU_CHINFO_WRAP)==0)
1168 uloverlap = xtrax + 0.1f;
1170 // Find the character, the characters has to be in the memory already
1171 // since character checking has been done earlier already.
1172 che= find_vfont_char(vfd, cha);
1174 twidth = char_width(cu, che, info);
1175 ulwidth = cu->fsize * ((twidth* (1.0f+(info->kern/40.0f)))+uloverlap);
1176 build_underline(cu, ct->xof*cu->fsize, ct->yof*cu->fsize + (cu->ulpos-0.05f)*cu->fsize,
1177 ct->xof*cu->fsize + ulwidth,
1178 ct->yof*cu->fsize + (cu->ulpos-0.05f)*cu->fsize - cu->ulheight*cu->fsize,
1186 for (i= 0; (i<slen) && (outta==0); i++) {
1188 info = &(custrinfo[i]);
1189 if (cu->sepchar == (i+1)) {
1198 custrinfo[0]= *info;
1201 mul_v3_m4v3(ob->loc, ob->obmat, vecyo);
1210 if(mode==FO_DUPLI) {
1212 return chartransdata;
1218 MEM_freeN(chartransdata);