Fix for wordwrapping when there is a space then a newline

release/v2.9
inmarket 2018-01-05 15:55:30 +10:00
parent 87ec4b7c77
commit c41cbd05e9
1 changed files with 42 additions and 38 deletions

View File

@ -31,7 +31,7 @@ static bool get_wordlen(const struct mf_font_s *font, mf_str *text,
struct wordlen_s *result)
{
mf_char c;
mf_str prev;
mf_str prev = *text;
result->word = 0;
result->space = 0;
@ -42,31 +42,35 @@ static bool get_wordlen(const struct mf_font_s *font, mf_str *text,
{
result->chars++;
result->word += mf_character_width(font, c);
prev = *text;
c = mf_getchar(text);
}
prev = *text;
while (c && is_wrap_space(c))
{
result->chars++;
if (c == ' ')
result->space += mf_character_width(font, c);
else if (c == '-')
result->space += mf_character_width(font, '-');
else if (c == '\t')
result->space += mf_character_width(font, 'm') * MF_TABSIZE;
else if (c == '\n')
else if (c == '\n') {
/* Special case for newlines, skip the character then break. */
prev = *text;
break;
}
prev = *text;
c = mf_getchar(text);
}
/* The last loop reads the first character of next word, put it back. */
if (c)
*text = prev;
return (c == '\0' || c == '\n');
}
@ -89,9 +93,9 @@ static bool append_word(const struct mf_font_s *font, int16_t width,
mf_str tmp = *text;
struct wordlen_s wordlen;
bool linebreak;
linebreak = get_wordlen(font, &tmp, &wordlen);
if (current->width + wordlen.word <= width)
{
*text = tmp;
@ -115,10 +119,10 @@ static bool append_char(const struct mf_font_s *font, int16_t width,
mf_str tmp = *text;
mf_char c;
uint16_t w;
c = mf_getchar(&tmp);
w = mf_character_width(font, c);
if (current->width + w <= width)
{
*text = tmp;
@ -142,31 +146,31 @@ static void tune_lines(struct linelen_s *current, struct linelen_s *previous,
int16_t curw1, prevw1;
int16_t curw2, prevw2;
int32_t delta1, delta2;
/* If the lines are rendered as is */
curw1 = current->width - current->last_word.space;
prevw1 = previous->width - previous->last_word.space;
delta1 = sq16(max_width - prevw1) + sq16(max_width - curw1);
/* If the last word is moved */
curw2 = current->width + previous->last_word.word;
prevw2 = previous->width - previous->last_word.word
- previous->last_word.space
- previous->last_word_2.space;
delta2 = sq16(max_width - prevw2) + sq16(max_width - curw2);
if (delta1 > delta2 && curw2 <= max_width)
{
/* Do the change. */
uint16_t chars;
chars = previous->last_word.chars;
previous->chars -= chars;
current->chars += chars;
previous->width -= previous->last_word.word + previous->last_word.space;
current->width += previous->last_word.word + previous->last_word.space;
previous->last_word = previous->last_word_2;
while (chars--) mf_rewind(&current->start);
}
}
@ -177,13 +181,13 @@ void mf_wordwrap(const struct mf_font_s *font, int16_t width,
struct linelen_s current = { 0 };
struct linelen_s previous = { 0 };
bool full;
current.start = text;
while (*text)
{
full = !append_word(font, width, &current, &text);
if (full || current.linebreak)
{
if (!current.chars)
@ -192,17 +196,17 @@ void mf_wordwrap(const struct mf_font_s *font, int16_t width,
* point. */
while (append_char(font, width, &current, &text));
}
if (previous.chars)
{
/* Tune the length and dispatch the previous line. */
if (!previous.linebreak && !current.linebreak)
tune_lines(&current, &previous, width);
if (!callback(previous.start, previous.chars, state))
return;
}
previous = current;
current.start = text;
current.chars = 0;
@ -213,14 +217,14 @@ void mf_wordwrap(const struct mf_font_s *font, int16_t width,
current.last_word.chars = 0;
}
}
/* Dispatch the last lines. */
if (previous.chars)
{
if (!callback(previous.start, previous.chars, state))
return;
}
if (current.chars)
callback(current.start, current.chars, state);
}
@ -231,64 +235,64 @@ void mf_wordwrap(const struct mf_font_s *font, int16_t width,
mf_str text, mf_line_callback_t callback, void *state)
{
mf_str linestart;
/* Current line width and character count */
int16_t lw_cur = 0, cc_cur = 0;
/* Previous wrap point */
int16_t cc_prev;
mf_str ls_prev;
linestart = text;
while (*text)
{
cc_prev = 0;
ls_prev = text;
while (*text)
{
mf_char c;
int16_t new_width;
mf_str tmp;
tmp = text;
c = mf_getchar(&text);
new_width = lw_cur + mf_character_width(font, c);
if (c == '\n')
{
cc_prev = cc_cur + 1;
ls_prev = text;
break;
}
if (new_width > width)
{
text = tmp;
break;
}
cc_cur++;
lw_cur = new_width;
if (is_wrap_space(c))
{
cc_prev = cc_cur;
ls_prev = text;
}
}
/* Handle unbreakable words */
if (cc_prev == 0)
{
cc_prev = cc_cur;
ls_prev = text;
}
if (!callback(linestart, cc_prev, state))
return;
linestart = ls_prev;
text = linestart;
lw_cur = 0;