Mercurial > hg > openttd
changeset 13263:d65c47851aab draft
(svn r17772) -Fix [FS#3264]: CJK languages don't have spaces, so for adding newlines (multi line strings) we need to (properly) handle the case when there are no spaces instead of truncating the string.
author | rubidium <rubidium@openttd.org> |
---|---|
date | Tue, 13 Oct 2009 20:19:34 +0000 |
parents | 4738f109dfbb |
children | fd77863ff104 |
files | src/gfx.cpp src/gfx_func.h src/network/network_chat_gui.cpp |
diffstat | 3 files changed, 47 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -619,12 +619,13 @@ * starting with index 0 is the real string end. * * @param str string to check and correct for length restrictions + * @param last the last valid location (for '\0') in the buffer of str * @param maxw the maximum width the string can have on one line * @return return a 32bit wide number consisting of 2 packed values: * 0 - 15 the number of lines ADDED to the string * 16 - 31 the fontsize in which the length calculation was done at */ -uint32 FormatStringLinebreaks(char *str, int maxw) +uint32 FormatStringLinebreaks(char *str, const char *last, int maxw) { FontSize size = _cur_fontsize; int num = 0; @@ -632,6 +633,7 @@ assert(maxw > 0); for (;;) { + /* The character *after* the last space. */ char *last_space = NULL; int w = 0; @@ -641,18 +643,49 @@ if (IsWhitespace(c)) last_space = str; if (IsPrintable(c)) { - w += GetCharacterWidth(size, c); - /* string is longer than maximum width so we need to decide what to - * do. We can do two things: - * 1. If no whitespace was found at all up until now (on this line) then - * we will truncate the string and bail out. - * 2. In all other cases force a linebreak at the last seen whitespace */ + int char_w = GetCharacterWidth(size, c); + w += char_w; if (w > maxw) { - if (last_space == NULL) { - *Utf8PrevChar(str) = '\0'; + /* The string is longer than maximum width so we need to decide + * what to do with it. */ + if (w == char_w) { + /* The character is wider than allowed width; don't know + * what to do with this case... bail out! */ return num + (size << 16); } - str = last_space; + if (last_space == NULL) { + /* No space has been found. Just terminate at our current + * location. This usually happens for languages that do not + * require spaces in strings, like Chinese, Japanese and + * Korean. For other languages terminating mid-word might + * not be the best, but terminating the whole string instead + * of continuing the word at the next line is worse. */ + str = Utf8PrevChar(str); + size_t len = strlen(str); + char *terminator = str + len; + + /* The string location + length of the string + 1 for '\0' + * always fits; otherwise there's no trailing '\0' and it + * it not a valid string. */ + assert(terminator <= last); + assert(*terminator == '\0'); + + /* If the string is too long we have to terminate it earlier. */ + if (terminator == last) { + /* Get the 'begin' of the previous character and make that + * the terminator of the string; we truncate it 'early'. */ + *Utf8PrevChar(terminator) = '\0'; + len = strlen(str); + } + /* Also move the terminator! */ + memmove(str + 1, str, len + 1); + *str = '\0'; + /* str needs to point to the character *after* the last space */ + str++; + } else { + /* A space is found; perfect place to terminate */ + str = last_space; + } break; } } else { @@ -721,7 +754,7 @@ GetString(buffer, str, lastof(buffer)); - uint32 tmp = FormatStringLinebreaks(buffer, maxw); + uint32 tmp = FormatStringLinebreaks(buffer, lastof(buffer), maxw); return GetMultilineStringHeight(buffer, GB(tmp, 0, 16)); } @@ -761,7 +794,7 @@ char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); - uint32 tmp = FormatStringLinebreaks(buffer, maxw); + uint32 tmp = FormatStringLinebreaks(buffer, lastof(buffer), maxw); int num = GB(tmp, 0, 16); int mt = GetCharacterHeight((FontSize)GB(tmp, 16, 16));
--- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -115,7 +115,7 @@ Dimension GetStringBoundingBox(const char *str); Dimension GetStringBoundingBox(StringID strid); -uint32 FormatStringLinebreaks(char *str, int maxw); +uint32 FormatStringLinebreaks(char *str, const char *last, int maxw); int GetStringHeight(StringID str, int maxw); Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion); void LoadStringWidthTable();
--- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -86,7 +86,7 @@ Utf8TrimString(buf, DRAW_STRING_BUFFER); /* Force linebreaks for strings that are too long */ - lines = GB(FormatStringLinebreaks(buf, _chatmsg_box.width - 8), 0, 16) + 1; + lines = GB(FormatStringLinebreaks(buf, lastof(buf), _chatmsg_box.width - 8), 0, 16) + 1; if (lines >= MAX_CHAT_MESSAGES) return; msg_count = GetChatMessageCount();