mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-07-10 13:29:52 -04:00
[Bugfix] FS#13912 - splash_scroller with cyrillic crashes
I think they mean corrupted not crashes as I couldn't repro that splash_scroller stepped by individual chars and split multibyte sequences leaving corrupted chars now it uses the new font_measurestring() to get the max_w and chops it at break chars instead this required a bit of a logic change to the function but should be as good with less complications Change-Id: I692db8b4737f41aec08dbc122fb844028498326d
This commit is contained in:
parent
1c84362f3e
commit
a7754eee71
3 changed files with 69 additions and 52 deletions
|
|
@ -876,6 +876,7 @@ static const struct plugin_api rockbox_api = {
|
|||
|
||||
/* new stuff at the end, sort into place next time
|
||||
the API gets incompatible */
|
||||
font_measurestring,
|
||||
};
|
||||
|
||||
static int plugin_buffer_handle;
|
||||
|
|
|
|||
|
|
@ -1040,6 +1040,8 @@ struct plugin_api {
|
|||
|
||||
/* new stuff at the end, sort into place next time
|
||||
the API gets incompatible */
|
||||
int (*font_measurestring)(const unsigned char *str, size_t maxbytes,
|
||||
size_t maxwidth, int *w, int *h, int fontnum);
|
||||
};
|
||||
|
||||
/* plugin header */
|
||||
|
|
|
|||
|
|
@ -74,82 +74,96 @@ int splash_scroller(int timeout, const char* str)
|
|||
|
||||
font_getstringsize("W", &ch_w, &ch_h, fontnum);
|
||||
|
||||
const int max_w = LCD_WIDTH - (ch_w * 2);
|
||||
const int max_w = LCD_WIDTH;
|
||||
const int max_lines = LCD_HEIGHT / ch_h - 1;
|
||||
const int wrap_thresh = (LCD_WIDTH / 3);
|
||||
const char *ch;
|
||||
const char *brk;
|
||||
const int wrap_thresh = (LCD_WIDTH / 4);
|
||||
|
||||
const int max_ch = (LCD_WIDTH / ch_w - 1) * 2;
|
||||
char line[max_ch + 2]; /* display buffer */
|
||||
const char break_chars[] = "@#$%^&*+-{}[]()/\\|<>:;.,? _\n\r\t";
|
||||
char line[max_ch + 2]; /* display buffer +2 incase of tab chars */
|
||||
const char break_chars[] = "/\\ \r\n\f\v";
|
||||
const char *ch, *brk;
|
||||
|
||||
int linepos, curline, linesdisp, realline, chars_next_break;
|
||||
int linepos, curline, linesdisp, maxl, last_break;
|
||||
int realline = 0;
|
||||
int action = ACTION_NONE;
|
||||
int firstline = 0;
|
||||
int cycles = 2; /* get action timeout returns immediately on first call */
|
||||
|
||||
while (cycles > 0)
|
||||
{
|
||||
/* walk whole buffer every refresh, only display relevant portion */
|
||||
lcd_clear_display();
|
||||
curline = 0;
|
||||
linepos = 0;
|
||||
linesdisp = 0;
|
||||
last_break = 0;
|
||||
ch = str;
|
||||
for (; *ch && linepos < max_ch; ch++)
|
||||
while(*ch != '\0')
|
||||
{
|
||||
if (ch[0] == '\t')
|
||||
linepos = 0;
|
||||
brk = NULL;
|
||||
maxl = rb->font_measurestring(ch, max_ch, max_w, &w, NULL, fontnum);
|
||||
for (; *ch && linepos < maxl; ch++)
|
||||
{
|
||||
line[linepos++] = ' ';
|
||||
line[linepos] = ' ';
|
||||
}
|
||||
else if (ch[0] == '\b' && timeout > 0)
|
||||
{
|
||||
line[linepos] = ' ';
|
||||
beep_play(1000, HZ, 1000);
|
||||
}
|
||||
else if (ch[0] < ' ' && ch[0] > '\0') /* Dont copy control characters */
|
||||
line[linepos] = (linepos == 0) ? '\0' : ' ';
|
||||
else
|
||||
line[linepos] = ch[0];
|
||||
if (strpbrk_n(ch, 1, break_chars))
|
||||
{
|
||||
last_break = linepos;
|
||||
brk = ch;
|
||||
if (!isgraph(*brk)) /*!isprint() || isspace()*/
|
||||
brk++;
|
||||
if (*ch == '\n')
|
||||
{
|
||||
ch++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ch[0] == '\t')
|
||||
{
|
||||
line[linepos++] = ' ';
|
||||
line[linepos] = ' ';
|
||||
if(maxl == max_ch)
|
||||
maxl-=2;
|
||||
}
|
||||
else if (ch[0] == '\b' || ch[0] == '\a')
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
beep_play(1000, HZ, 1000);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ch[0] < ' ' && ch[0] > '\0') /* Dont copy control characters */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
line[linepos] = ch[0];
|
||||
|
||||
line[linepos + 1] = '\0'; /* terminate to check text extent */
|
||||
font_getstringsize(line, &w, NULL, fontnum);
|
||||
linepos++;
|
||||
}
|
||||
line[linepos] = '\0';
|
||||
|
||||
/* try to not split in middle of words */
|
||||
if (w + wrap_thresh >= max_w &&
|
||||
strpbrk_n(ch, 1, break_chars))
|
||||
if (last_break > 0 && *ch != '\0')
|
||||
{
|
||||
brk = strpbrk_n(ch+1, max_ch, break_chars);
|
||||
chars_next_break = (brk - ch);
|
||||
if (brk &&
|
||||
(chars_next_break < 2 || w + (ch_w * chars_next_break) > max_w))
|
||||
if (strpbrk_n(ch, 1, break_chars) ||
|
||||
(w + wrap_thresh > max_w && strpbrk_n(ch, max_ch, break_chars)))
|
||||
{
|
||||
if (!isprint(line[linepos]))
|
||||
{
|
||||
line[linepos] = '\0';
|
||||
ch--; /* back-up we want it on the next line */
|
||||
}
|
||||
w += max_w;
|
||||
line[last_break] = '\0';
|
||||
ch = brk;
|
||||
}
|
||||
}
|
||||
realline = curline - firstline;
|
||||
if (realline >= 0 && realline < max_lines)
|
||||
{
|
||||
lcd_putsxy(0, realline * ch_h, line);
|
||||
linesdisp++;
|
||||
}
|
||||
|
||||
if (w > max_w ||
|
||||
(ch[0] >= '\n' && iscntrl(ch[0])) ||
|
||||
ch[1] == '\0')
|
||||
{
|
||||
realline = curline - firstline;
|
||||
if (realline >= 0 && realline < max_lines)
|
||||
{
|
||||
lcd_putsxy(0, realline * ch_h, line);
|
||||
linesdisp++;
|
||||
}
|
||||
linepos = 0;
|
||||
curline++;
|
||||
continue;
|
||||
}
|
||||
linepos++;
|
||||
curline++;
|
||||
}
|
||||
|
||||
if (realline >= max_lines)
|
||||
{
|
||||
rb->lcd_hline(10, LCD_WIDTH - 10, LCD_HEIGHT - 1);
|
||||
}
|
||||
|
||||
lcd_update();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue