Revert to master - those changes are globally valid, but remain incomplete,
[blender.git] / source / blender / blenkernel / intern / font.c
index 90362c7a3ade9d3788f68dd27627cadd724e4d25..e3ebb7f908ce96a54100044031baff4d93abe598 100644 (file)
@@ -52,7 +52,6 @@
 #include "DNA_packedFile_types.h"
 #include "DNA_curve_types.h"
 #include "DNA_vfont_types.h"
-#include "DNA_scene_types.h"
 #include "DNA_object_types.h"
 
 #include "BKE_packedFile.h"
@@ -62,7 +61,6 @@
 #include "BKE_main.h"
 #include "BKE_anim.h"
 #include "BKE_curve.h"
-#include "BKE_displist.h"
 
 static ThreadRWMutex vfont_rwlock = BLI_RWLOCK_INITIALIZER;
 
@@ -184,7 +182,7 @@ static VFontData *vfont_get_data(Main *bmain, VFont *vfont)
                                printf("Font file doesn't exist: %s\n", vfont->name);
 
                                /* DON'T DO THIS
-                                * missing file shouldn't modifty path! - campbell */
+                                * missing file shouldn't modify path! - campbell */
 #if 0
                                strcpy(vfont->name, FO_BUILTIN_NAME);
 #endif
@@ -205,26 +203,26 @@ static VFontData *vfont_get_data(Main *bmain, VFont *vfont)
        return vfont->data;
 }
 
-VFont *BKE_vfont_load(Main *bmain, const char *name)
+VFont *BKE_vfont_load(Main *bmain, const char *filepath)
 {
        char filename[FILE_MAXFILE];
        VFont *vfont = NULL;
        PackedFile *pf;
        PackedFile *temp_pf = NULL;
-       int is_builtin;
+       bool is_builtin;
        
-       if (STREQ(name, FO_BUILTIN_NAME)) {
-               BLI_strncpy(filename, name, sizeof(filename));
+       if (STREQ(filepath, FO_BUILTIN_NAME)) {
+               BLI_strncpy(filename, filepath, sizeof(filename));
                
                pf = get_builtin_packedfile();
-               is_builtin = TRUE;
+               is_builtin = true;
        }
        else {
-               BLI_split_file_part(name, filename, sizeof(filename));
-               pf = newPackedFile(NULL, name, bmain->name);
-               temp_pf = newPackedFile(NULL, name, bmain->name);
+               BLI_split_file_part(filepath, filename, sizeof(filename));
+               pf = newPackedFile(NULL, filepath, bmain->name);
+               temp_pf = newPackedFile(NULL, filepath, bmain->name);
                
-               is_builtin = FALSE;
+               is_builtin = false;
        }
 
        if (pf) {
@@ -232,14 +230,14 @@ VFont *BKE_vfont_load(Main *bmain, const char *name)
 
                vfd = BLI_vfontdata_from_freetypefont(pf);
                if (vfd) {
-                       vfont = BKE_libblock_alloc(&bmain->vfont, ID_VF, filename);
+                       vfont = BKE_libblock_alloc(bmain, ID_VF, filename);
                        vfont->data = vfd;
 
                        /* if there's a font name, use it for the ID name */
                        if (vfd->name[0] != '\0') {
                                BLI_strncpy(vfont->id.name + 2, vfd->name, sizeof(vfont->id.name) - 2);
                        }
-                       BLI_strncpy(vfont->name, name, sizeof(vfont->name));
+                       BLI_strncpy(vfont->name, filepath, sizeof(vfont->name));
 
                        /* if autopack is on store the packedfile in de font structure */
                        if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
@@ -247,7 +245,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *name)
                        }
 
                        /* Do not add FO_BUILTIN_NAME to temporary listbase */
-                       if (strcmp(filename, FO_BUILTIN_NAME)) {
+                       if (!STREQ(filename, FO_BUILTIN_NAME)) {
                                vfont->temp_pf = temp_pf;
                        }
                }
@@ -261,6 +259,37 @@ VFont *BKE_vfont_load(Main *bmain, const char *name)
        return vfont;
 }
 
+VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists)
+{
+       VFont *vfont;
+       char str[FILE_MAX], strtest[FILE_MAX];
+
+       BLI_strncpy(str, filepath, sizeof(str));
+       BLI_path_abs(str, bmain->name);
+
+       /* first search an identical filepath */
+       for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
+               BLI_strncpy(strtest, vfont->name, sizeof(vfont->name));
+               BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id));
+
+               if (BLI_path_cmp(strtest, str) == 0) {
+                       vfont->id.us++;  /* officially should not, it doesn't link here! */
+                       if (r_exists)
+                               *r_exists = true;
+                       return vfont;
+               }
+       }
+
+       if (r_exists)
+               *r_exists = false;
+       return BKE_vfont_load(bmain, filepath);
+}
+
+VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath)
+{
+       return BKE_vfont_load_exists_ex(bmain, filepath, NULL);
+}
+
 static VFont *which_vfont(Curve *cu, CharInfo *info)
 {
        switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) {
@@ -292,14 +321,14 @@ static VChar *find_vfont_char(VFontData *vfd, unsigned int character)
 {
        return BLI_ghash_lookup(vfd->characters, SET_UINT_IN_POINTER(character));
 }
-               
-static void build_underline(Curve *cu, float x1, float y1, float x2, float y2, int charidx, short mat_nr)
+
+static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
+                            float yofs, float rot, int charidx, short mat_nr)
 {
        Nurb *nu2;
        BPoint *bp;
        
        nu2 = (Nurb *) MEM_callocN(sizeof(Nurb), "underline_nurb");
-       if (nu2 == NULL) return;
        nu2->resolu = cu->resolu;
        nu2->bezt = NULL;
        nu2->knotsu = nu2->knotsv = NULL;
@@ -313,22 +342,47 @@ static void build_underline(Curve *cu, float x1, float y1, float x2, float y2, i
        nu2->flagu = CU_NURB_CYCLIC;
 
        bp = (BPoint *)MEM_callocN(4 * sizeof(BPoint), "underline_bp");
-       if (bp == NULL) {
-               MEM_freeN(nu2);
-               return;
-       }
 
-       copy_v4_fl4(bp[0].vec, x1, y1, 0.0f, 1.0f);
-       copy_v4_fl4(bp[1].vec, x2, y1, 0.0f, 1.0f);
-       copy_v4_fl4(bp[2].vec, x2, y2, 0.0f, 1.0f);
-       copy_v4_fl4(bp[3].vec, x1, y2, 0.0f, 1.0f);
+       copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f);
+       copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f);
+       copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f);
+       copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f);
 
        nu2->bp = bp;
