summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-10-13 20:19:34 +0000
committerrubidium <rubidium@openttd.org>2009-10-13 20:19:34 +0000
commit3bb1f4217dcb229c2e064e9f0e1d58a757474cc0 (patch)
treee06f35be311d13016ca78baa6bf5972cf9dff6de
parent313fb659433b0af187e04185d0b7875889548372 (diff)
downloadopenttd-3bb1f4217dcb229c2e064e9f0e1d58a757474cc0.tar.xz
(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.
-rw-r--r--src/gfx.cpp57
-rw-r--r--src/gfx_func.h2
-rw-r--r--src/network/network_chat_gui.cpp2
3 files changed, 47 insertions, 14 deletions
diff --git a/src/gfx.cpp b/src/gfx.cpp
index 328e6da1c..8b9c09360 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -619,12 +619,13 @@ int DrawString(int left, int right, int top, StringID str, TextColour colour, St
* 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 @@ uint32 FormatStringLinebreaks(char *str, int maxw)
assert(maxw > 0);
for (;;) {
+ /* The character *after* the last space. */
char *last_space = NULL;
int w = 0;
@@ -641,18 +643,49 @@ uint32 FormatStringLinebreaks(char *str, int maxw)
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 @@ int GetStringHeight(StringID str, int maxw)
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 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str,
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));
diff --git a/src/gfx_func.h b/src/gfx_func.h
index 5dbef7917..c8ba4c0d6 100644
--- a/src/gfx_func.h
+++ b/src/gfx_func.h
@@ -115,7 +115,7 @@ void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
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();
diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp
index 8e9b4cc66..ef05ad931 100644
--- a/src/network/network_chat_gui.cpp
+++ b/src/network/network_chat_gui.cpp
@@ -86,7 +86,7 @@ void CDECL NetworkAddChatMessage(TextColour colour, uint8 duration, const char *
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();