video: truetype: Support a limit on the width of a line
Expo needs to be able to word-wrap lines so that they are displayed as the user expects. Add a limit on the width of each line and support this in the measurement algorithm. Add a log category to truetype while we are here. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -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, NULL);
|
||||
txt->font_size, str, -1, &bbox, NULL);
|
||||
if (ret)
|
||||
return log_msg_ret("mea", ret);
|
||||
if (widthp)
|
||||
|
@@ -3,6 +3,8 @@
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_VIDEO
|
||||
|
||||
#include <abuf.h>
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
@@ -733,16 +735,17 @@ 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,
|
||||
struct alist *lines)
|
||||
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;
|
||||
const char *s, *last_space;
|
||||
int width, last_width;
|
||||
stbtt_fontinfo *font;
|
||||
int lsb, advance;
|
||||
int width;
|
||||
int start;
|
||||
int limit;
|
||||
int lastch;
|
||||
int ret;
|
||||
|
||||
@@ -754,14 +757,30 @@ 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;
|
||||
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;
|
||||
|
||||
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;
|
||||
@@ -772,10 +791,16 @@ static int truetype_measure(struct udevice *dev, const char *name, uint size,
|
||||
lastch = ch;
|
||||
|
||||
/* see if we need to start a new line */
|
||||
if (ch == '\n') {
|
||||
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;
|
||||
@@ -788,8 +813,7 @@ static int truetype_measure(struct udevice *dev, const char *name, uint size,
|
||||
mline.start, mline.len, mline.len, text + mline.start);
|
||||
|
||||
start = s - text;
|
||||
if (ch == '\n')
|
||||
start++;
|
||||
start++;
|
||||
lastch = 0;
|
||||
neww = 0;
|
||||
}
|
||||
@@ -811,7 +835,7 @@ static int truetype_measure(struct udevice *dev, const char *name, uint size,
|
||||
bbox->valid = true;
|
||||
bbox->x0 = 0;
|
||||
bbox->y0 = 0;
|
||||
bbox->x1 = tt_ceil((double)width * met->scale);
|
||||
bbox->x1 = max(bbox->x1, mline.bbox.x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -608,8 +608,8 @@ 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,
|
||||
struct alist *lines)
|
||||
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);
|
||||
@@ -618,7 +618,7 @@ int vidconsole_measure(struct udevice *dev, const char *name, uint size,
|
||||
if (ops->measure) {
|
||||
if (lines)
|
||||
alist_empty(lines);
|
||||
ret = ops->measure(dev, name, size, text, bbox, lines);
|
||||
ret = ops->measure(dev, name, size, text, limit, bbox, lines);
|
||||
if (ret != -ENOSYS)
|
||||
return ret;
|
||||
}
|
||||
|
@@ -250,6 +250,7 @@ struct vidconsole_ops {
|
||||
* @name: Font name to use (NULL to use default)
|
||||
* @size: Font size to use (0 to use default)
|
||||
* @text: Text to measure
|
||||
* @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
|
||||
@@ -259,8 +260,8 @@ struct vidconsole_ops {
|
||||
* Returns: 0 on success, -ENOENT if no such font
|
||||
*/
|
||||
int (*measure)(struct udevice *dev, const char *name, uint size,
|
||||
const char *text, struct vidconsole_bbox *bbox,
|
||||
struct alist *lines);
|
||||
const char *text, int limit,
|
||||
struct vidconsole_bbox *bbox, struct alist *lines);
|
||||
|
||||
/**
|
||||
* nominal() - Measure the expected width of a line of text
|
||||
@@ -350,6 +351,7 @@ int vidconsole_select_font(struct udevice *dev, const char *name, uint size);
|
||||
* @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
|
||||
@@ -359,8 +361,8 @@ int vidconsole_select_font(struct udevice *dev, const char *name, uint size);
|
||||
* 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,
|
||||
struct alist *lines);
|
||||
const char *text, int limit,
|
||||
struct vidconsole_bbox *bbox, struct alist *lines);
|
||||
/**
|
||||
* vidconsole_nominal() - Measure the expected width of a line of text
|
||||
*
|
||||
|
@@ -789,6 +789,7 @@ static int dm_test_font_measure(struct unit_test_state *uts)
|
||||
struct vidconsole_bbox bbox;
|
||||
struct video_priv *priv;
|
||||
struct udevice *dev, *con;
|
||||
const int limit = 0x320;
|
||||
struct alist lines;
|
||||
int nl;
|
||||
|
||||
@@ -801,7 +802,7 @@ static int dm_test_font_measure(struct unit_test_state *uts)
|
||||
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
||||
vidconsole_position_cursor(con, 0, 0);
|
||||
alist_init_struct(&lines, struct vidconsole_mline);
|
||||
ut_assertok(vidconsole_measure(con, NULL, 0, test_string, &bbox,
|
||||
ut_assertok(vidconsole_measure(con, NULL, 0, test_string, -1, &bbox,
|
||||
&lines));
|
||||
ut_asserteq(0, bbox.x0);
|
||||
ut_asserteq(0, bbox.y0);
|
||||
@@ -831,6 +832,62 @@ static int dm_test_font_measure(struct unit_test_state *uts)
|
||||
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);
|
||||
|
Reference in New Issue
Block a user