-       BLI_addtail(&(cu->nurb), nu2);
+       BLI_addtail(nubase, nu2);
+
+       if (rot != 0.0f) {
+               float si, co;
+               int i;
+
+               si = sinf(rot);
+               co = cosf(rot);
+
+               for (i = nu2->pntsu; i > 0; i--) {
+                       float *fp;
+                       float x, y;
 
+                       fp = bp->vec;
+
+                       x = fp[0] - rect->xmin;
+                       y = fp[1] - rect->ymin;
+
+                       fp[0] = (+co * x + si * y) + rect->xmin;
+                       fp[1] = (-si * x + co * y) + rect->ymin;
+
+                       bp++;
+               }
+
+               bp = nu2->bp;
+       }
+
+       mul_v2_fl(bp[0].vec, cu->fsize);
+       mul_v2_fl(bp[1].vec, cu->fsize);
+       mul_v2_fl(bp[2].vec, cu->fsize);
+       mul_v2_fl(bp[3].vec, cu->fsize);
 }
 
-static void buildchar(Main *bmain, Curve *cu, unsigned int character, CharInfo *info,
+static void buildchar(Main *bmain, Curve *cu, ListBase *nubase, unsigned int character, CharInfo *info,
                       float ofsx, float ofsy, float rot, int charidx)
 {
        BezTriple *bezt1, *bezt2;
@@ -450,34 +504,62 @@ static void buildchar(Main *bmain, Curve *cu, unsigned int character, CharInfo *
                                bezt2++;
                        }
                        
-                       BLI_addtail(&(cu->nurb), nu2);
+                       BLI_addtail(nubase, nu2);
                }
                
                nu1 = nu1->next;
        }
 }
 
-int BKE_vfont_select_get(Object *ob, int *start, int *end)
+int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end)
 {
        Curve *cu = ob->data;
+       EditFont *ef = cu->editfont;
+       int start, end, direction;
        
-       if (cu->editfont == NULL || ob->type != OB_FONT) return 0;
+       if ((ob->type != OB_FONT) || (ef == NULL)) return 0;
+
+       BLI_assert(ef->len >= 0);
+       BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1);
+       BLI_assert(ef->selend   >= 0 && ef->selend   <= ef->len);
+       BLI_assert(ef->pos      >= 0 && ef->pos      <= ef->len);
 
-       BLI_assert(cu->selstart >= 0 && cu->selstart <= cu->len + 1);
-       BLI_assert(cu->selend   >= 0 && cu->selend   <= cu->len + 1);
-       BLI_assert(cu->pos      >= 0 && cu->pos      <= cu->len);
+       if (ef->selstart == 0) {
+               return 0;
+       }
 
