Revert to master - those changes are globally valid, but remain incomplete,
[blender.git] / source / blender / blenkernel / intern / font.c
index 5ae4180267d9411ff8bad2f6be49086395203110..e3ebb7f908ce96a54100044031baff4d93abe598 100644 (file)
@@ -203,7 +203,7 @@ 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;
@@ -211,16 +211,16 @@ VFont *BKE_vfont_load(Main *bmain, const char *name)
        PackedFile *temp_pf = NULL;
        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;
        }
        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;
        }
@@ -237,7 +237,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *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)) {
@@ -245,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;
                        }
                }
@@ -259,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)) {
@@ -312,10 +343,10 @@ static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
 
        bp = (BPoint *)MEM_callocN(4 * sizeof(BPoint), "underline_bp");
 
-       copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f);
-       copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f);
-       copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f);
-       copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymax + yofs), 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(nubase, nu2);
@@ -484,26 +515,53 @@ 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 ((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 + 1);
+       BLI_assert(ef->selend   >= 0 && ef->selend   <= ef->len);
        BLI_assert(ef->pos      >= 0 && ef->pos      <= ef->len);
 
-       if (ef->selstart == 0) return 0;
+       if (ef->selstart == 0) {
+               return 0;
+       }
+
        if (ef->selstart <= ef->selend) {
-               *r_start = ef->selstart - 1;
-               *r_end = ef->selend - 1;
-               return 1;
+               start = ef->selstart - 1;
+               end = ef->selend - 1;
+               direction = 1;
+       }
+       else {
+               start = ef->selend;
+               end = ef->selstart - 2;
+               direction = -1;
+       }
+
+       if (start == end + 1) {
+               return 0;
        }
        else {
-               *r_start = ef->selend;
-               *r_end = ef->selstart - 2;
-               return -1;
+               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)
 {
        /* The character wasn't found, propably ascii = 0, then the width shall be 0 as well */
@@ -518,6 +576,24 @@ static float char_width(Curve *cu, VChar *che, CharInfo *info)
        }
 }
 
+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)
@@ -528,18 +604,25 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
        VFont *vfont, *oldvfont;
        VFontData *vfd = NULL;
        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;
+       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 */
@@ -556,9 +639,6 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
 
        /* The VFont Data can not be found */
        if (!vfd) return ok;
-
-       if (cu->ulheight == 0.0f)
-               cu->ulheight = 0.05f;
        
        if (ef) {
                slen = ef->len;
@@ -601,25 +681,26 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
        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);
+       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 */
@@ -645,6 +726,7 @@ makebreak:
                if (!vfd) {
                        MEM_freeN(chartransdata);
                        chartransdata = NULL;
+                       MEM_freeN(lineinfo);
                        goto finally;
                }
 
@@ -679,12 +761,12 @@ makebreak:
                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));
@@ -709,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;
@@ -717,31 +799,33 @@ makebreak:
 
                        yof -= linedist;
 
-                       linedata[lnr] = (xof - xtrax) - (tb->x / cu->fsize);
-                       linedata2[lnr] = cnr;
-                       linedata3[lnr] = tb->w / cu->fsize;
-                       linedata4[lnr] = wsnr;
+                       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, linedata[lnr]);
+                       CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
 
-                       if ((tb->h != 0.0f) &&
-                           ((-(yof - (tb->y / cu->fsize))) > ((tb->h / cu->fsize) - (linedist * cu->fsize)) - cu->yof) &&
-                           (cu->totbox > (curbox + 1)) )
+                       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;
@@ -755,9 +839,9 @@ 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 {
                        EditFontSelBox *sb = NULL;
@@ -799,68 +883,88 @@ makebreak:
        for (i = 0; i <= slen; i++) {
                ascii = mem[i];
                ct = &chartransdata[i];
-               if (ascii == '\n' || ascii == '\r' || ct->dobreak) cu->lines++;
+               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) {
@@ -1032,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;
@@ -1061,14 +1160,14 @@ makebreak:
                                info->mat_nr = 0;
                        }
                        /* We do not want to see any character for \n or \r */
-                       if (cha != '\n' && cha != '\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') && (cha != '\r')) {
+                       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] != '\r') &&
+                               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))
                                {
@@ -1122,6 +1221,9 @@ finally:
        }
 
        return ok;
+
+#undef MARGIN_X_MIN
+#undef MARGIN_Y_MIN
 }