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
This commit is contained in:
Tom Rini
2025-05-02 13:57:26 -06:00
12 changed files with 594 additions and 141 deletions

View File

@@ -131,6 +131,7 @@
font-size = <30>; font-size = <30>;
menu-inset = <3>; menu-inset = <3>;
menuitem-gap-y = <1>; menuitem-gap-y = <1>;
white-on-black;
}; };
cedit-theme { cedit-theme {

View File

@@ -194,7 +194,7 @@ int expo_render(struct expo *exp)
u32 colour; u32 colour;
int ret; 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); colour = video_index_to_colour(vid_priv, back);
ret = video_fill(dev, colour); ret = video_fill(dev, colour);
if (ret) if (ret)

View File

@@ -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, ret = vidconsole_measure(scn->expo->cons, txt->font_name,
txt->font_size, str, &bbox); txt->font_size, str, -1, &bbox, NULL);
if (ret) if (ret)
return log_msg_ret("mea", ret); return log_msg_ret("mea", ret);
if (widthp) if (widthp)
@@ -330,8 +330,9 @@ static void scene_render_background(struct scene_obj *obj, bool box_only)
enum colour_idx fore, back; enum colour_idx fore, back;
uint inset = theme->menu_inset; uint inset = theme->menu_inset;
vid_priv = dev_get_uclass_priv(dev);
/* draw a background for the object */ /* draw a background for the object */
if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) { if (vid_priv->white_on_black) {
fore = VID_DARK_GREY; fore = VID_DARK_GREY;
back = VID_WHITE; back = VID_WHITE;
} else { } else {
@@ -344,7 +345,6 @@ static void scene_render_background(struct scene_obj *obj, bool box_only)
return; return;
vidconsole_push_colour(cons, fore, back, &old); 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, video_fill_part(dev, label_bbox.x0 - inset, label_bbox.y0 - inset,
label_bbox.x1 + inset, label_bbox.y1 + inset, label_bbox.x1 + inset, label_bbox.y1 + inset,
vid_priv->colour_fg); vid_priv->colour_fg);
@@ -408,7 +408,8 @@ static int scene_obj_render(struct scene_obj *obj, bool text_mode)
struct vidconsole_colour old; struct vidconsole_colour old;
enum colour_idx fore, back; 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; fore = VID_BLACK;
back = VID_WHITE; back = VID_WHITE;
} else { } else {
@@ -416,7 +417,6 @@ static int scene_obj_render(struct scene_obj *obj, bool text_mode)
back = VID_BLACK; back = VID_BLACK;
} }
vid_priv = dev_get_uclass_priv(dev);
if (obj->flags & SCENEOF_POINT) { if (obj->flags & SCENEOF_POINT) {
vidconsole_push_colour(cons, fore, back, &old); vidconsole_push_colour(cons, fore, back, &old);
video_fill_part(dev, x - theme->menu_inset, y, video_fill_part(dev, x - theme->menu_inset, y,

View File

@@ -359,6 +359,24 @@ void console_puts_select_stderr(bool serial_only, const char *s)
console_puts_select(stderr, serial_only, 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) static void console_puts(int file, const char *s)
{ {
int i; int i;

View File

@@ -3,6 +3,8 @@
* Copyright (c) 2016 Google, Inc * Copyright (c) 2016 Google, Inc
*/ */
#define LOG_CATEGORY UCLASS_VIDEO
#include <abuf.h> #include <abuf.h>
#include <dm.h> #include <dm.h>
#include <log.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) 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); struct console_tt_priv *priv = dev_get_priv(dev);
/* A new input line has start, so clear our history */ /* A new input line has start, so clear our history */
priv->pos_ptr = 0; priv->pos_ptr = 0;
vc_priv->last_ch = 0;
return 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, 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 console_tt_metrics *met;
struct vidconsole_mline mline;
const char *s, *last_space;
int width, last_width;
stbtt_fontinfo *font; stbtt_fontinfo *font;
int lsb, advance; int lsb, advance;
const char *s; int start;
int width; int limit;
int last; int lastch;
int ret; int ret;
ret = get_metrics(dev, name, size, &met); 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) if (!*text)
return 0; return 0;
limit = -1;
if (pixel_limit != -1)
limit = tt_ceil((double)pixel_limit / met->scale);
font = &met->font; font = &met->font;
width = 0; 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; int ch = *s;
/* Used kerning to fine-tune the position of this character */ if (ch == ' ') {
if (last) /*
width += stbtt_GetCodepointKernAdvance(font, last, 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 */ /* First get some basic metrics about this character */
stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb); stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
neww = width + advance;
width += advance; /* Use kerning to fine-tune the position of this character */
last = ch; 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 = 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->valid = true;
bbox->x0 = 0; bbox->x0 = 0;
bbox->y0 = 0; bbox->y0 = 0;
bbox->x1 = tt_ceil((double)width * met->scale); bbox->x1 = max(bbox->x1, mline.bbox.x1);
bbox->y1 = met->font_size;
return 0; return 0;
} }

View File

@@ -127,6 +127,9 @@ void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y)
priv->xcur_frac = VID_TO_POS(x); priv->xcur_frac = VID_TO_POS(x);
priv->xstart_frac = priv->xcur_frac; priv->xstart_frac = priv->xcur_frac;
priv->ycur = y; priv->ycur = y;
/* make sure not to kern against the previous character */
priv->last_ch = 0;
vidconsole_entry_start(dev); vidconsole_entry_start(dev);
} }
@@ -508,12 +511,14 @@ int vidconsole_put_char(struct udevice *dev, char ch)
return 0; 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; 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); ret = vidconsole_put_char(dev, *s);
if (ret) if (ret)
return ret; return ret;
@@ -522,11 +527,19 @@ int vidconsole_put_string(struct udevice *dev, const char *str)
return 0; 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) static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
{ {
struct udevice *dev = sdev->priv; struct udevice *dev = sdev->priv;
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
int ret; int ret;
if (priv->quiet)
return;
ret = vidconsole_put_char(dev, ch); ret = vidconsole_put_char(dev, ch);
if (ret) { if (ret) {
#ifdef DEBUG #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) static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
{ {
struct udevice *dev = sdev->priv; struct udevice *dev = sdev->priv;
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
int ret; int ret;
if (priv->quiet)
return;
ret = vidconsole_put_string(dev, s); ret = vidconsole_put_string(dev, s);
if (ret) { if (ret) {
#ifdef DEBUG #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, 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_priv *priv = dev_get_uclass_priv(dev);
struct vidconsole_ops *ops = vidconsole_get_ops(dev); struct vidconsole_ops *ops = vidconsole_get_ops(dev);
int ret; int ret;
if (ops->measure) { 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) if (ret != -ENOSYS)
return ret; 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); y = min_t(short, row * priv->y_charsize, vid_priv->ysize - 1);
vidconsole_set_cursor_pos(dev, x, y); 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;
}

View File

@@ -26,6 +26,7 @@
#ifdef CONFIG_SANDBOX #ifdef CONFIG_SANDBOX
#include <asm/sdl.h> #include <asm/sdl.h>
#endif #endif
#include "vidconsole_internal.h"
/* /*
* Theory of operation: * Theory of operation:
@@ -216,6 +217,40 @@ int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
return 0; 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) int video_reserve_from_bloblist(struct video_handoff *ho)
{ {
if (!ho->fb || ho->size == 0) 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); struct video_priv *priv = dev_get_uclass_priv(dev);
int fore, back; 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 */ /* White is used when switching to bold, use light gray here */
fore = VID_LIGHT_GRAY; fore = VID_LIGHT_GRAY;
back = VID_BLACK; back = VID_BLACK;
@@ -481,6 +516,7 @@ int video_sync(struct udevice *vid, bool force)
video_flush_dcache(vid, true); video_flush_dcache(vid, true);
#if defined(CONFIG_VIDEO_SANDBOX_SDL) #if defined(CONFIG_VIDEO_SANDBOX_SDL)
/* to see the copy framebuffer, use priv->copy_fb */
sandbox_sdl_sync(priv->fb); sandbox_sdl_sync(priv->fb);
#endif #endif
priv->last_sync = get_timer(0); priv->last_sync = get_timer(0);
@@ -582,6 +618,18 @@ static void video_idle(struct cyclic_info *cyc)
video_sync_all(); 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 */ /* Set up the display ready for use */
static int video_post_probe(struct udevice *dev) 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) if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->copy_base)
priv->copy_fb = map_sysmem(plat->copy_base, plat->size); priv->copy_fb = map_sysmem(plat->copy_base, plat->size);
priv->white_on_black = CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK);
/* Set up colors */ /* Set up colors */
video_set_default_colors(dev, false); video_set_default_colors(dev, false);

View File

@@ -169,6 +169,21 @@ int console_announce_r(void);
*/ */
void console_puts_select_stderr(bool serial_only, const char *s); 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 * console_clear() - Clear the console
* *

45
include/test/video.h Normal file
View File

@@ -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

View File

@@ -100,6 +100,7 @@ enum video_format {
* @fg_col_idx: Foreground color code (bit 3 = bold, bit 0-2 = color) * @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) * @bg_col_idx: Background color code (bit 3 = bold, bit 0-2 = color)
* @last_sync: Monotonic time of last video sync * @last_sync: Monotonic time of last video sync
* @white_on_black: Use a black background
*/ */
struct video_priv { struct video_priv {
/* Things set up by the driver: */ /* Things set up by the driver: */
@@ -131,6 +132,7 @@ struct video_priv {
u8 fg_col_idx; u8 fg_col_idx;
u8 bg_col_idx; u8 bg_col_idx;
ulong last_sync; 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 * 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 * @dev: Device to update
* @xstart: X start position in pixels from the left * @xstart: X start position in pixels from the left
@@ -260,6 +262,23 @@ int video_fill(struct udevice *dev, u32 colour);
int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend, int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
int yend, u32 colour); 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 * video_sync() - Sync a device's frame buffer with its hardware
* *
@@ -346,6 +365,16 @@ void video_set_flush_dcache(struct udevice *dev, bool flush);
*/ */
void video_set_default_colors(struct udevice *dev, bool invert); 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 * video_default_font_height() - Get the default font height
* *

View File

@@ -6,6 +6,7 @@
#ifndef __video_console_h #ifndef __video_console_h
#define __video_console_h #define __video_console_h
#include <alist.h>
#include <video.h> #include <video.h>
struct abuf; struct abuf;
@@ -52,6 +53,7 @@ enum {
* @row_saved: Saved Y position in pixels (0=top) * @row_saved: Saved Y position in pixels (0=top)
* @escape_buf: Buffer to accumulate escape sequence * @escape_buf: Buffer to accumulate escape sequence
* @utf8_buf: Buffer to accumulate UTF-8 byte sequence * @utf8_buf: Buffer to accumulate UTF-8 byte sequence
* @quiet: Suppress all output from stdio
*/ */
struct vidconsole_priv { struct vidconsole_priv {
struct stdio_dev sdev; struct stdio_dev sdev;
@@ -76,6 +78,7 @@ struct vidconsole_priv {
int col_saved; int col_saved;
char escape_buf[32]; char escape_buf[32];
char utf8_buf[5]; char utf8_buf[5];
bool quiet;
}; };
/** /**
@@ -119,6 +122,19 @@ struct vidconsole_bbox {
int y1; int y1;
}; };
/**
* 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 * struct vidconsole_ops - Video console operations
* *
@@ -228,18 +244,26 @@ struct vidconsole_ops {
int (*select_font)(struct udevice *dev, const char *name, uint size); 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) * @name: Font name to use (NULL to use default)
* @size: Font size to use (0 to use default) * @size: Font size to use (0 to use default)
* @text: Text to measure * @text: Text to measure
* @limit: Width limit for each line, or -1 if none
* @bbox: Returns bounding box of text, assuming it is positioned * @bbox: Returns bounding box of text, assuming it is positioned
* at 0,0 * 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 * Returns: 0 on success, -ENOENT if no such font
*/ */
int (*measure)(struct udevice *dev, const char *name, uint size, 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 * 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); 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 * The text can include newlines
* @name: Font name, NULL for default *
* @size: Font size, ignored if @name is NULL * @dev: Device to adjust
* @text: Text to measure * @name: Font name to use (NULL to use default)
* @bbox: Returns nounding box of text * @size: Font size to use (0 to use default)
* Returns: 0 if OK, -ve on error * @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, 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 * vidconsole_nominal() - Measure the expected width of a line of text
* *
@@ -469,6 +501,23 @@ int vidconsole_entry_start(struct udevice *dev);
*/ */
int vidconsole_put_char(struct udevice *dev, char ch); 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 * vidconsole_put_string() - Output a string to the current console position
* *
@@ -537,4 +586,12 @@ void vidconsole_list_fonts(struct udevice *dev);
*/ */
int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep); 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 #endif

View File

@@ -17,8 +17,10 @@
#include <asm/sdl.h> #include <asm/sdl.h>
#include <dm/test.h> #include <dm/test.h>
#include <dm/uclass-internal.h> #include <dm/uclass-internal.h>
#include <test/lib.h>
#include <test/test.h> #include <test/test.h>
#include <test/ut.h> #include <test/ut.h>
#include <test/video.h>
/* /*
* These tests use the standard sandbox frame buffer, the resolution of which * 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); DM_TEST(dm_test_video_base, UTF_SCAN_PDATA | UTF_SCAN_FDT);
/** int video_compress_fb(struct unit_test_state *uts, struct udevice *dev,
* compress_frame_buffer() - Compress the frame buffer and return its size bool use_copy)
*
* 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)
{ {
struct video_priv *priv = dev_get_uclass_priv(dev); struct video_priv *priv = dev_get_uclass_priv(dev);
uint destlen; uint destlen;
@@ -86,19 +72,7 @@ static int compress_frame_buffer(struct unit_test_state *uts,
return destlen; return destlen;
} }
/** int video_check_copy_fb(struct unit_test_state *uts, struct udevice *dev)
* 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)
{ {
struct video_priv *priv = dev_get_uclass_priv(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(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "8x16", 0)); ut_assertok(vidconsole_select_font(con, "8x16", 0));
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_putc_xy(con, 0, 0, 'a'); vidconsole_putc_xy(con, 0, 0, 'a');
ut_asserteq(79, compress_frame_buffer(uts, dev, false)); ut_asserteq(79, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
vidconsole_putc_xy(con, 0, 0, ' '); vidconsole_putc_xy(con, 0, 0, ' ');
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i); vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
ut_asserteq(273, compress_frame_buffer(uts, dev, false)); ut_asserteq(273, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
vidconsole_set_row(con, 0, WHITE); vidconsole_set_row(con, 0, WHITE);
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i); vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
ut_asserteq(273, compress_frame_buffer(uts, dev, false)); ut_asserteq(273, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "12x22", 0)); ut_assertok(vidconsole_select_font(con, "12x22", 0));
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_putc_xy(con, 0, 0, 'a'); vidconsole_putc_xy(con, 0, 0, 'a');
ut_asserteq(89, compress_frame_buffer(uts, dev, false)); ut_asserteq(89, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
vidconsole_putc_xy(con, 0, 0, ' '); vidconsole_putc_xy(con, 0, 0, ' ');
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i); vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
ut_asserteq(363, compress_frame_buffer(uts, dev, false)); ut_asserteq(363, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
vidconsole_set_row(con, 0, WHITE); vidconsole_set_row(con, 0, WHITE);
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i); vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
ut_asserteq(363, compress_frame_buffer(uts, dev, false)); ut_asserteq(363, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "8x16", 0)); ut_assertok(vidconsole_select_font(con, "8x16", 0));
vidconsole_put_string(con, test_string); vidconsole_put_string(con, test_string);
ut_asserteq(466, compress_frame_buffer(uts, dev, false)); ut_asserteq(466, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; return 0;
} }
@@ -279,24 +253,24 @@ static int dm_test_video_ansi(struct unit_test_state *uts)
/* reference clear: */ /* reference clear: */
video_clear(con->parent); video_clear(con->parent);
video_sync(con->parent, false); video_sync(con->parent, false);
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
/* test clear escape sequence: [2J */ /* test clear escape sequence: [2J */
vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J"); vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
/* test set-cursor: [%d;%df */ /* test set-cursor: [%d;%df */
vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd"); vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
ut_asserteq(143, compress_frame_buffer(uts, dev, false)); ut_asserteq(143, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
/* test colors (30-37 fg color, 40-47 bg color) */ /* 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"[30;41mfoo"); /* black on red */
vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */ vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
ut_asserteq(272, compress_frame_buffer(uts, dev, false)); ut_asserteq(272, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "8x16", 0)); ut_assertok(vidconsole_select_font(con, "8x16", 0));
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
/* Check display wrap */ /* Check display wrap */
for (i = 0; i < 120; i++) for (i = 0; i < 120; i++)
vidconsole_put_char(con, 'A' + i % 50); vidconsole_put_char(con, 'A' + i % 50);
ut_asserteq(wrap_size, compress_frame_buffer(uts, dev, false)); ut_asserteq(wrap_size, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
/* Check display scrolling */ /* Check display scrolling */
for (i = 0; i < SCROLL_LINES; i++) { for (i = 0; i < SCROLL_LINES; i++) {
vidconsole_put_char(con, 'A' + i % 50); vidconsole_put_char(con, 'A' + i % 50);
vidconsole_put_char(con, '\n'); vidconsole_put_char(con, '\n');
} }
ut_asserteq(scroll_size, compress_frame_buffer(uts, dev, false)); ut_asserteq(scroll_size, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
/* If we scroll enough, the screen becomes blank again */ /* If we scroll enough, the screen becomes blank again */
for (i = 0; i < SCROLL_LINES; i++) for (i = 0; i < SCROLL_LINES; i++)
vidconsole_put_char(con, '\n'); vidconsole_put_char(con, '\n');
ut_asserteq(46, compress_frame_buffer(uts, dev, false)); ut_asserteq(46, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false)); ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
ut_asserteq(1368, compress_frame_buffer(uts, dev, false)); ut_asserteq(1368, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false)); ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
ut_asserteq(1247, compress_frame_buffer(uts, dev, false)); ut_asserteq(1247, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; return 0;
} }
@@ -467,8 +441,8 @@ static int dm_test_video_bmp16(struct unit_test_state *uts)
&src_len)); &src_len));
ut_assertok(video_bmp_display(dev, dst, 0, 0, false)); ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
ut_asserteq(3700, compress_frame_buffer(uts, dev, false)); ut_asserteq(3700, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; return 0;
} }
@@ -491,8 +465,8 @@ static int dm_test_video_bmp24(struct unit_test_state *uts)
&src_len)); &src_len));
ut_assertok(video_bmp_display(dev, dst, 0, 0, false)); ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
ut_asserteq(3656, compress_frame_buffer(uts, dev, false)); ut_asserteq(3656, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; return 0;
} }
@@ -515,8 +489,8 @@ static int dm_test_video_bmp24_32(struct unit_test_state *uts)
&src_len)); &src_len));
ut_assertok(video_bmp_display(dev, dst, 0, 0, false)); ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
ut_asserteq(6827, compress_frame_buffer(uts, dev, false)); ut_asserteq(6827, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false)); ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
ut_asserteq(2024, compress_frame_buffer(uts, dev, false)); ut_asserteq(2024, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false)); ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
ut_asserteq(1368, compress_frame_buffer(uts, dev, false)); ut_asserteq(1368, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false)); ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
ut_asserteq(2024, compress_frame_buffer(uts, dev, false)); ut_asserteq(2024, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(read_file(uts, "tools/logos/denx.bmp", &addr));
ut_assertok(video_bmp_display(dev, addr, 0, 0, false)); ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
ut_asserteq(1247, compress_frame_buffer(uts, dev, false)); ut_asserteq(1247, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_put_string(con, test_string); vidconsole_put_string(con, test_string);
ut_asserteq(12174, compress_frame_buffer(uts, dev, false)); vidconsole_put_stringn(con, test_string, 30);
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_asserteq(13184, video_compress_fb(uts, dev, false));
ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_put_string(con, test_string); vidconsole_put_string(con, test_string);
ut_asserteq(34287, compress_frame_buffer(uts, dev, false)); ut_asserteq(34287, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
vidconsole_put_string(con, test_string); vidconsole_put_string(con, test_string);
ut_asserteq(29471, compress_frame_buffer(uts, dev, false)); ut_asserteq(29471, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; 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);
vidconsole_put_string(con, test_string); vidconsole_put_string(con, test_string);
ut_asserteq(6678, compress_frame_buffer(uts, dev, false)); ut_asserteq(6678, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
/* /*
* Secretly clear the hardware frame buffer, but in a different * 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);
vidconsole_put_string(con, test_string); vidconsole_put_string(con, test_string);
video_sync(dev, true); video_sync(dev, true);
ut_asserteq(7589, compress_frame_buffer(uts, dev, false)); ut_asserteq(7589, video_compress_fb(uts, dev, false));
ut_asserteq(7704, compress_frame_buffer(uts, dev, true)); ut_asserteq(7704, video_compress_fb(uts, dev, true));
return 0; 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.xend);
ut_asserteq(0, priv->damage.yend); ut_asserteq(0, priv->damage.yend);
ut_asserteq(7339, compress_frame_buffer(uts, dev, false)); ut_asserteq(7339, video_compress_fb(uts, dev, false));
ut_assertok(check_copy_frame_buffer(uts, dev)); ut_assertok(video_check_copy_fb(uts, dev));
return 0; return 0;
} }
DM_TEST(dm_test_video_damage, UTF_SCAN_PDATA | UTF_SCAN_FDT); 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);