changeset 19951:34e10abce441 draft

(svn r24885) -Fix: Pass proper UTF-16 strings instead of UCS-2 to ICU in order to preserve characters outside the BMP.
author michi_cc <michi_cc@openttd.org>
date Thu, 03 Jan 2013 23:14:38 +0000
parents cd268aa44111
children 5e7bacb2a8d8
files src/gfx.cpp
diffstat 1 files changed, 30 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -297,11 +297,11 @@
 }
 
 #if !defined(WITH_ICU)
-typedef WChar UChar;
-static UChar *HandleBiDiAndArabicShapes(UChar *text) { return text; }
+static WChar *HandleBiDiAndArabicShapes(WChar *text) { return text; }
 #else
 #include <unicode/ubidi.h>
 #include <unicode/ushape.h>
+#include <unicode/ustring.h>
 
 /**
  * Function to be able to handle right-to-left text and Arabic chars properly.
@@ -332,31 +332,34 @@
  * @param lastof the end of the buffer
  * @return the buffer to draw from
  */
-static UChar *HandleBiDiAndArabicShapes(UChar *buffer)
+static WChar *HandleBiDiAndArabicShapes(WChar *buffer)
 {
-	static UChar input_output[DRAW_STRING_BUFFER];
+	UChar input[DRAW_STRING_BUFFER];
 	UChar intermediate[DRAW_STRING_BUFFER];
+	static WChar output[DRAW_STRING_BUFFER];
 
-	UChar *t = buffer;
-	size_t length = 0;
-	while (*t != '\0' && length < lengthof(input_output) - 1) {
-		input_output[length++] = *t++;
-	}
-	input_output[length] = 0;
+	/* Transform from UTF-32 to internal ICU format of UTF-16. */
+	UErrorCode err = U_ZERO_ERROR;
+	int32_t length = 0;
+	u_strFromUTF32(input, lengthof(input), &length, (UChar32 *)buffer, -1, &err);
+	if (U_FAILURE(err)) return buffer;
 
-	UErrorCode err = U_ZERO_ERROR;
-	UBiDi *para = ubidi_openSized((int32_t)length, 0, &err);
+	UBiDi *para = ubidi_openSized(length, 0, &err);
 	if (para == NULL) return buffer;
 
-	ubidi_setPara(para, input_output, (int32_t)length, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, NULL, &err);
-	ubidi_writeReordered(para, intermediate, (int32_t)length, UBIDI_REMOVE_BIDI_CONTROLS, &err);
-	length = u_shapeArabic(intermediate, (int32_t)length, input_output, lengthof(input_output), U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_LETTERS_SHAPE, &err);
+	ubidi_setPara(para, input, length, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, NULL, &err);
+	length = ubidi_writeReordered(para, intermediate, lengthof(intermediate), UBIDI_REMOVE_BIDI_CONTROLS, &err);
+	length = u_shapeArabic(intermediate, length, input, lengthof(input), U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_LETTERS_SHAPE, &err);
 	ubidi_close(para);
-
 	if (U_FAILURE(err)) return buffer;
 
-	input_output[length] = '\0';
-	return input_output;
+	/* Transform back to UTF-32. */
+	u_strToUTF32((UChar32 *)output, lengthof(output), NULL, input, length, &err);
+	if (U_FAILURE(err)) return buffer;
+
+	/* u_strToUTF32 doesn't add a NUL charcter if the buffer is too small, be safe. */
+	output[lengthof(output) - 1] = '\0';
+	return output;
 }
 #endif /* WITH_ICU */
 
@@ -420,7 +423,7 @@
 	return w;
 }
 
-static int ReallyDoDrawString(const UChar *string, int x, int y, DrawStringParams &params, bool parse_string_also_when_clipped = false);
+static int ReallyDoDrawString(const WChar *string, int x, int y, DrawStringParams &params, bool parse_string_also_when_clipped = false);
 
 /**
  * Get the real width of the string.
@@ -428,7 +431,7 @@
  * @param start_fontsize Fontsize to start the text with
  * @return the width.
  */
-static int GetStringWidth(const UChar *str, FontSize start_fontsize)
+static int GetStringWidth(const WChar *str, FontSize start_fontsize)
 {
 	FontSize size = start_fontsize;
 	int max_width;
@@ -496,11 +499,11 @@
 	 * the string and draw the parts separated by SETX(Y).
 	 * So here we split
 	 */
-	static SmallVector<UChar *, 4> setx_offsets;
+	static SmallVector<WChar *, 4> setx_offsets;
 	setx_offsets.Clear();
 
-	UChar draw_buffer[DRAW_STRING_BUFFER];
-	UChar *p = draw_buffer;
+	WChar draw_buffer[DRAW_STRING_BUFFER];
+	WChar *p = draw_buffer;
 
 	*setx_offsets.Append() = p;
 
@@ -559,8 +562,8 @@
 	/* In case we have a RTL language we swap the alignment. */
 	if (!(align & SA_FORCE) && _current_text_dir == TD_RTL && !(align & SA_STRIP) && (align & SA_HOR_MASK) != SA_HOR_CENTER) align ^= SA_RIGHT;
 
-	for (UChar **iter = setx_offsets.Begin(); iter != setx_offsets.End(); iter++) {
-		UChar *to_draw = *iter;
+	for (WChar **iter = setx_offsets.Begin(); iter != setx_offsets.End(); iter++) {
+		WChar *to_draw = *iter;
 		int offset = 0;
 
 		/* Skip the SETX(Y) and set the appropriate offsets. */
@@ -1088,11 +1091,11 @@
  * @return                    the x-coordinates where the drawing has finished.
  *                            If nothing is drawn, the originally passed x-coordinate is returned
  */
-static int ReallyDoDrawString(const UChar *string, int x, int y, DrawStringParams &params, bool parse_string_also_when_clipped)
+static int ReallyDoDrawString(const WChar *string, int x, int y, DrawStringParams &params, bool parse_string_also_when_clipped)
 {
 	DrawPixelInfo *dpi = _cur_dpi;
 	bool draw_shadow = GetDrawGlyphShadow();
-	UChar c;
+	WChar c;
 	int xo = x;
 
 	if (!parse_string_also_when_clipped) {