[Bf-blender-cvs] [8e65e38649f] blender2.8: Font textbox overflow: Different methods

Dalai Felinto noreply at git.blender.org
Tue Nov 27 00:49:27 CET 2018


Commit: 8e65e38649f4a926e3c08cb414ff4789454d0f07
Author: Dalai Felinto
Date:   Wed Sep 12 13:00:30 2018 -0300
Branches: blender2.8
https://developer.blender.org/rB8e65e38649f4a926e3c08cb414ff4789454d0f07

Font textbox overflow: Different methods

Sometimes the text doesn't fit. What to do in this case?

* Overflow: The default behaviour still is to overflow the text.
* Truncated: If any text box is defined we can also not draw the text
  that goes outside the text boxes.
* Scale to Fit: For single-text box texts we can scale down the text until
  it fits.

To support textboxes we are bisecting the scale until we find a good
match. Right now the hardcoded iteration limit is 20, and the threshold 0.0001f.

An alternative in the future would be to tackle this by integrating existing
layout engines such as HarfBuzz.

Note: Scale to fit won't work for multiple text-boxes if any of them has
either width or height as zero.

Reviewers: campbellbarton
Differential Revision: https://developer.blender.org/D3874

Feature development sponsored by Viddyoze.

===================================================================

M	release/scripts/startup/bl_ui/properties_data_curve.py
M	source/blender/blenkernel/intern/font.c
M	source/blender/draw/modes/edit_text_mode.c
M	source/blender/makesdna/DNA_curve_types.h
M	source/blender/makesrna/intern/rna_curve.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index 2625c23a5a8..e7f9de5dc20 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -441,6 +441,7 @@ class DATA_PT_text_boxes(CurveButtonsPanelText, Panel):
         text = context.curve
 
         layout.operator("font.textbox_add", icon='ADD')
+        layout.prop(text, "overflow", text="Overflow")
 
         for i, box in enumerate(text.text_boxes):
 
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index f6e1fabc6c0..9c24cc436c6 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -364,7 +364,8 @@ static VChar *find_vfont_char(VFontData *vfd, unsigned int character)
 }
 
 static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
-                            float yofs, float rot, int charidx, short mat_nr)
+                            float yofs, float rot, int charidx, short mat_nr,
+                            const float font_size)
 {
 	Nurb *nu2;
 	BPoint *bp;
@@ -417,18 +418,19 @@ static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
 		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);
