[Concept,13/16] video: Add len parameter to vidconsole_measure()

Message ID 20260122041155.174721-14-sjg@u-boot.org
State New
Headers
Series expo: Add multiline editing support for textedit |

Commit Message

Simon Glass Jan. 22, 2026, 4:11 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add a len parameter to vidconsole_measure() to allow measuring a
substring of the input text. This is useful for measuring text up to
a specific cursor position, which is needed for cursor-positioning with
multi-line text input.

Also return the position of the character where the substring ended,
needed for cursor positioning.

Pass -1 for len to measure the whole string (existing behaviour).

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 boot/scene.c                      | 2 +-
 drivers/video/console_truetype.c  | 9 ++++++---
 drivers/video/vidconsole-uclass.c | 7 ++++---
 include/video_console.h           | 8 ++++++--
 test/dm/video.c                   | 6 +++---
 5 files changed, 20 insertions(+), 12 deletions(-)
  

Patch

diff --git a/boot/scene.c b/boot/scene.c
index 52cb7055eb3..ff21b524843 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -538,7 +538,7 @@  int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
 			obj->req_bbox.x1 - obj->req_bbox.x0 : -1;
 
 		ret = vidconsole_measure(scn->expo->cons, gen->font_name,
-					 gen->font_size, str, limit, &bbox,
+					 gen->font_size, str, -1, limit, &bbox,
 					 &gen->lines);
 		if (ret)
 			return log_msg_ret("mea", ret);
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index 78683f8de13..25df22e31b0 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -1004,12 +1004,12 @@  static int truetype_select_font(struct udevice *dev, void *vctx,
 }
 
 static int truetype_measure(struct udevice *dev, const char *name, uint size,
-			    const char *text, int pixel_limit,
+			    const char *text, int len, int pixel_limit,
 			    struct vidconsole_bbox *bbox, struct alist *lines)
 {
 	struct console_tt_metrics *met;
 	struct vidconsole_mline mline;
-	const char *s, *last_space;
+	const char *s, *last_space, *end;
 	int width, last_width;
 	stbtt_fontinfo *font;
 	int lsb, advance;
@@ -1030,6 +1030,7 @@  static int truetype_measure(struct udevice *dev, const char *name, uint size,
 	if (pixel_limit != -1)
 		limit = tt_ceil((double)pixel_limit / met->scale);
 
+	end = len < 0 ? NULL : text + len;
 	font = &met->font;
 	width = 0;
 	bbox->y1 = 0;
@@ -1037,7 +1038,7 @@  static int truetype_measure(struct udevice *dev, const char *name, uint size,
 	start = 0;
 	last_space = NULL;
 	last_width = 0;
-	for (lastch = 0, s = text; *s; s++) {
+	for (lastch = 0, s = text; *s && s != end; s++) {
 		int neww;
 		int ch = *s;
 
@@ -1069,6 +1070,7 @@  static int truetype_measure(struct udevice *dev, const char *name, uint size,
 			mline.bbox.x0 = 0;
 			mline.bbox.y0 = bbox->y1;
 			mline.bbox.x1 = tt_ceil((double)width * met->scale);
+			mline.xpos = (int)((double)width * met->scale);
 			bbox->x1 = max(bbox->x1, mline.bbox.x1);
 			bbox->y1 += met->font_size;
 			mline.bbox.y1 = bbox->y1;
@@ -1095,6 +1097,7 @@  static int truetype_measure(struct udevice *dev, const char *name, uint size,
 	mline.bbox.x0 = 0;
 	mline.bbox.y0 = bbox->y1;
 	mline.bbox.x1 = tt_ceil((double)width * met->scale);
+	mline.xpos = (int)((double)width * met->scale);
 	bbox->y1 += met->font_size;
 	mline.bbox.y1 = bbox->y1;
 	mline.start = start;
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index 0f9e9e35a98..d13b4eac272 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -665,7 +665,7 @@  int vidconsole_select_font(struct udevice *dev, void *ctx, const char *name,
 }
 
 int vidconsole_measure(struct udevice *dev, const char *name, uint size,
-		       const char *text, int limit,
+		       const char *text, int len, int limit,
 		       struct vidconsole_bbox *bbox, struct alist *lines)
 {
 	struct vidconsole_ctx *ctx = vidconsole_ctx(dev);
@@ -675,7 +675,8 @@  int vidconsole_measure(struct udevice *dev, const char *name, uint size,
 	if (ops->measure) {
 		if (lines)
 			alist_empty(lines);
-		ret = ops->measure(dev, name, size, text, limit, bbox, lines);
+		ret = ops->measure(dev, name, size, text, len, limit, bbox,
+				   lines);
 		if (ret != -ENOSYS)
 			return ret;
 	}
@@ -683,7 +684,7 @@  int vidconsole_measure(struct udevice *dev, const char *name, uint size,
 	bbox->valid = true;
 	bbox->x0 = 0;
 	bbox->y0 = 0;
-	bbox->x1 = ctx->x_charsize * strlen(text);
+	bbox->x1 = ctx->x_charsize * (len < 0 ? strlen(text) : len);
 	bbox->y1 = ctx->y_charsize;
 
 	return 0;
diff --git a/include/video_console.h b/include/video_console.h
index 13d32dea2a9..1861138c152 100644
--- a/include/video_console.h
+++ b/include/video_console.h
@@ -221,11 +221,13 @@  struct vidconsole_bbox {
  * vidconsole_mline - Holds information about a line of measured text
  *
  * @bbox: Bounding box of the line, assuming it starts at 0,0
+ * @xpos: Cursor x position at end of line (truncated, not ceiled like bbox.x1)
  * @start: String index of the first character in the line
  * @len: Number of characters in the line
  */
 struct vidconsole_mline {
 	struct vidconsole_bbox bbox;
+	int xpos;
 	int start;
 	int len;
 };
@@ -355,6 +357,7 @@  struct vidconsole_ops {
 	 * @name:	Font name to use (NULL to use default)
 	 * @size:	Font size to use (0 to use default)
 	 * @text:	Text to measure
+	 * @len:	Number of characters to measure, or -1 for whole string
 	 * @limit:	Width limit for each line, or -1 if none
 	 * @bbox:	Returns bounding box of text, assuming it is positioned
 	 *		at 0,0
@@ -365,7 +368,7 @@  struct vidconsole_ops {
 	 * Returns: 0 on success, -ENOENT if no such font
 	 */
 	int (*measure)(struct udevice *dev, const char *name, uint size,
-		       const char *text, int limit,
+		       const char *text, int len, int limit,
 		       struct vidconsole_bbox *bbox, struct alist *lines);
 
 	/**
@@ -485,6 +488,7 @@  int vidconsole_select_font(struct udevice *dev, void *ctx, const char *name,
  * @name:	Font name to use (NULL to use default)
  * @size:	Font size to use (0 to use default)
  * @text:	Text to measure
+ * @len:	Number of characters to measure, or -1 for whole string
  * @limit:	Width limit for each line, or -1 if none
  * @bbox:	Returns bounding box of text, assuming it is positioned
  *		at 0,0
@@ -495,7 +499,7 @@  int vidconsole_select_font(struct udevice *dev, void *ctx, const char *name,
  * Returns: 0 on success, -ENOENT if no such font
  */
 int vidconsole_measure(struct udevice *dev, const char *name, uint size,
-		       const char *text, int limit,
+		       const char *text, int len, int limit,
 		       struct vidconsole_bbox *bbox, struct alist *lines);
 /**
  * vidconsole_nominal() - Measure the expected width of a line of text
diff --git a/test/dm/video.c b/test/dm/video.c
index d3ecb62b43a..92b2ee9a6e3 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -982,7 +982,7 @@  static int dm_test_font_measure(struct unit_test_state *uts)
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_position_cursor(con, 0, 0);
 	alist_init_struct(&lines, struct vidconsole_mline);
-	ut_assertok(vidconsole_measure(con, NULL, 0, test_string, -1, &bbox,
+	ut_assertok(vidconsole_measure(con, NULL, 0, test_string, -1, -1, &bbox,
 				       &lines));
 	ut_asserteq(0, bbox.x0);
 	ut_asserteq(0, bbox.y0);
@@ -1013,8 +1013,8 @@  static int dm_test_font_measure(struct unit_test_state *uts)
 	ut_asserteq(strlen(test_string + nl + 1), line->len);
 
 	/* now use a limit on the width */
-	ut_assertok(vidconsole_measure(con, NULL, 0, test_string, limit, &bbox,
-				       &lines));
+	ut_assertok(vidconsole_measure(con, NULL, 0, test_string, -1, limit,
+				       &bbox, &lines));
 	ut_asserteq(0, bbox.x0);
 	ut_asserteq(0, bbox.y0);
 	ut_asserteq(0x31e, bbox.x1);