-       if (cu->selstart == 0) return 0;
-       if (cu->selstart <= cu->selend) {
-               *start = cu->selstart - 1;
-               *end = cu->selend - 1;
-               return 1;
+       if (ef->selstart <= ef->selend) {
+               start = ef->selstart - 1;
+               end = ef->selend - 1;
+               direction = 1;
        }
        else {
-               *start = cu->selend;
-               *end = cu->selstart - 2;
-               return -1;
+               start = ef->selend;
+               end = ef->selstart - 2;
+               direction = -1;
+       }
+
+       if (start == end + 1) {
+               return 0;
        }
+       else {
+               BLI_assert(start < end + 1);
+               *r_start = start;
+               *r_end = end;
+               return direction;
+       }
+}
+
+void BKE_vfont_select_clamp(Object *ob)
+{
+       Curve *cu = ob->data;
+       EditFont *ef = cu->editfont;
+
+       BLI_assert((ob->type == OB_FONT) && ef);
+
+       CLAMP_MAX(ef->pos,      ef->len);
+       CLAMP_MAX(ef->selstart, ef->len + 1);
+       CLAMP_MAX(ef->selend,   ef->len);
 }
 
 static float char_width(Curve *cu, VChar *che, CharInfo *info)
@@ -494,24 +576,53 @@ static float char_width(Curve *cu, VChar *che, CharInfo *info)
        }
 }
 