+	mul_v2_fl(bp[0].vec, font_size);
+	mul_v2_fl(bp[1].vec, font_size);
+	mul_v2_fl(bp[2].vec, font_size);
+	mul_v2_fl(bp[3].vec, font_size);
 }
 
 static void buildchar(Curve *cu, ListBase *nubase, unsigned int character, CharInfo *info,
-                      float ofsx, float ofsy, float rot, int charidx)
+                      float ofsx, float ofsy, float rot, int charidx,
+                      const float fsize)
 {
 	BezTriple *bezt1, *bezt2;
 	Nurb *nu1 = NULL, *nu2 = NULL;
-	float *fp, fsize, shear, x, si, co;
+	float *fp, shear, x, si, co;
 	VFontData *vfd = NULL;
 	VChar *che = NULL;
 	int i;
@@ -448,7 +450,6 @@ static void buildchar(Curve *cu, ListBase *nubase, unsigned int character, CharI
 #endif
 
 	/* make a copy at distance ofsx, ofsy with shear */
-	fsize = cu->fsize;
 	shear = cu->shear;
 	si = sinf(rot);
 	co = cosf(rot);
@@ -635,6 +636,27 @@ struct TempLineInfo {
 	int   wspace_nr;  /* number of whitespaces of line */
 };
 
+typedef struct VFontToCurveIter {
+	int iteraction;
+	float scale_to_fit;
+	struct {
+		float min;
+		float max;
+	} bisect;
+	bool ok;
+	int status;
+} VFontToCurveIter;
+
+enum {
+	VFONT_TO_CURVE_INIT = 0,
+	VFONT_TO_CURVE_BISECT,
+	VFONT_TO_CURVE_SCALE_ONCE,
+	VFONT_TO_CURVE_DONE,
+};
+
+#define FONT_TO_CURVE_SCALE_ITERATIONS 20
+#define FONT_TO_CURVE_SCALE_THRESHOLD 0.0001f
+
 /**
  * Font metric values explained:
  *
@@ -651,7 +673,9 @@ struct TempLineInfo {
 #define ASCENT(vfd) ((vfd)->ascender * (vfd)->em_height)
 #define DESCENT(vfd) ((vfd)->em_height - ASCENT(vfd))
 
-bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
+static bool vfont_to_curve(Object *ob, Curve *cu, int mode,
+                           VFontToCurveIter *iter_data,
+                           ListBase *r_nubase,
                            const wchar_t **r_text, int *r_text_len, bool *r_text_free,
                            struct CharTrans **r_chartransdata)
 {
@@ -671,11 +695,16 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
 	int curbox;
 	int selstart, selend;
 	int cnr = 0, lnr = 0, wsnr = 0;
-	const wchar_t *mem;
+	const wchar_t *mem = NULL;
 	wchar_t ascii;
 	bool ok = false;
-	const float xof_scale = cu->xof / cu->fsize;
-	const float yof_scale = cu->yof / cu->fsize;
+	const float font_size = cu->fsize * iter_data->scale_to_fit;
+	const float xof_scale = cu->xof / font_size;
+	const float yof_scale = cu->yof / font_size;
+	int last_line = -1;
+	/* Length of the text disregarding \n breaks. */
+	float current_line_length = 0.0f;
+	float longest_line_length = 0.0f;
 
 	/* Text at the beginning of the last used text-box (use for y-axis alignment).
 	 * We overallocate by one to simplify logic of getting last char. */
@@ -756,7 +785,7 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
 	linedist = cu->linedist;
 
 	curbox = 0;
-	textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+	textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
 	use_textbox = (tb_scale.w != 0.0f);
 
 
@@ -768,7 +797,7 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
 	oldvfont = NULL;
 
 	for (i = 0; i < slen; i++) {
-		custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK);
+		custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK | CU_CHINFO_OVERFLOW);
 	}
 
 	for (i = 0; i <= slen; i++) {
@@ -837,6 +866,7 @@ makebreak:
 		{
 			//		fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]);
 			for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
+				bool dobreak = false;
 				if (mem[j] == ' ' || mem[j] == '-') {
 					ct -= (i - (j - 1));
 					cnr -= (i - (j - 1));
@@ -846,9 +876,9 @@ makebreak:
 					xof = ct->xof;
 					ct[1].dobreak = 1;
 					custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
-					goto makebreak;
+					dobreak = true;
 				}
-				if (chartransdata[j].dobreak) {
+				else if (chartransdata[j].dobreak) {
 					//				fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]);
 					ct->dobreak = 1;
 					custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
@@ -856,6 +886,13 @@ makebreak:
 					cnr -= 1;
 					i--;
 					xof = ct->xof;
+					dobreak = true;
+				}
+				if (dobreak) {
+					if (tb_scale.h == 0.0f) {
+						/* Note: If underlined text is truncated away, the extra space is also truncated. */
+						custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW;
+					}
 					goto makebreak;
 				}
 			}
@@ -877,16 +914,30 @@ makebreak:
 			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;
-				curbox++;
-				i_textbox_array[curbox] = i + 1;
+				if (cu->totbox > (curbox + 1)) {
+					maxlen = 0;
+					curbox++;
+					i_textbox_array[curbox] = i + 1;
 
-				textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+					textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
 
-				yof = MARGIN_Y_MIN;
+					yof = MARGIN_Y_MIN;
+				}
+				else if (last_line == -1) {
+					last_line = lnr + 1;
+					info->flag |= CU_CHINFO_OVERFLOW;
+				}
+			}
+
+			current_line_length += xof;
+			if (ct->dobreak) {
+				current_line_length += twidth;
+			}
+			else {
+				longest_line_length = MAX2(current_line_length, longest_line_length);
+				current_line_length = 0.0f;
 			}
 
 			/* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
@@ -925,9 +976,9 @@ makebreak:
 
 			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;
+				sb->y = yof * font_size - linedist * font_size * 0.1f;
+				sb->h = linedist * font_size;
+				sb->w = xof * font_size;
 			}
 
 			if (ascii == 32) {
@@ -944,11 +995,13 @@ makebreak:
 			xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f)) ) + xtrax;
 
 			if (sb) {
-				sb->w = (xof * cu->fsize) - sb->w;
+				sb->w = (xof * font_size) - sb->w;
 			}
 		}
 		ct++;
 	}
+	current_line_length += xof + twidth;
+	longest_line_length = MAX2(current_line_length, longest_line_length);
 
 	cu->lines = 1;
 	for (i = 0; i <= slen; i++) {
@@ -1050,7 +1103,7 @@ makebreak:
 				ct_last = chartransdata + (is_last_filled_textbox ? slen: i_textbox_next - 1);
 				lines = ct_last->linenr - ct_first->linenr + 1;
 
-				textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / cu->fsize);
+				textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / font_size);
 				/* The initial Y origin of the textbox is hardcoded to 1.0f * text scale. */
 				const float textbox_y_origin = 1.0f;
 				float yoff = 0.0f;
@@ -1133,7 +1186,7 @@ makebreak:
 
 			copy_m3_m4(cmat, cu->textoncurve->obmat);
 			mul_m3_m3m3(cmat, cmat, imat3);
-			sizefac = normalize_v3(cmat[0]) / cu->fsize;
+			sizefac = normalize_v3(cmat[0]) / font_size;
 
 			minx = miny = 1.0e20f;
 			maxx = maxy = -1.0e20f;
@@ -1226,13 +1279,15 @@ makebreak:
 		ct = chartransdata;
 		for (i = 0; i <= selend; i++, ct++) {
 			if (i >= selstart) {
-				selboxes[i - selstart].x = ct->xof * cu->fsize;
-				selboxes[i - selstart].y = ct->yof * cu->fsize;
+				selboxes[i - selstart].x = ct->xof * font_size;
+				selboxes[i - selstart].y = ct->yof * font_size;
 			}
 		}
 	}
 
