summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2025-05-02 13:57:26 -0600
committerTom Rini <trini@konsulko.com>2025-05-02 13:57:26 -0600
commit6cc812f8cc55c132458c7da5b9fb7666315cbe8c (patch)
tree297fb9e724f252a3fdb46ee28348e66ff7c05a96
parent4ca87fd18c1b718be423755939a6e5b1688869f5 (diff)
parent7703cfe025cbbb2277498483304b4db958521d9e (diff)
Merge patch series "video: Enhancements related to truetype and console"
Simon Glass <sjg@chromium.org> says: This series includes some precursor patches needed for forthcoming expo enhancements. - truetype support for multiple lines - make white-on-black a runtime option - support drawing a rectangle
-rw-r--r--arch/sandbox/dts/test.dts1
-rw-r--r--boot/expo.c2
-rw-r--r--boot/scene.c10
-rw-r--r--common/console.c18
-rw-r--r--drivers/video/console_truetype.c90
-rw-r--r--drivers/video/vidconsole-uclass.c36
-rw-r--r--drivers/video/video-uclass.c52
-rw-r--r--include/console.h15
-rw-r--r--include/test/video.h45
-rw-r--r--include/video.h31
-rw-r--r--include/video_console.h83
-rw-r--r--test/dm/video.c352
12 files changed, 594 insertions, 141 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 52e9ddbf50f..7026c73bc69 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -131,6 +131,7 @@
font-size = <30>;
menu-inset = <3>;
menuitem-gap-y = <1>;
+ white-on-black;
};
cedit-theme {
diff --git a/boot/expo.c b/boot/expo.c
index 786f665f53c..8ce645e5a8f 100644
--- a/boot/expo.c
+++ b/boot/expo.c
@@ -194,7 +194,7 @@ int expo_render(struct expo *exp)
u32 colour;
int ret;
- back = CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK) ? VID_BLACK : VID_WHITE;
+ back = vid_priv->white_on_black ? VID_BLACK : VID_WHITE;
colour = video_index_to_colour(vid_priv, back);
ret = video_fill(dev, colour);
if (ret)
diff --git a/boot/scene.c b/boot/scene.c
index 3290a40222a..fb82ffe768c 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -298,7 +298,7 @@ int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
}
ret = vidconsole_measure(scn->expo->cons, txt->font_name,
- txt->font_size, str, &bbox);
+ txt->font_size, str, -1, &bbox, NULL);
if (ret)
return log_msg_ret("mea", ret);
if (widthp)
@@ -330,8 +330,9 @@ static void scene_render_background(struct scene_obj *obj, bool box_only)
enum colour_idx fore, back;
uint inset = theme->menu_inset;
+ vid_priv = dev_get_uclass_priv(dev);
/* draw a background for the object */
- if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
+ if (vid_priv->white_on_black) {
fore = VID_DARK_GREY;
back = VID_WHITE;
} else {
@@ -344,7 +345,6 @@ static void scene_render_background(struct scene_obj *obj, bool box_only)
return;
vidconsole_push_colour(cons, fore, back, &old);
- vid_priv = dev_get_uclass_priv(dev);
video_fill_part(dev, label_bbox.x0 - inset, label_bbox.y0 - inset,
label_bbox.x1 + inset, label_bbox.y1 + inset,
vid_priv->colour_fg);
@@ -408,7 +408,8 @@ static int scene_obj_render(struct scene_obj *obj, bool text_mode)
struct vidconsole_colour old;
enum colour_idx fore, back;
- if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
+ vid_priv = dev_get_uclass_priv(dev);
+ if (vid_priv->white_on_black) {
fore = VID_BLACK;
back = VID_WHITE;
} else {
@@ -416,7 +417,6 @@ static int scene_obj_render(struct scene_obj *obj, bool text_mode)
back = VID_BLACK;
}
- vid_priv = dev_get_uclass_priv(dev);
if (obj->flags & SCENEOF_POINT) {
vidconsole_push_colour(cons, fore, back, &old);
video_fill_part(dev, x - theme->menu_inset, y,
diff --git a/common/console.c b/common/console.c
index 275da2f264d..48586fd2166 100644
--- a/common/console.c
+++ b/common/console.c
@@ -359,6 +359,24 @@ void console_puts_select_stderr(bool serial_only, const char *s)
console_puts_select(stderr, serial_only, s);
}
+int console_printf_select_stderr(bool serial_only, const char *fmt, ...)
+{
+ char buf[CONFIG_SYS_PBSIZE];
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+
+ /* For this to work, buf must be larger than anything we ever want to
+ * print.
+ */
+ ret = vscnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ console_puts_select_stderr(serial_only, buf);
+
+ return ret;
+}
+
static void console_puts(int file, const char *s)
{
int i;
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index 980baee83cf..6d2c2c2e177 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -3,6 +3,8 @@
* Copyright (c) 2016 Google, Inc
*/
+#define LOG_CATEGORY UCLASS_VIDEO
+
#include <abuf.h>
#include <dm.h>
#include <log.h>
@@ -488,10 +490,12 @@ static int console_truetype_backspace(struct udevice *dev)
static int console_truetype_entry_start(struct udevice *dev)
{
+ struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
struct console_tt_priv *priv = dev_get_priv(dev);
/* A new input line has start, so clear our history */
priv->pos_ptr = 0;
+ vc_priv->last_ch = 0;
return 0;
}
@@ -733,14 +737,18 @@ static int truetype_select_font(struct udevice *dev, const char *name,
}
static int truetype_measure(struct udevice *dev, const char *name, uint size,
- const char *text, struct vidconsole_bbox *bbox)
+ const char *text, int pixel_limit,
+ struct vidconsole_bbox *bbox, struct alist *lines)
{
struct console_tt_metrics *met;
+ struct vidconsole_mline mline;
+ const char *s, *last_space;
+ int width, last_width;
stbtt_fontinfo *font;
int lsb, advance;
- const char *s;
- int width;
- int last;
+ int start;
+ int limit;
+ int lastch;
int ret;
ret = get_metrics(dev, name, size, &met);
@@ -751,27 +759,85 @@ static int truetype_measure(struct udevice *dev, const char *name, uint size,
if (!*text)
return 0;
+ limit = -1;
+ if (pixel_limit != -1)
+ limit = tt_ceil((double)pixel_limit / met->scale);
+
font = &met->font;
width = 0;
- for (last = 0, s = text; *s; s++) {
+ bbox->y1 = 0;
+ bbox->x1 = 0;
+ start = 0;
+ last_space = NULL;
+ last_width = 0;
+ for (lastch = 0, s = text; *s; s++) {
+ int neww;
int ch = *s;
- /* Used kerning to fine-tune the position of this character */
- if (last)
- width += stbtt_GetCodepointKernAdvance(font, last, ch);
+ if (ch == ' ') {
+ /*
+ * store the position and width so we can use it again
+ * if we need to word-wrap
+ */
+ last_space = s;
+ last_width = width;
+ }
/* First get some basic metrics about this character */
stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
+ neww = width + advance;
+
+ /* Use kerning to fine-tune the position of this character */
+ if (lastch)
+ neww += stbtt_GetCodepointKernAdvance(font, lastch, ch);
+ lastch = ch;
+
+ /* see if we need to start a new line */
+ if (ch == '\n' || (limit != -1 && neww >= limit)) {
+ if (ch != '\n' && last_space) {
+ s = last_space;
+ width = last_width;
+ }
+ last_space = NULL;
+ mline.bbox.x0 = 0;
+ mline.bbox.y0 = bbox->y1;
+ mline.bbox.x1 = tt_ceil((double)width * met->scale);
+ bbox->x1 = max(bbox->x1, mline.bbox.x1);
+ bbox->y1 += met->font_size;
+ mline.bbox.y1 = bbox->y1;
+ mline.bbox.valid = true;
+ mline.start = start;
+ mline.len = (s - text) - start;
+ if (lines && !alist_add(lines, mline))
+ return log_msg_ret("ttm", -ENOMEM);
+ log_debug("line x1 %d y0 %d y1 %d start %d len %d text '%.*s'\n",
+ mline.bbox.x1, mline.bbox.y0, mline.bbox.y1,
+ mline.start, mline.len, mline.len, text + mline.start);
+
+ start = s - text;
+ start++;
+ lastch = 0;
+ neww = 0;
+ }
- width += advance;
- last = ch;
+ width = neww;
}
+ /* add the final line */
+ mline.bbox.x0 = 0;
+ mline.bbox.y0 = bbox->y1;
+ mline.bbox.x1 = tt_ceil((double)width * met->scale);
+ bbox->y1 += met->font_size;
+ mline.bbox.y1 = bbox->y1;
+ mline.start = start;
+ mline.len = (s - text) - start;
+ if (lines && !alist_add(lines, mline))
+ return log_msg_ret("ttM", -ENOMEM);
+
bbox->valid = true;
bbox->x0 = 0;
bbox->y0 = 0;
- bbox->x1 = tt_ceil((double)width * met->scale);
- bbox->y1 = met->font_size;
+ bbox->x1 = max(bbox->x1, mline.bbox.x1);
return 0;
}
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index a1dfd35b7b8..f1b2d61bd8f 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -127,6 +127,9 @@ void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y)
priv->xcur_frac = VID_TO_POS(x);
priv->xstart_frac = priv->xcur_frac;
priv->ycur = y;
+
+ /* make sure not to kern against the previous character */
+ priv->last_ch = 0;
vidconsole_entry_start(dev);
}
@@ -508,12 +511,14 @@ int vidconsole_put_char(struct udevice *dev, char ch)
return 0;
}
-int vidconsole_put_string(struct udevice *dev, const char *str)
+int vidconsole_put_stringn(struct udevice *dev, const char *str, int maxlen)
{
- const char *s;
+ const char *s, *end = NULL;
int ret;
- for (s = str; *s; s++) {
+ if (maxlen != -1)
+ end = str + maxlen;
+ for (s = str; *s && (maxlen == -1 || s < end); s++) {
ret = vidconsole_put_char(dev, *s);
if (ret)
return ret;
@@ -522,11 +527,19 @@ int vidconsole_put_string(struct udevice *dev, const char *str)
return 0;
}
+int vidconsole_put_string(struct udevice *dev, const char *str)
+{
+ return vidconsole_put_stringn(dev, str, -1);
+}
+
static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
{
struct udevice *dev = sdev->priv;
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
int ret;
+ if (priv->quiet)
+ return;
ret = vidconsole_put_char(dev, ch);
if (ret) {
#ifdef DEBUG
@@ -544,8 +557,11 @@ static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
{
struct udevice *dev = sdev->priv;
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
int ret;
+ if (priv->quiet)
+ return;
ret = vidconsole_put_string(dev, s);
if (ret) {
#ifdef DEBUG
@@ -608,14 +624,17 @@ int vidconsole_select_font(struct udevice *dev, const char *name, uint size)
}
int vidconsole_measure(struct udevice *dev, const char *name, uint size,
- const char *text, struct vidconsole_bbox *bbox)
+ const char *text, int limit,
+ struct vidconsole_bbox *bbox, struct alist *lines)
{
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
struct vidconsole_ops *ops = vidconsole_get_ops(dev);
int ret;
if (ops->measure) {
- ret = ops->measure(dev, name, size, text, bbox);
+ if (lines)
+ alist_empty(lines);
+ ret = ops->measure(dev, name, size, text, limit, bbox, lines);
if (ret != -ENOSYS)
return ret;
}
@@ -784,3 +803,10 @@ void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
y = min_t(short, row * priv->y_charsize, vid_priv->ysize - 1);
vidconsole_set_cursor_pos(dev, x, y);
}
+
+void vidconsole_set_quiet(struct udevice *dev, bool quiet)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+
+ priv->quiet = quiet;
+}
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index 503cdb9f025..53641fc28b6 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -26,6 +26,7 @@
#ifdef CONFIG_SANDBOX
#include <asm/sdl.h>
#endif
+#include "vidconsole_internal.h"
/*
* Theory of operation:
@@ -216,6 +217,40 @@ int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
return 0;
}
+int video_draw_box(struct udevice *dev, int x0, int y0, int x1, int y1,
+ int width, u32 colour)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+ int pbytes = VNBYTES(priv->bpix);
+ void *start, *line;
+ int pixels = x1 - x0;
+ int row;
+
+ start = priv->fb + y0 * priv->line_length;
+ start += x0 * pbytes;
+ line = start;
+ for (row = y0; row < y1; row++) {
+ void *ptr = line;
+ int i;
+
+ for (i = 0; i < width; i++)
+ fill_pixel_and_goto_next(&ptr, colour, pbytes, pbytes);
+ if (row < y0 + width || row >= y1 - width) {
+ for (i = 0; i < pixels - width * 2; i++)
+ fill_pixel_and_goto_next(&ptr, colour, pbytes,
+ pbytes);
+ } else {
+ ptr += (pixels - width * 2) * pbytes;
+ }
+ for (i = 0; i < width; i++)
+ fill_pixel_and_goto_next(&ptr, colour, pbytes, pbytes);
+ line += priv->line_length;
+ }
+ video_damage(dev, x0, y0, x1 - x0, y1 - y0);
+
+ return 0;
+}
+
int video_reserve_from_bloblist(struct video_handoff *ho)
{
if (!ho->fb || ho->size == 0)
@@ -345,7 +380,7 @@ void video_set_default_colors(struct udevice *dev, bool invert)
struct video_priv *priv = dev_get_uclass_priv(dev);
int fore, back;
- if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
+ if (priv->white_on_black) {
/* White is used when switching to bold, use light gray here */
fore = VID_LIGHT_GRAY;
back = VID_BLACK;
@@ -481,6 +516,7 @@ int video_sync(struct udevice *vid, bool force)
video_flush_dcache(vid, true);
#if defined(CONFIG_VIDEO_SANDBOX_SDL)
+ /* to see the copy framebuffer, use priv->copy_fb */
sandbox_sdl_sync(priv->fb);
#endif
priv->last_sync = get_timer(0);
@@ -582,6 +618,18 @@ static void video_idle(struct cyclic_info *cyc)
video_sync_all();
}
+void video_set_white_on_black(struct udevice *dev, bool white_on_black)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ if (priv->white_on_black != white_on_black) {
+ priv->white_on_black = white_on_black;
+ video_set_default_colors(dev, false);
+
+ video_clear(dev);
+ }
+}
+
/* Set up the display ready for use */
static int video_post_probe(struct udevice *dev)
{
@@ -624,6 +672,8 @@ static int video_post_probe(struct udevice *dev)
if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->copy_base)
priv->copy_fb = map_sysmem(plat->copy_base, plat->size);
+ priv->white_on_black = CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK);
+
/* Set up colors */
video_set_default_colors(dev, false);
diff --git a/include/console.h b/include/console.h
index 57fdb0834c1..8d0d7bb8a4c 100644
--- a/include/console.h
+++ b/include/console.h
@@ -170,6 +170,21 @@ int console_announce_r(void);
void console_puts_select_stderr(bool serial_only, const char *s);
/**
+ * console_printf_select_stderr() - Output a formatted string to selected devs
+ *
+ * This writes to stderr only. It is useful for outputting errors. Note that it
+ * uses its own buffer, separate from the print buffer, to allow printing
+ * messages within console/stdio code
+ *
+ * @serial_only: true to output only to serial, false to output to everything
+ * else
+ * @fmt: Printf format string, followed by format arguments
+ * Return: number of characters written
+ */
+int console_printf_select_stderr(bool serial_only, const char *fmt, ...)
+ __attribute__ ((format (__printf__, 2, 3)));
+
+/**
* console_clear() - Clear the console
*
* Uses an ANSI sequence to clear the display, failing back to clearing the
diff --git a/include/test/video.h b/include/test/video.h
new file mode 100644
index 00000000000..000fd708c86
--- /dev/null
+++ b/include/test/video.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2013 Google, Inc.
+ */
+
+#ifndef __TEST_VIDEO_H
+#define __TEST_VIDEO_H
+
+#include <stdbool.h>
+
+struct udevice;
+struct unit_test_state;
+
+/**
+ * video_compress_fb() - Compress the frame buffer and return its size
+ *
+ * We want to write tests which perform operations on the video console and
+ * check that the frame buffer ends up with the correct contents. But it is
+ * painful to store 'known good' images for comparison with the frame
+ * buffer. As an alternative, we can compress the frame buffer and check the
+ * size of the compressed data. This provides a pretty good level of
+ * certainty and the resulting tests need only check a single value.
+ *
+ * @uts: Test state
+ * @dev: Video device
+ * @use_copy: Use copy frame buffer if available
+ * Return: compressed size of the frame buffer, or -ve on error
+ */
+int video_compress_fb(struct unit_test_state *uts, struct udevice *dev,
+ bool use_copy);
+
+/**
+ * check_copy_frame_buffer() - Compare main frame buffer to copy
+ *
+ * If the copy frame buffer is enabled, this compares it to the main
+ * frame buffer. Normally they should have the same contents after a
+ * sync.
+ *
+ * @uts: Test state
+ * @dev: Video device
+ * Return: 0, or -ve on error
+ */
+int video_check_copy_fb(struct unit_test_state *uts, struct udevice *dev);
+
+#endif
diff --git a/include/video.h b/include/video.h
index 2fe2f73a865..9ea6b676463 100644
--- a/include/video.h
+++ b/include/video.h
@@ -100,6 +100,7 @@ enum video_format {
* @fg_col_idx: Foreground color code (bit 3 = bold, bit 0-2 = color)
* @bg_col_idx: Background color code (bit 3 = bold, bit 0-2 = color)
* @last_sync: Monotonic time of last video sync
+ * @white_on_black: Use a black background
*/
struct video_priv {
/* Things set up by the driver: */
@@ -131,6 +132,7 @@ struct video_priv {
u8 fg_col_idx;
u8 bg_col_idx;
ulong last_sync;
+ bool white_on_black;
};
/**
@@ -247,7 +249,7 @@ int video_fill(struct udevice *dev, u32 colour);
/**
* video_fill_part() - Erase a region
*
- * Erase a rectangle of the display within the given bounds.
+ * Erase a rectangle on the display within the given bounds
*
* @dev: Device to update
* @xstart: X start position in pixels from the left
@@ -261,6 +263,23 @@ int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
int yend, u32 colour);
/**
+ * video_draw_box() - Draw a box
+ *
+ * Draw a rectangle on the display within the given bounds
+ *
+ * @dev: Device to update
+ * @x0: X start position in pixels from the left
+ * @y0: Y start position in pixels from the top
+ * @x1: X end position in pixels from the left
+ * @y1: Y end position in pixels from the top
+ * @width: width in pixels
+ * @colour: Value to write
+ * Return: 0 if OK, -ENOSYS if the display depth is not supported
+ */
+int video_draw_box(struct udevice *dev, int x0, int y0, int x1, int y1,
+ int width, u32 colour);
+
+/**
* video_sync() - Sync a device's frame buffer with its hardware
*
* @vid: Device to sync
@@ -347,6 +366,16 @@ void video_set_flush_dcache(struct udevice *dev, bool flush);
void video_set_default_colors(struct udevice *dev, bool invert);
/**
+ * video_set_white_on_black() - Change the setting for white-on-black
+ *
+ * This does nothing if the setting is already the same.
+ *
+ * @dev: video device
+ * @white_on_black: true to use white-on-black, false for black-on-white
+ */
+void video_set_white_on_black(struct udevice *dev, bool white_on_black);
+
+/**
* video_default_font_height() - Get the default font height
*
* @dev: video device
diff --git a/include/video_console.h b/include/video_console.h
index 13197fa4518..8f3f58f3aa9 100644
--- a/include/video_console.h
+++ b/include/video_console.h
@@ -6,6 +6,7 @@
#ifndef __video_console_h
#define __video_console_h
+#include <alist.h>
#include <video.h>
struct abuf;
@@ -52,6 +53,7 @@ enum {
* @row_saved: Saved Y position in pixels (0=top)
* @escape_buf: Buffer to accumulate escape sequence
* @utf8_buf: Buffer to accumulate UTF-8 byte sequence
+ * @quiet: Suppress all output from stdio
*/
struct vidconsole_priv {
struct stdio_dev sdev;
@@ -76,6 +78,7 @@ struct vidconsole_priv {
int col_saved;
char escape_buf[32];
char utf8_buf[5];
+ bool quiet;
};
/**
@@ -120,6 +123,19 @@ 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
+ * @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 start;
+ int len;
+};
+
+/**
* struct vidconsole_ops - Video console operations
*
* These operations work on either an absolute console position (measured
@@ -228,18 +244,26 @@ struct vidconsole_ops {
int (*select_font)(struct udevice *dev, const char *name, uint size);
/**
- * measure() - Measure the bounds of some text
+ * measure() - Measure the bounding box of some text
*
- * @dev: Device to adjust
+ * The text can include newlines
+ *
+ * @dev: Console device to use
* @name: Font name to use (NULL to use default)
* @size: Font size to use (0 to use default)
* @text: Text to measure
+ * @limit: Width limit for each line, or -1 if none
* @bbox: Returns bounding box of text, assuming it is positioned
* at 0,0
+ * @lines: If non-NULL, this must be an alist of
+ * struct vidconsole_mline inited by caller. A separate
+ * record is added for each line of text
+ *
* Returns: 0 on success, -ENOENT if no such font
*/
int (*measure)(struct udevice *dev, const char *name, uint size,
- const char *text, struct vidconsole_bbox *bbox);
+ const char *text, int limit,
+ struct vidconsole_bbox *bbox, struct alist *lines);
/**
* nominal() - Measure the expected width of a line of text
@@ -320,19 +344,27 @@ int vidconsole_get_font(struct udevice *dev, int seq,
*/
int vidconsole_select_font(struct udevice *dev, const char *name, uint size);
-/*
- * vidconsole_measure() - Measuring the bounding box of some text
+/**
+ * vidconsole_measure() - Measure the bounding box of some text
*
- * @dev: Console device to use
- * @name: Font name, NULL for default
- * @size: Font size, ignored if @name is NULL
- * @text: Text to measure
- * @bbox: Returns nounding box of text
- * Returns: 0 if OK, -ve on error
+ * The text can include newlines
+ *
+ * @dev: Device to adjust
+ * @name: Font name to use (NULL to use default)
+ * @size: Font size to use (0 to use default)
+ * @text: Text to measure
+ * @limit: Width limit for each line, or -1 if none
+ * @bbox: Returns bounding box of text, assuming it is positioned
+ * at 0,0
+ * @lines: If non-NULL, this must be an alist of
+ * struct vidconsole_mline inited by caller. The list is emptied
+ * and then a separate record is added for each line of text
+ *
+ * Returns: 0 on success, -ENOENT if no such font
*/
int vidconsole_measure(struct udevice *dev, const char *name, uint size,
- const char *text, struct vidconsole_bbox *bbox);
-
+ const char *text, int limit,
+ struct vidconsole_bbox *bbox, struct alist *lines);
/**
* vidconsole_nominal() - Measure the expected width of a line of text
*
@@ -470,6 +502,23 @@ int vidconsole_entry_start(struct udevice *dev);
int vidconsole_put_char(struct udevice *dev, char ch);
/**
+ * vidconsole_put_stringn() - Output part of a string to the current console pos
+ *
+ * Outputs part of a string to the console and advances the cursor. This
+ * function handles wrapping to new lines and scrolling the console. Special
+ * characters are handled also: \n, \r, \b and \t.
+ *
+ * The device always starts with the cursor at position 0,0 (top left). It
+ * can be adjusted manually using vidconsole_position_cursor().
+ *
+ * @dev: Device to adjust
+ * @str: String to write
+ * @maxlen: Maximum chars to output, or -1 for all
+ * Return: 0 if OK, -ve on error
+ */
+int vidconsole_put_stringn(struct udevice *dev, const char *str, int maxlen);
+
+/**
* vidconsole_put_string() - Output a string to the current console position
*
* Outputs a string to the console and advances the cursor. This function
@@ -537,4 +586,12 @@ void vidconsole_list_fonts(struct udevice *dev);
*/
int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep);
+/**
+ * vidconsole_set_quiet() - Select whether the console should output stdio
+ *
+ * @dev: vidconsole device
+ * @quiet: true to suppress stdout/stderr output, false to enable it
+ */
+void vidconsole_set_quiet(struct udevice *dev, bool quiet);
+
#endif
diff --git a/test/dm/video.c b/test/dm/video.c
index 929fc16d0ef..ecf74605b5c 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -17,8 +17,10 @@
#include <asm/sdl.h>
#include <dm/test.h>
#include <dm/uclass-internal.h>
+#include <test/lib.h>
#include <test/test.h>
#include <test/ut.h>
+#include <test/video.h>
/*
* These tests use the standard sandbox frame buffer, the resolution of which
@@ -44,24 +46,8 @@ static int dm_test_video_base(struct unit_test_state *uts)
}
DM_TEST(dm_test_video_base, UTF_SCAN_PDATA | UTF_SCAN_FDT);
-/**
- * compress_frame_buffer() - Compress the frame buffer and return its size
- *
- * We want to write tests which perform operations on the video console and
- * check that the frame buffer ends up with the correct contents. But it is
- * painful to store 'known good' images for comparison with the frame
- * buffer. As an alternative, we can compress the frame buffer and check the
- * size of the compressed data. This provides a pretty good level of
- * certainty and the resulting tests need only check a single value.
- *
- * @uts: Test state
- * @dev: Video device
- * @use_copy: Use copy frame buffer if available
- * Return: compressed size of the frame buffer, or -ve on error
- */
-static int compress_frame_buffer(struct unit_test_state *uts,
- struct udevice *dev,
- bool use_copy)
+int video_compress_fb(struct unit_test_state *uts, struct udevice *dev,
+ bool use_copy)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
uint destlen;
@@ -86,19 +72,7 @@ static int compress_frame_buffer(struct unit_test_state *uts,
return destlen;
}
-/**
- * check_copy_frame_buffer() - Compare main frame buffer to copy
- *
- * If the copy frame buffer is enabled, this compares it to the main
- * frame buffer. Normally they should have the same contents after a
- * sync.
- *
- * @uts: Test state
- * @dev: Video device
- * Return: 0, or -ve on error
- */
-static int check_copy_frame_buffer(struct unit_test_state *uts,
- struct udevice *dev)
+int video_check_copy_fb(struct unit_test_state *uts, struct udevice *dev)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
@@ -174,31 +148,31 @@ static int dm_test_video_text(struct unit_test_state *uts)
ut_assertok(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "8x16", 0));
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_putc_xy(con, 0, 0, 'a');
- ut_asserteq(79, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(79, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
vidconsole_putc_xy(con, 0, 0, ' ');
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
for (i = 0; i < 20; i++)
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
- ut_asserteq(273, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(273, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
vidconsole_set_row(con, 0, WHITE);
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
for (i = 0; i < 20; i++)
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
- ut_asserteq(273, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(273, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -216,31 +190,31 @@ static int dm_test_video_text_12x22(struct unit_test_state *uts)
ut_assertok(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "12x22", 0));
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_putc_xy(con, 0, 0, 'a');
- ut_asserteq(89, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(89, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
vidconsole_putc_xy(con, 0, 0, ' ');
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
for (i = 0; i < 20; i++)
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
- ut_asserteq(363, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(363, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
vidconsole_set_row(con, 0, WHITE);
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
for (i = 0; i < 20; i++)
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
- ut_asserteq(363, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(363, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -257,8 +231,8 @@ static int dm_test_video_chars(struct unit_test_state *uts)
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "8x16", 0));
vidconsole_put_string(con, test_string);
- ut_asserteq(466, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(466, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -279,24 +253,24 @@ static int dm_test_video_ansi(struct unit_test_state *uts)
/* reference clear: */
video_clear(con->parent);
video_sync(con->parent, false);
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
/* test clear escape sequence: [2J */
vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
/* test set-cursor: [%d;%df */
vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
- ut_asserteq(143, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(143, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
/* test colors (30-37 fg color, 40-47 bg color) */
vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
- ut_asserteq(272, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(272, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -328,28 +302,28 @@ static int check_vidconsole_output(struct unit_test_state *uts, int rot,
ut_assertok(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "8x16", 0));
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
/* Check display wrap */
for (i = 0; i < 120; i++)
vidconsole_put_char(con, 'A' + i % 50);
- ut_asserteq(wrap_size, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(wrap_size, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
/* Check display scrolling */
for (i = 0; i < SCROLL_LINES; i++) {
vidconsole_put_char(con, 'A' + i % 50);
vidconsole_put_char(con, '\n');
}
- ut_asserteq(scroll_size, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(scroll_size, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
/* If we scroll enough, the screen becomes blank again */
for (i = 0; i < SCROLL_LINES; i++)
vidconsole_put_char(con, '\n');
- ut_asserteq(46, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(46, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -423,8 +397,8 @@ static int dm_test_video_bmp(struct unit_test_state *uts)
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
- ut_asserteq(1368, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(1368, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -443,8 +417,8 @@ static int dm_test_video_bmp8(struct unit_test_state *uts)
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
- ut_asserteq(1247, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(1247, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -467,8 +441,8 @@ static int dm_test_video_bmp16(struct unit_test_state *uts)
&src_len));
ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
- ut_asserteq(3700, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(3700, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -491,8 +465,8 @@ static int dm_test_video_bmp24(struct unit_test_state *uts)
&src_len));
ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
- ut_asserteq(3656, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(3656, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -515,8 +489,8 @@ static int dm_test_video_bmp24_32(struct unit_test_state *uts)
&src_len));
ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
- ut_asserteq(6827, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(6827, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -534,8 +508,8 @@ static int dm_test_video_bmp32(struct unit_test_state *uts)
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
- ut_asserteq(2024, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(2024, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -551,8 +525,8 @@ static int dm_test_video_bmp_comp(struct unit_test_state *uts)
ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
- ut_asserteq(1368, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(1368, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -571,8 +545,8 @@ static int dm_test_video_comp_bmp32(struct unit_test_state *uts)
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
- ut_asserteq(2024, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(2024, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -591,8 +565,8 @@ static int dm_test_video_comp_bmp8(struct unit_test_state *uts)
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
- ut_asserteq(1247, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(1247, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -607,8 +581,9 @@ static int dm_test_video_truetype(struct unit_test_state *uts)
ut_assertok(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_put_string(con, test_string);
- ut_asserteq(12174, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ vidconsole_put_stringn(con, test_string, 30);
+ ut_asserteq(13184, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -629,8 +604,8 @@ static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
ut_assertok(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_put_string(con, test_string);
- ut_asserteq(34287, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(34287, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -651,8 +626,8 @@ static int dm_test_video_truetype_bs(struct unit_test_state *uts)
ut_assertok(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_put_string(con, test_string);
- ut_asserteq(29471, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(29471, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
@@ -690,8 +665,8 @@ static int dm_test_video_copy(struct unit_test_state *uts)
vidconsole_put_string(con, test_string);
vidconsole_put_string(con, test_string);
- ut_asserteq(6678, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(6678, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
/*
* Secretly clear the hardware frame buffer, but in a different
@@ -715,8 +690,8 @@ static int dm_test_video_copy(struct unit_test_state *uts)
vidconsole_put_string(con, test_string);
vidconsole_put_string(con, test_string);
video_sync(dev, true);
- ut_asserteq(7589, compress_frame_buffer(uts, dev, false));
- ut_asserteq(7704, compress_frame_buffer(uts, dev, true));
+ ut_asserteq(7589, video_compress_fb(uts, dev, false));
+ ut_asserteq(7704, video_compress_fb(uts, dev, true));
return 0;
}
@@ -771,9 +746,180 @@ static int dm_test_video_damage(struct unit_test_state *uts)
ut_asserteq(0, priv->damage.xend);
ut_asserteq(0, priv->damage.yend);
- ut_asserteq(7339, compress_frame_buffer(uts, dev, false));
- ut_assertok(check_copy_frame_buffer(uts, dev));
+ ut_asserteq(7339, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
DM_TEST(dm_test_video_damage, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
+/* Test font measurement */
+static int dm_test_font_measure(struct unit_test_state *uts)
+{
+ const char *test_string = "There is always much\nto be said for not "
+ "attempting more than you can do and for making a certainty of "
+ "what you try. But this principle, like others in life and "
+ "war, has its exceptions.";
+ const struct vidconsole_mline *line;
+ struct vidconsole_bbox bbox;
+ struct video_priv *priv;
+ struct udevice *dev, *con;
+ const int limit = 0x320;
+ struct alist lines;
+ int nl;
+
+ ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
+ priv = dev_get_uclass_priv(dev);
+ ut_asserteq(1366, priv->xsize);
+ ut_asserteq(768, priv->ysize);
+
+ /* this is using the Nimbus font with size of 18 pixels */
+ 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,
+ &lines));
+ ut_asserteq(0, bbox.x0);
+ ut_asserteq(0, bbox.y0);
+ ut_asserteq(0x3ea, bbox.x1);
+ ut_asserteq(0x24, bbox.y1);
+ ut_asserteq(2, lines.count);
+
+ nl = strchr(test_string, '\n') - test_string;
+
+ line = alist_get(&lines, 0, struct vidconsole_mline);
+ ut_assertnonnull(line);
+ ut_asserteq(0, line->bbox.x0);
+ ut_asserteq(0, line->bbox.y0);
+ ut_asserteq(0x8c, line->bbox.x1);
+ ut_asserteq(0x12, line->bbox.y1);
+ ut_asserteq(0, line->start);
+ ut_asserteq(20, line->len);
+ ut_asserteq(nl, line->len);
+
+ line++;
+ ut_asserteq(0x0, line->bbox.x0);
+ ut_asserteq(0x12, line->bbox.y0);
+ ut_asserteq(0x3ea, line->bbox.x1);
+ ut_asserteq(0x24, line->bbox.y1);
+ ut_asserteq(21, line->start);
+ ut_asserteq(nl + 1, line->start);
+ ut_asserteq(163, line->len);
+ 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_asserteq(0, bbox.x0);
+ ut_asserteq(0, bbox.y0);
+ ut_asserteq(0x31e, bbox.x1);
+ ut_asserteq(0x36, bbox.y1);
+ ut_asserteq(3, lines.count);
+
+ nl = strchr(test_string, '\n') - test_string;
+
+ line = alist_get(&lines, 0, struct vidconsole_mline);
+ ut_assertnonnull(line);
+ ut_asserteq(0, line->bbox.x0);
+ ut_asserteq(0, line->bbox.y0);
+ ut_asserteq(0x8c, line->bbox.x1);
+ ut_asserteq(0x12, line->bbox.y1);
+ ut_asserteq(0, line->start);
+ ut_asserteq(20, line->len);
+ ut_asserteq(nl, line->len);
+ printf("line0 '%.*s'\n", line->len, test_string + line->start);
+ ut_asserteq_strn("There is always much",
+ test_string + line->start);
+
+ line++;
+ ut_asserteq(0x0, line->bbox.x0);
+ ut_asserteq(0x12, line->bbox.y0);
+ ut_asserteq(0x31e, line->bbox.x1);
+ ut_asserteq(0x24, line->bbox.y1);
+ ut_asserteq(21, line->start);
+ ut_asserteq(nl + 1, line->start);
+ ut_asserteq(129, line->len);
+ printf("line1 '%.*s'\n", line->len, test_string + line->start);
+ ut_asserteq_strn("to be said for not attempting more than you can do "
+ "and for making a certainty of what you try. But this "
+ "principle, like others in",
+ test_string + line->start);
+
+ line++;
+ ut_asserteq(0x0, line->bbox.x0);
+ ut_asserteq(0x24, line->bbox.y0);
+ ut_asserteq(0xc8, line->bbox.x1);
+ ut_asserteq(0x36, line->bbox.y1);
+ ut_asserteq(21 + 130, line->start);
+ ut_asserteq(33, line->len);
+ printf("line2 '%.*s'\n", line->len, test_string + line->start);
+ ut_asserteq_strn("life and war, has its exceptions.",
+ test_string + line->start);
+
+ /*
+ * all characters should be accounted for, except the newline and the
+ * space which is consumed in the wordwrap
+ */
+ ut_asserteq(strlen(test_string) - 2,
+ line[-2].len + line[-1].len + line->len);
+
+ return 0;
+}
+DM_TEST(dm_test_font_measure, UTF_SCAN_FDT);
+
+/* Test silencing the video console */
+static int dm_test_video_silence(struct unit_test_state *uts)
+{
+ struct udevice *dev, *con;
+ struct stdio_dev *sdev;
+
+ ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
+
+ /*
+ * use the old console device from before when dm_test_pre_run() was
+ * called, since that is what is in stdio / console
+ */
+ sdev = stdio_get_by_name("vidconsole");
+ ut_assertnonnull(sdev);
+ con = sdev->priv;
+ ut_assertok(vidconsole_clear_and_reset(con));
+ ut_unsilence_console(uts);
+
+ printf("message 1: console\n");
+ vidconsole_put_string(con, "message 1: video\n");
+
+ vidconsole_set_quiet(con, true);
+ printf("second message: console\n");
+ vidconsole_put_string(con, "second message: video\n");
+
+ vidconsole_set_quiet(con, false);
+ printf("final message: console\n");
+ vidconsole_put_string(con, "final message: video\n");
+
+ ut_asserteq(3892, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
+
+ return 0;
+}
+DM_TEST(dm_test_video_silence, UTF_SCAN_FDT);
+
+/* test drawing a box */
+static int dm_test_video_box(struct unit_test_state *uts)
+{
+ struct video_priv *priv;
+ struct udevice *dev;
+
+ ut_assertok(video_get_nologo(uts, &dev));
+ priv = dev_get_uclass_priv(dev);
+ video_draw_box(dev, 100, 100, 200, 200, 3,
+ video_index_to_colour(priv, VID_LIGHT_BLUE));
+ video_draw_box(dev, 300, 100, 400, 200, 1,
+ video_index_to_colour(priv, VID_MAGENTA));
+ video_draw_box(dev, 500, 100, 600, 200, 20,
+ video_index_to_colour(priv, VID_LIGHT_RED));
+ ut_asserteq(133, video_compress_fb(uts, dev, false));
+ ut_assertok(video_check_copy_fb(uts, dev));
+
+ return 0;
+}
+DM_TEST(dm_test_video_box, UTF_SCAN_FDT);