-bool BKE_vfont_to_curve(Main *bmain, Scene *scene, Object *ob, int mode,
-                        struct CharTrans **r_chartransdata)
+static void textbox_scale(TextBox *tb_dst, const TextBox *tb_src, float scale)
+{
+       tb_dst->x = tb_src->x * scale;
+       tb_dst->y = tb_src->y * scale;
+       tb_dst->w = tb_src->w * scale;
+       tb_dst->h = tb_src->h * scale;
+}
+
+/**
+ * Used for storing per-line data for alignment & wrapping.
+ */
+struct TempLineInfo {
+       float x_min;      /* left margin */
+       float x_max;      /* right margin */
+       int   char_nr;    /* number of characters */
+       int   wspace_nr;  /* number of whitespaces of line */
+};
+
+bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase,
+                           const wchar_t **r_text, int *r_text_len, bool *r_text_free,
+                           struct CharTrans **r_chartransdata)
 {
+       Curve *cu = ob->data;
+       EditFont *ef = cu->editfont;
+       EditFontSelBox *selboxes = NULL;
        VFont *vfont, *oldvfont;
        VFontData *vfd = NULL;
-       Curve *cu;
        CharInfo *info = NULL, *custrinfo;
-       TextBox *tb;
+       TextBox tb_scale;
+       bool use_textbox;
        VChar *che;
        struct CharTrans *chartransdata = NULL, *ct;
-       float *f, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4;
+       struct TempLineInfo *lineinfo;
+       float *f, xof, yof, xtrax, linedist;
        float twidth, maxlen = 0;
        int i, slen, j;
        int curbox;
        int selstart, selend;
-       short cnr = 0, lnr = 0, wsnr = 0;
-       wchar_t *mem, *tmp, ascii;
+       int cnr = 0, lnr = 0, wsnr = 0;
+       const wchar_t *mem;
+       wchar_t ascii;
        bool ok = false;
+       const float xof_scale = cu->xof / cu->fsize;
+       const float yof_scale = cu->yof / cu->fsize;
+
+#define MARGIN_X_MIN (xof_scale + tb_scale.x)
+#define MARGIN_Y_MIN (yof_scale + tb_scale.y)
 
        /* remark: do calculations including the trailing '\0' of a string
         * because the cursor can be at that location */
@@ -519,7 +630,6 @@ bool BKE_vfont_to_curve(Main *bmain, Scene *scene, Object *ob, int mode,
        BLI_assert(ob->type == OB_FONT);
 
        /* Set font data */
-       cu = (Curve *) ob->data;
        vfont = cu->vfont;
 
        if (cu->str == NULL) return ok;
@@ -529,79 +639,97 @@ bool BKE_vfont_to_curve(Main *bmain, Scene *scene, Object *ob, int mode,
 
        /* The VFont Data can not be found */
        if (!vfd) return ok;
-
-       if (cu->ulheight == 0.0f)
-               cu->ulheight = 0.05f;
        
-       if (cu->editfont) {
-               slen = cu->len;
-               mem = cu->editfont->textbuf;
-               custrinfo = cu->editfont->textbufinfo;
+       if (ef) {
+               slen = ef->len;
+               mem = ef->textbuf;
+               custrinfo = ef->textbufinfo;
        }
        else {
-               size_t utf8len;
-
-               utf8len = BLI_strlen_utf8(cu->str);
+               wchar_t *mem_tmp;
+               slen = cu->len_wchar;
 
                /* Create unicode string */
-               mem = MEM_mallocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem");
+               mem_tmp = MEM_mallocN(((slen + 1) * sizeof(wchar_t)), "convertedmem");
 
-               slen = BLI_strncpy_wchar_from_utf8(mem, cu->str, utf8len + 1);
+               BLI_strncpy_wchar_from_utf8(mem_tmp, cu->str, slen + 1);
 
                if (cu->strinfo == NULL) {  /* old file */
                        cu->strinfo = MEM_callocN((slen + 4) * sizeof(CharInfo), "strinfo compat");
                }
                custrinfo = cu->strinfo;
+
+               mem = mem_tmp;
        }
 
        if (cu->tb == NULL)
                cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "TextBox compat");
 
+       if (ef) {
+               if (ef->selboxes)
+                       MEM_freeN(ef->selboxes);
+
+               if (BKE_vfont_select_get(ob, &selstart, &selend))
+                       ef->selboxes = MEM_callocN((selend - selstart + 1) * sizeof(EditFontSelBox), "font selboxes");
+               else
+                       ef->selboxes = NULL;
+
+               selboxes = ef->selboxes;
+       }
+
        /* calc offset and rotation of each char */
        ct = chartransdata = MEM_callocN((slen + 1) * sizeof(struct CharTrans), "buildtext");
 
        /* We assume the worst case: 1 character per line (is freed at end anyway) */
-
-       linedata  = MEM_mallocN(sizeof(float) * (slen * 2 + 1), "buildtext2");
-       linedata2 = MEM_mallocN(sizeof(float) * (slen * 2 + 1), "buildtext3");
-       linedata3 = MEM_callocN(sizeof(float) * (slen * 2 + 1), "buildtext4");
-       linedata4 = MEM_callocN(sizeof(float) * (slen * 2 + 1), "buildtext5");
+       lineinfo = MEM_mallocN(sizeof(*lineinfo) * (slen * 2 + 1), "lineinfo");
        
        linedist = cu->linedist;
        
-       xof = cu->xof + (cu->tb[0].x / cu->fsize);
-       yof = cu->yof + (cu->tb[0].y / cu->fsize);
+       curbox = 0;
+       textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+       use_textbox = (tb_scale.w != 0.0f);
+
+
+       xof = MARGIN_X_MIN;
+       yof = MARGIN_Y_MIN;
 
        xtrax = 0.5f * cu->spacing - 0.5f;
 
        oldvfont = NULL;
 
-       for (i = 0; i < slen; i++) custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK);
-
-       if (cu->selboxes) MEM_freeN(cu->selboxes);
-       cu->selboxes = NULL;
-       if (BKE_vfont_select_get(ob, &selstart, &selend))
-               cu->selboxes = MEM_callocN((selend - selstart + 1) * sizeof(SelBox), "font selboxes");
+       for (i = 0; i < slen; i++) {
+               custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK);
+       }
 
-       tb = &(cu->tb[0]);
-       curbox = 0;
        for (i = 0; i <= slen; i++) {
 makebreak:
                /* Characters in the list */
-               info = &(custrinfo[i]);
+               info = &custrinfo[i];
                ascii = mem[i];
                if (info->flag & CU_CHINFO_SMALLCAPS) {
                        ascii = towupper(ascii);
                        if (mem[i] != ascii) {
-                               mem[i] = ascii;
                                info->flag |= CU_CHINFO_SMALLCAPS_CHECK;
                        }
                }
 
                vfont = which_vfont(cu, info);
-               
+
                if (vfont == NULL) break;
 
+               if (vfont != oldvfont) {
+                       vfd = vfont_get_data(bmain, vfont);
+                       oldvfont = vfont;
+               }
+
+               /* VFont Data for VFont couldn't be found */
+               if (!vfd) {
+                       MEM_freeN(chartransdata);
+                       chartransdata = NULL;
+                       MEM_freeN(lineinfo);
+                       goto finally;
+               }
+
                if (!ELEM(ascii, '\n', '\0')) {
                        BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_READ);
                        che = find_vfont_char(vfd, ascii);
@@ -630,34 +758,15 @@ makebreak:
                        che = NULL;
                }
 
-               /* No VFont found */
-               if (vfont == NULL) {
-                       MEM_freeN(chartransdata);
-                       chartransdata = NULL;
-                       goto finally;
-               }
-
-               if (vfont != oldvfont) {
-                       vfd = vfont_get_data(bmain, vfont);
-                       oldvfont = vfont;
-               }
-
-               /* VFont Data for VFont couldn't be found */
-               if (!vfd) {
-                       MEM_freeN(chartransdata);
-                       chartransdata = NULL;
-                       goto finally;
-               }
-
                twidth = char_width(cu, che, info);
 
                /* Calculate positions */
-               if ((tb->w != 0.0f) &&
+               if ((tb_scale.w != 0.0f) &&
                    (ct->dobreak == 0) &&
-                   (((xof - (tb->x / cu->fsize) + twidth) * cu->fsize) > tb->w + cu->xof * cu->fsize))
+                   (((xof - tb_scale.x) + twidth) > xof_scale + tb_scale.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--) {
+                       for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
                                if (mem[j] == ' ' || mem[j] == '-') {
                                        ct -= (i - (j - 1));
                                        cnr -= (i - (j - 1));
@@ -682,7 +791,7 @@ makebreak:
                        }
                }
 
-               if (ascii == '\n' || ascii == '\r' || ascii == 0 || ct->dobreak) {
+               if (ascii == '\n' || ascii == 0 || ct->dobreak) {
                        ct->xof = xof;
                        ct->yof = yof;
                        ct->linenr = lnr;
@@ -690,30 +799,33 @@ makebreak:
 
                        yof -= linedist;
 
-                       maxlen = max_ff(maxlen, (xof - tb->x / cu->fsize));
-                       linedata[lnr] = xof - tb->x / cu->fsize;
-                       linedata2[lnr] = cnr;
-                       linedata3[lnr] = tb->w / cu->fsize;
-                       linedata4[lnr] = wsnr;
-                       
-                       if ((tb->h != 0.0f) &&
-                           ((-(yof - (tb->y / cu->fsize))) > ((tb->h / cu->fsize) - (linedist * cu->fsize)) - cu->yof) &&
-                           (cu->totbox > (curbox + 1)) )
+                       lineinfo[lnr].x_min     = (xof - xtrax) - tb_scale.x;
+                       lineinfo[lnr].x_max     = tb_scale.w;
+                       lineinfo[lnr].char_nr   = cnr;
+                       lineinfo[lnr].wspace_nr = wsnr;
+
+                       CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
+
+                       if ((tb_scale.h != 0.0f) &&
+                           (cu->totbox > (curbox + 1)) &&
+                           ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale))
                        {
                                maxlen = 0;
-                               tb++;
                                curbox++;
-                               yof = cu->yof + tb->y / cu->fsize;
+
+                               textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+
+                               yof = MARGIN_Y_MIN;
                        }
 
                        /* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
 #if 0
-                       if (ascii == '\n' || ascii == '\r')
-                               xof = cu->xof;
+                       if (ascii == '\n')
+                               xof = xof_scale;
                        else
-                               xof = cu->xof + (tb->x / cu->fsize);
+                               xof = MARGIN_X_MIN;
 #else
-                       xof = cu->xof + (tb->x / cu->fsize);
+                       xof = MARGIN_X_MIN;
 #endif
                        lnr++;
                        cnr = 0;
@@ -727,12 +839,12 @@ makebreak:
                        ct->linenr = lnr;
                        ct->charnr = cnr++;
 
-                       tabfac = (xof - cu->xof + 0.01f);
+                       tabfac = (xof - MARGIN_X_MIN + 0.01f);
                        tabfac = 2.0f * ceilf(tabfac / 2.0f);
-                       xof = cu->xof + tabfac;
+                       xof = MARGIN_X_MIN + tabfac;
                }
                else {
-                       SelBox *sb = NULL;
+                       EditFontSelBox *sb = NULL;
                        float wsfac;
 
                        ct->xof = xof;
@@ -740,8 +852,8 @@ makebreak:
                        ct->linenr = lnr;
                        ct->charnr = cnr++;
 
-                       if (cu->selboxes && (i >= selstart) && (i <= selend)) {
-                               sb = &(cu->selboxes[i - selstart]);
+                       if (selboxes && (i >= selstart) && (i <= selend)) {
+                               sb = &selboxes[i - selstart];
                                sb->y = yof * cu->fsize - linedist * cu->fsize * 0.1f;
                                sb->h = linedist * cu->fsize;
                                sb->w = xof * cu->fsize;
@@ -768,83 +880,95 @@ makebreak:
        }
        
        cu->lines = 1;
-       ct = chartransdata;
-       tmp = mem;
-       for (i = 0; i <= slen; i++, tmp++, ct++) {
-               ascii = *tmp;
-               if (ascii == '\n' || ascii == '\r' || ct->dobreak) cu->lines++;
+       for (i = 0; i <= slen; i++) {
+               ascii = mem[i];
+               ct = &chartransdata[i];
+               if (ascii == '\n' || ct->dobreak) cu->lines++;
        }
 
-       /* linedata is now: width of line
-        * linedata2 is now: number of characters
-        * linedata3 is now: maxlen of that line
-        * linedata4 is now: number of whitespaces of line */
+       /* linedata is now: width of line */
 
        if (cu->spacemode != CU_LEFT) {
                ct = chartransdata;
 
                if (cu->spacemode == CU_RIGHT) {
-                       for (i = 0; i < lnr; i++) linedata[i] = linedata3[i] - linedata[i];
+                       struct TempLineInfo *li;
+
+                       for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+                               li->x_min = (li->x_max - li->x_min) + xof_scale;
+                       }
+
                        for (i = 0; i <= slen; i++) {
-                               ct->xof += linedata[ct->linenr];
+                               ct->xof += lineinfo[ct->linenr].x_min;
                                ct++;
                        }
                }
                else if (cu->spacemode == CU_MIDDLE) {
-                       for (i = 0; i < lnr; i++) linedata[i] = (linedata3[i] - linedata[i]) / 2;
+                       struct TempLineInfo *li;
+
+                       for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+                               li->x_min = ((li->x_max - li->x_min) + xof_scale) / 2.0f;
+                       }
+
                        for (i = 0; i <= slen; i++) {
-                               ct->xof += linedata[ct->linenr];
+                               ct->xof += lineinfo[ct->linenr].x_min;
                                ct++;
                        }
                }
-               else if ((cu->spacemode == CU_FLUSH) && (cu->tb[0].w != 0.0f)) {
-                       for (i = 0; i < lnr; i++)
-                               if (linedata2[i] > 1)
-                                       linedata[i] = (linedata3[i] - linedata[i]) / (linedata2[i] - 1);
+               else if ((cu->spacemode == CU_FLUSH) && use_textbox) {
+                       struct TempLineInfo *li;
+
+                       for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+                               li->x_min = ((li->x_max - li->x_min) + xof_scale);
+
+                               if (li->char_nr > 1) {
+                                       li->x_min /= (float)(li->char_nr - 1);
+                               }
+                       }
                        for (i = 0; i <= slen; i++) {
-                               for (j = i; (!ELEM3(mem[j], '\0', '\n', '\r')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) {
+                               for (j = i; (!ELEM(mem[j], '\0', '\n')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) {
                                        /* do nothing */
                                }
 
-//                             if ((mem[j] != '\r') && (mem[j] != '\n') && (mem[j])) {
-                               ct->xof += ct->charnr * linedata[ct->linenr];
+//                             if ((mem[j] != '\n') && (mem[j])) {
+                               ct->xof += ct->charnr * lineinfo[ct->linenr].x_min;
 //                             }
                                ct++;
                        }
                }
-               else if ((cu->spacemode == CU_JUSTIFY) && (cu->tb[0].w != 0.0f)) {
+               else if ((cu->spacemode == CU_JUSTIFY) && use_textbox) {
                        float curofs = 0.0f;
                        for (i = 0; i <= slen; i++) {
-                               for (j = i; (mem[j]) && (mem[j] != '\n') &&
-                                    (mem[j] != '\r') && (chartransdata[j].dobreak == 0) && (j < slen);
+                               for (j = i;
+                                    (mem[j]) && (mem[j] != '\n') && (chartransdata[j].dobreak == 0) && (j < slen);
                                     j++)
                                {
                                        /* pass */
                                }
 
-                               if ((mem[j] != '\r') && (mem[j] != '\n') &&
+                               if ((mem[j] != '\n') &&
                                    ((chartransdata[j].dobreak != 0)))
                                {
-                                       if (mem[i] == ' ') curofs += (linedata3[ct->linenr] - linedata[ct->linenr]) / linedata4[ct->linenr];
+                                       if (mem[i] == ' ') {
+                                               struct TempLineInfo *li;
+
+                                               li = &lineinfo[ct->linenr];
+                                               curofs += ((li->x_max - li->x_min) + xof_scale) / (float)li->wspace_nr;
+                                       }
                                        ct->xof += curofs;
                                }
-                               if (mem[i] == '\n' || mem[i] == '\r' || chartransdata[i].dobreak) curofs = 0;
+                               if (mem[i] == '\n' || chartransdata[i].dobreak) curofs = 0;
                                ct++;
                        }
                }
        }
-       
+
+       MEM_freeN(lineinfo);
+
        /* TEXT ON CURVE */
        /* Note: Only OB_CURVE objects could have a path  */
        if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) {
-               Curve *cucu = cu->textoncurve->data;
-               int oldflag = cucu->flag;
-               
-               cucu->flag |= (CU_PATH + CU_FOLLOW);
-               
-               if (cu->textoncurve->curve_cache == NULL || cu->textoncurve->curve_cache->path == NULL) {
-                       BKE_displist_make_curveTypes(scene, cu->textoncurve, 0);
-               }
+               BLI_assert(cu->textoncurve->curve_cache != NULL);
                if (cu->textoncurve->curve_cache->path) {
                        float distfac, imat[4][4], imat3[3][3], cmat[3][3];
                        float minx, maxx, miny, maxy;
@@ -901,7 +1025,11 @@ makebreak:
                                float si, co;
                                
                                /* rotate around center character */
+                               info = &custrinfo[i];
                                ascii = mem[i];
+                               if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
+                                       ascii = towupper(ascii);
+                               }
 
                                che = find_vfont_char(vfd, ascii);
        
@@ -928,27 +1056,30 @@ makebreak:
                                
                                ct->xof = vec[0] + si * yof;
                                ct->yof = vec[1] + co * yof;
+
+                               if (selboxes && (i >= selstart) && (i <= selend)) {
+                                       EditFontSelBox *sb;
+                                       sb = &selboxes[i - selstart];
+                                       sb->rot = -ct->rot;
+                               }
                                
                        }
-                       cucu->flag = oldflag;
                }
        }
 
-       if (cu->selboxes) {
+       if (selboxes) {
                ct = chartransdata;
                for (i = 0; i <= selend; i++, ct++) {
                        if (i >= selstart) {
-                               cu->selboxes[i - selstart].x = ct->xof * cu->fsize;
-                               cu->selboxes[i - selstart].y = ct->yof * cu->fsize;
+                               selboxes[i - selstart].x = ct->xof * cu->fsize;
+                               selboxes[i - selstart].y = ct->yof * cu->fsize;
                        }
                }
        }
 
        if (mode == FO_CURSUP || mode == FO_CURSDOWN || mode == FO_PAGEUP || mode == FO_PAGEDOWN) {
-               /* 2: curs up
-                * 3: curs down */
-               ct = chartransdata + cu->pos;
-               
+               ct = &chartransdata[ef->pos];
+
                if ((mode == FO_CURSUP || mode == FO_PAGEUP) && ct->linenr == 0) {
                        /* pass */
                }
@@ -964,7 +1095,7 @@ makebreak:
                        }
                        cnr = ct->charnr;
                        /* seek for char with lnr en cnr */
-                       cu->pos = 0;
+                       ef->pos = 0;
                        ct = chartransdata;
                        for (i = 0; i < slen; i++) {
                                if (ct->linenr == lnr) {
@@ -975,21 +1106,21 @@ makebreak:
                                else if (ct->linenr > lnr) {
                                        break;
                                }
-                               cu->pos++;
+                               ef->pos++;
                                ct++;
                        }
                }
        }
        
        /* cursor first */
-       if (cu->editfont) {
+       if (ef) {
                float si, co;
                
-               ct = chartransdata + cu->pos;
+               ct = &chartransdata[ef->pos];
                si = sinf(ct->rot);
                co = cosf(ct->rot);
 
-               f = cu->editfont->textcurs[0];
+               f = ef->textcurs[0];
                
                f[0] = cu->fsize * (-0.1f * co + ct->xof);
                f[1] = cu->fsize * ( 0.1f * si + ct->yof);
@@ -1005,11 +1136,6 @@ makebreak:
                
        }
 
-       MEM_freeN(linedata);
-       MEM_freeN(linedata2);
-       MEM_freeN(linedata3);
-       MEM_freeN(linedata4);
-
        if (mode == FO_SELCHANGE) {
                MEM_freeN(chartransdata);
                chartransdata = NULL;
@@ -1018,67 +1144,53 @@ makebreak:
 
        if (mode == FO_EDIT) {
                /* make nurbdata */
-               BKE_nurbList_free(&cu->nurb);
+               BKE_nurbList_free(r_nubase);
                
                ct = chartransdata;
-               if (cu->sepchar == 0) {
-                       for (i = 0; i < slen; i++) {
-                               unsigned int cha = (unsigned int) mem[i];
-                               info = &(custrinfo[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;
-                               }
-                               /* We do not want to see any character for \n or \r */
-                               if (cha != '\n' && cha != '\r')
-                                       buildchar(bmain, cu, cha, info, ct->xof, ct->yof, ct->rot, i);
-                               
-                               if ((info->flag & CU_CHINFO_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) {
-                                       float ulwidth, uloverlap = 0.0f;
-                                       
-                                       if ((i < (slen - 1)) && (mem[i + 1] != '\n') && (mem[i + 1] != '\r') &&
-                                           ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) &&
-                                           ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0))
-                                       {
-                                               uloverlap = xtrax + 0.1f;
-                                       }
-                                       /* Find the character, the characters has to be in the memory already
-                                        * since character checking has been done earlier already. */
-                                       che = find_vfont_char(vfd, cha);
-
-                                       twidth = char_width(cu, che, info);
-                                       ulwidth = cu->fsize * ((twidth * (1.0f + (info->kern / 40.0f))) + uloverlap);
-                                       build_underline(cu, ct->xof * cu->fsize, ct->yof * cu->fsize + (cu->ulpos - 0.05f) * cu->fsize,
-                                                       ct->xof * cu->fsize + ulwidth,
-                                                       ct->yof * cu->fsize + (cu->ulpos - 0.05f) * cu->fsize - cu->ulheight * cu->fsize,
-                                                       i, info->mat_nr);
-                               }
-                               ct++;
+               for (i = 0; i < slen; i++) {
+                       unsigned int cha = (unsigned int) mem[i];
+                       info = &(custrinfo[i]);
+
+                       if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
+                               cha = towupper(cha);
                        }
-               }
-               else {
-                       int outta = 0;
-                       for (i = 0; (i < slen) && (outta == 0); i++) {
-                               ascii = mem[i];
-                               info = &(custrinfo[i]);
-                               if (cu->sepchar == (i + 1)) {
-                                       float vecyo[3];
-
-                                       vecyo[0] = ct->xof;
-                                       vecyo[1] = ct->yof;
-                                       vecyo[2] = 0.0f;
-
-                                       mem[0] = ascii;
-                                       mem[1] = 0;
-                                       custrinfo[0] = *info;
-                                       cu->pos = 1;
-                                       cu->len = 1;
-                                       mul_v3_m4v3(ob->loc, ob->obmat, vecyo);
-                                       outta = 1;
-                                       cu->sepchar = 0;
+
+                       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;
+                       }
+                       /* We do not want to see any character for \n or \r */
+                       if (cha != '\n')
+                               buildchar(bmain, cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i);
+
+                       if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {
+                               float ulwidth, uloverlap = 0.0f;
+                               rctf rect;
+
+                               if ((i < (slen - 1)) && (mem[i + 1] != '\n') &&
+                                   ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) &&
+                                   ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0))
+                               {
+                                       uloverlap = xtrax + 0.1f;
                                }
-                               ct++;
+                               /* Find the character, the characters has to be in the memory already
+                                * since character checking has been done earlier already. */
+                               che = find_vfont_char(vfd, cha);
+
+                               twidth = char_width(cu, che, info);
+                               ulwidth = (twidth * (1.0f + (info->kern / 40.0f))) + uloverlap;
+
+                               rect.xmin = ct->xof;
+                               rect.xmax = rect.xmin + ulwidth;
+
+                               rect.ymin = ct->yof;
+                               rect.ymax = rect.ymin - cu->ulheight;
+
+                               build_underline(cu, r_nubase,
+                                               &rect, cu->ulpos - 0.05f,
+                                               ct->rot, i, info->mat_nr);
                        }
+                       ct++;
                }
        }
 
@@ -1086,15 +1198,46 @@ makebreak:
 
 finally:
 
-       if (cu->editfont == NULL)
-               MEM_freeN(mem);
-
-       if (r_chartransdata) {
-               *r_chartransdata = chartransdata;
+       {
+               if (r_text) {
+                       *r_text = mem;
+                       *r_text_len = slen;
+                       *r_text_free = (ef == NULL);
+               }
+               else {
+                       if (ef == NULL) {
+                               MEM_freeN((void *)mem);
+                       }
+               }
        }
-       else {
-               MEM_freeN(chartransdata);
+
+       if (chartransdata) {
+               if (ok && r_chartransdata) {
+                       *r_chartransdata = chartransdata;
+               }
+               else {
+                       MEM_freeN(chartransdata);
+               }
        }
 
        return ok;
+
+#undef MARGIN_X_MIN
+#undef MARGIN_Y_MIN
+}
+
+
+bool BKE_vfont_to_curve_nubase(Main *bmain, Object *ob, int mode, ListBase *r_nubase)
+{
+       BLI_assert(ob->type == OB_FONT);
+
+       return BKE_vfont_to_curve_ex(bmain, ob, mode, r_nubase,
+                                    NULL, NULL, NULL, NULL);
+}
+
+bool BKE_vfont_to_curve(Main *bmain, Object *ob, int mode)
+{
+       Curve *cu = ob->data;
+
+       return BKE_vfont_to_curve_ex(bmain, ob, mode, &cu->nurb, NULL, NULL, NULL, NULL);
 }