-	if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN)) {
+	if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN) && 
+	    iter_data->status == VFONT_TO_CURVE_INIT)
+	{
 		ct = &chartransdata[ef->pos];
 
 		if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) {
@@ -1277,27 +1332,25 @@ makebreak:
 
 		f = ef->textcurs[0];
 
-		f[0] = cu->fsize * (-0.1f * co + ct->xof);
-		f[1] = cu->fsize * ( 0.1f * si + ct->yof);
+		f[0] = font_size * (-0.1f * co + ct->xof);
+		f[1] = font_size * ( 0.1f * si + ct->yof);
 
-		f[2] = cu->fsize * ( 0.1f * co + ct->xof);
-		f[3] = cu->fsize * (-0.1f * si + ct->yof);
+		f[2] = font_size * ( 0.1f * co + ct->xof);
+		f[3] = font_size * (-0.1f * si + ct->yof);
 
-		f[4] = cu->fsize * ( 0.1f * co + 0.8f * si + ct->xof);
-		f[5] = cu->fsize * (-0.1f * si + 0.8f * co + ct->yof);
+		f[4] = font_size * ( 0.1f * co + 0.8f * si + ct->xof);
+		f[5] = font_size * (-0.1f * si + 0.8f * co + ct->yof);
 
-		f[6] = cu->fsize * (-0.1f * co + 0.8f * si + ct->xof);
-		f[7] = cu->fsize * ( 0.1f * si + 0.8f * co + ct->yof);
+		f[6] = font_size * (-0.1f * co + 0.8f * si + ct->xof);
+		f[7] = font_size * ( 0.1f * si + 0.8f * co + ct->yof);
 
 	}
 
 	if (mode == FO_SELCHANGE) {
 		MEM_freeN(chartransdata);
 		chartransdata = NULL;
-		goto finally;
 	}
-
-	if (mode == FO_EDIT) {
+	else if (mode == FO_EDIT) {
 		/* ma

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list