Unicode support.

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1551 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
meep-eep
2005-02-20 00:44:35 +00:00
parent ec9d571efd
commit 820ac4f8f3
8 changed files with 292 additions and 144 deletions
+132 -135
View File
@@ -49,6 +49,8 @@ static void xform_PLUT_step (SIZE TDelta);
static void FlushPLUTXForms (void); static void FlushPLUTXForms (void);
static int ambient_anim_task (void *data); static int ambient_anim_task (void *data);
static BOOLEAN getLineWithinWidth(TEXT *pText,
const unsigned char **startNext, SIZE maxWidth, COUNT maxChars);
#define MAX_RESPONSES 8 #define MAX_RESPONSES 8
#define BACKGROUND_VOL speechVolumeScale == 0.0f ? MAX_VOLUME : (MAX_VOLUME >> 1) #define BACKGROUND_VOL speechVolumeScale == 0.0f ? MAX_VOLUME : (MAX_VOLUME >> 1)
@@ -125,61 +127,30 @@ static Mutex subtitle_mutex;
static const UNICODE * volatile last_subtitle; static const UNICODE * volatile last_subtitle;
static TFB_Image *subtitle_cache; static TFB_Image *subtitle_cache;
/* _count_lines - mostly stolen from add_text, just sees how many lines /* _count_lines - sees how many lines a given input string would take to
a given input string would take to display given the * display given the line wrapping information
line wrapping information */ */
static int _count_lines (PTEXT pText) static int _count_lines (PTEXT pText)
{ {
COUNT maxchars = (COUNT)~0;
UNICODE ch;
const UNICODE *pStr;
SIZE text_width; SIZE text_width;
int num = 0; COUNT maxchars = (COUNT)~0;
const unsigned char *pStr;
int numLines = 0;
BOOLEAN eol;
text_width = CommData.AlienTextWidth; text_width = CommData.AlienTextWidth;
SetContextFont (CommData.AlienFont); SetContextFont (CommData.AlienFont);
pStr = pText->pStr; pStr = pText->pStr;
do do
{ {
++num; ++numLines;
pText->pStr = pStr; pText->pStr = pStr;
pText->CharCount = 1; eol = getLineWithinWidth(pText, &pStr, text_width, maxchars);
} while (!eol && maxchars);
{
BOOLEAN eot;
RECT r, old_r;
COUNT OldCount;
GetContextClipRect (&r);
eot = FALSE;
do
{
old_r = r;
OldCount = pText->CharCount;
while (!(eot = (BOOLEAN)(
(ch = *++pStr) == '\0'
|| ch == '\n'
|| ch == '\r'
|| (COUNT)(pStr - pText->pStr) >= maxchars
)) && ch != ' ')
;
pText->CharCount = pStr - pText->pStr;
TextRect (pText, &r, NULL_PTR);
} while (!eot && r.extent.width < text_width);
if (r.extent.width >= text_width)
{
pText->CharCount = OldCount;
r = old_r;
}
}
pStr = pText->pStr + pText->CharCount;
} while ((ch = *pStr++) != '\0' && ch != '\n' && ch != '\r' && maxchars);
pText->pStr = pStr; pText->pStr = pStr;
return (num); return numLines;
} }
static COORD static COORD
@@ -189,11 +160,11 @@ add_text (int status, PTEXT pTextIn)
TEXT locText; TEXT locText;
PTEXT pText; PTEXT pText;
SIZE leading; SIZE leading;
wchar_t ch;
const unsigned char *pStr; const unsigned char *pStr;
SIZE text_width; SIZE text_width;
int num_lines = 0; int num_lines = 0;
static COORD last_baseline; static COORD last_baseline;
BOOLEAN eol;
BatchGraphics (); BatchGraphics ();
@@ -255,7 +226,7 @@ add_text (int status, PTEXT pTextIn)
maxchars = pTextIn->CharCount; maxchars = pTextIn->CharCount;
locText = *pTextIn; locText = *pTextIn;
locText.baseline.x -= 8; locText.baseline.x -= 8;
locText.CharCount = 1; locText.CharCount = (COUNT)~0;
locText.pStr = "*"; locText.pStr = "*";
font_DrawText (&locText); font_DrawText (&locText);
@@ -274,7 +245,8 @@ add_text (int status, PTEXT pTextIn)
pText->baseline.y -= (leading * num_lines); pText->baseline.y -= (leading * num_lines);
else if (CommData.AlienTextTemplate.valign == VALIGN_MIDDLE) else if (CommData.AlienTextTemplate.valign == VALIGN_MIDDLE)
pText->baseline.y -= ((leading * num_lines) / 2); pText->baseline.y -= ((leading * num_lines) / 2);
if (pText->baseline.y < 0) pText->baseline.y = 0; if (pText->baseline.y < 0)
pText->baseline.y = 0;
} }
do do
@@ -282,93 +254,49 @@ add_text (int status, PTEXT pTextIn)
pText->pStr = pStr; pText->pStr = pStr;
pText->baseline.y += leading; pText->baseline.y += leading;
eol = getLineWithinWidth(pText, &pStr, text_width, maxchars);
maxchars -= pText->CharCount;
if (maxchars != 0)
--maxchars;
numchars += pText->CharCount;
if (status <= 0)
{ {
BOOLEAN eot; if (pText->baseline.y < SIS_SCREEN_HEIGHT)
RECT r, old_r; font_DrawText (pText);
COUNT oldCount;
const unsigned char *oldPStr;
wchar_t oldCh;
COUNT charCount;
GetContextClipRect (&r); if (status < -4 && pText->baseline.y >= -status - 10)
oldCount = 1;
charCount = 0;
ch = '\0';
for (;;)
{ {
old_r = r; ++pStr;
oldPStr = pStr; break;
oldCh = ch;
for (;;)
{
ch = getCharFromString (&pStr);
eot = ch == '\0' || ch == '\n' || ch == '\r'
|| charCount >= maxchars;
if (eot || ch == ' ')
break;
charCount++;
}
oldCount = pText->CharCount;
pText->CharCount = charCount;
TextRect (pText, &r, NULL_PTR);
if (eot || r.extent.width >= text_width)
break;
charCount++;
// For the space in between words.
}
if (r.extent.width >= text_width)
{
pText->CharCount = oldCount;
pStr = oldPStr;
r = old_r;
ch = oldCh;
}
maxchars -= pText->CharCount;
if (maxchars != 0)
--maxchars;
numchars += pText->CharCount;
if (status <= 0)
{
if (pText->baseline.y < SIS_SCREEN_HEIGHT)
font_DrawText (pText);
if (status < -4 && pText->baseline.y >= -status - 10)
{
++pStr;
break;
}
}
else
{
SetContextForeGroundColor (CommData.AlienTextBColor);
--pText->baseline.x;
font_DrawText (pText);
++pText->baseline.x;
--pText->baseline.y;
font_DrawText (pText);
++pText->baseline.x;
++pText->baseline.y;
font_DrawText (pText);
--pText->baseline.x;
++pText->baseline.y;
font_DrawText (pText);
SetContextForeGroundColor (CommData.AlienTextFColor);
--pText->baseline.y;
font_DrawText (pText);
} }
} }
} while (ch != '\0' && ch != '\n' && ch != '\r' && maxchars); else
{
SetContextForeGroundColor (CommData.AlienTextBColor);
--pText->baseline.x;
font_DrawText (pText);
++pText->baseline.x;
--pText->baseline.y;
font_DrawText (pText);
++pText->baseline.x;
++pText->baseline.y;
font_DrawText (pText);
--pText->baseline.x;
++pText->baseline.y;
font_DrawText (pText);
SetContextForeGroundColor (CommData.AlienTextFColor);
--pText->baseline.y;
font_DrawText (pText);
}
} while (!eol && maxchars);
pText->pStr = pStr; pText->pStr = pStr;
if (status == 1) if (status == 1)
@@ -391,6 +319,70 @@ add_text (int status, PTEXT pTextIn)
return (pText->baseline.y); return (pText->baseline.y);
} }
static BOOLEAN
getLineWithinWidth(TEXT *pText, const unsigned char **startNext,
SIZE maxWidth, COUNT maxChars) {
BOOLEAN eol;
// The end of the line of text has been reached.
BOOLEAN done;
// We cannot add any more words.
RECT rect;
COUNT oldCount;
const unsigned char *ptr;
const unsigned char *wordStart;
wchar_t ch;
COUNT charCount;
//GetContextClipRect (&rect);
eol = FALSE;
done = FALSE;
oldCount = 1;
charCount = 0;
ch = '\0';
ptr = pText->pStr;
for (;;)
{
wordStart = ptr;
// Scan one word.
for (;;)
{
if (*ptr == '\0')
{
eol = TRUE;
done = TRUE;
break;
}
ch = getCharFromString (&ptr);
eol = ch == '\0' || ch == '\n' || ch == '\r';
done = eol || charCount >= maxChars;
if (done || ch == ' ')
break;
charCount++;
}
oldCount = pText->CharCount;
pText->CharCount = charCount;
TextRect (pText, &rect, NULL_PTR);
if (rect.extent.width >= maxWidth)
{
pText->CharCount = oldCount;
*startNext = wordStart;
return FALSE;
}
if (done)
{
*startNext = ptr;
return eol;
}
charCount++;
// For the space in between words.
}
}
static void static void
DrawSISComWindow (void) DrawSISComWindow (void)
{ {
@@ -1641,11 +1633,14 @@ DoCommunication (PENCOUNTER_STATE pES)
if (PulsedInputState.key[KEY_MENU_SELECT]) if (PulsedInputState.key[KEY_MENU_SELECT])
{ {
pES->phrase_buf_index = const unsigned char *end;
pES->response_list[pES->cur_response].response_text.CharCount; PTEXT response_text =
wstrncpy (pES->phrase_buf, &pES->response_list[pES->cur_response].response_text;
pES->response_list[pES->cur_response].response_text.pStr, end = skipUTF8Chars(response_text->pStr,
pES->phrase_buf_index); response_text->CharCount);
pES->phrase_buf_index = end - response_text->pStr;
memcpy(pES->phrase_buf, response_text->pStr,
pES->phrase_buf_index);
pES->phrase_buf[pES->phrase_buf_index++] = '\0'; pES->phrase_buf[pES->phrase_buf_index++] = '\0';
LockMutex (GraphicsLock); LockMutex (GraphicsLock);
@@ -1943,7 +1938,7 @@ DoResponsePhrase (RESPONSE_REF R, RESPONSE_FUNC response_func,
pEntry->response_ref = R; pEntry->response_ref = R;
pEntry->response_text.pStr = ConstructStr; pEntry->response_text.pStr = ConstructStr;
if (pEntry->response_text.pStr) if (pEntry->response_text.pStr)
pEntry->response_text.CharCount = wstrlen (ConstructStr); pEntry->response_text.CharCount = (COUNT)~0;
else else
{ {
STRING locString; STRING locString;
@@ -2395,7 +2390,9 @@ do_subtitles (UNICODE *pStr)
CommData.AlienTextTemplate.pStr = pStr; CommData.AlienTextTemplate.pStr = pStr;
t = CommData.AlienTextTemplate; t = CommData.AlienTextTemplate;
CommData.AlienTextTemplate.CharCount = t.pStr - CommData.AlienTextTemplate.pStr; CommData.AlienTextTemplate.CharCount =
utf8StringCountN(CommData.AlienTextTemplate.pStr,
t.pStr);
subtitle_state = WAIT_SUBTITLE; subtitle_state = WAIT_SUBTITLE;
break; break;
} }
+1 -1
View File
@@ -58,7 +58,7 @@ DrawConfirmationWindow (BOOLEAN answer)
t.pStr = "Really Quit?"; t.pStr = "Really Quit?";
t.align = ALIGN_CENTER; t.align = ALIGN_CENTER;
t.valign = VALIGN_BOTTOM; t.valign = VALIGN_BOTTOM;
t.CharCount = ~0; t.CharCount = (COUNT)~0;
font_DrawText (&t); font_DrawText (&t);
t.baseline.y += 10; t.baseline.y += 10;
t.baseline.x = r.corner.x + (r.extent.width >> 2); t.baseline.x = r.corner.x + (r.extent.width >> 2);
+1 -1
View File
@@ -324,7 +324,7 @@ _text_blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr)
static inline FRAME_DESC * static inline FRAME_DESC *
getCharFrame (FONT_DESC *fontPtr, wchar_t ch) { getCharFrame (FONT_DESC *fontPtr, wchar_t ch) {
wchar_t pageStart = ch & 0xff00; wchar_t pageStart = ch & CHARACTER_PAGE_MASK;
FONT_PAGE *page = fontPtr->fontPages; FONT_PAGE *page = fontPtr->fontPages;
for (;;) for (;;)
+1
View File
@@ -25,6 +25,7 @@ typedef struct FontPage
{ {
struct FontPage *next; struct FontPage *next;
wchar_t pageStart; wchar_t pageStart;
#define CHARACTER_PAGE_MASK 0xff800
wchar_t firstChar; wchar_t firstChar;
size_t numChars; size_t numChars;
FRAME_DESC *charDesc; FRAME_DESC *charDesc;
@@ -687,11 +687,11 @@ _GetFontData (uio_Stream *fp, DWORD length)
{ {
// Process one character page. // Process one character page.
size_t endBCD; size_t endBCD;
pageStart = bcds[startBCD].index & 0xff00; pageStart = bcds[startBCD].index & CHARACTER_PAGE_MASK;
endBCD = startBCD; endBCD = startBCD;
while (endBCD < numBCDs && while (endBCD < numBCDs &&
(bcds[endBCD].index & 0xff00) == pageStart) (bcds[endBCD].index & CHARACTER_PAGE_MASK) == pageStart)
endBCD++; endBCD++;
{ {
+15 -2
View File
@@ -144,10 +144,23 @@ GetStringLength (STRING String)
StringIndex = STRING_INDEX (String); StringIndex = STRING_INDEX (String);
LockStringTable (StringTable, &StringTablePtr); LockStringTable (StringTable, &StringTablePtr);
{
STRINGPTR start;
STRINGPTR end;
start = (STRINGPTR) ((BYTE *) StringTablePtr +
StringTablePtr->StringOffsets[StringIndex]);
end = (STRINGPTR) ((BYTE *) StringTablePtr +
StringTablePtr->StringOffsets[StringIndex + 1]);
StringLength = utf8StringCountN(start, end);
}
#if 0
StringLength = (COUNT)( StringLength = (COUNT)(
StringTablePtr->StringOffsets[StringIndex + 1] StringTablePtr->StringOffsets[StringIndex + 1]
- StringTablePtr->StringOffsets[StringIndex] - StringTablePtr->StringOffsets[StringIndex]);
); #endif
UnlockStringTable (StringTable); UnlockStringTable (StringTable);
} }
+132 -3
View File
@@ -17,10 +17,18 @@
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
// Resynchronise (skip everything starting with 0x10xxxxxx):
static inline void
resyncUTF8(const unsigned char **ptr) {
while ((**ptr & 0xc0) == 0x80)
*ptr++;
}
// Get one character from a UTF-8 encoded string. // Get one character from a UTF-8 encoded string.
// *ptr will point to the start of the next character. // *ptr will point to the start of the next character.
// Returns 0 if the encoding is bad. This can be distinguished from the // Returns 0 if the encoding is bad. This can be distinguished from the
// '\0' character by checking whether **ptr == '\0'. // '\0' character by checking whether **ptr == '\0' before calling this
// function.
wchar_t wchar_t
getCharFromString(const unsigned char **ptr) { getCharFromString(const unsigned char **ptr) {
wchar_t result; wchar_t result;
@@ -106,11 +114,132 @@ err:
fprintf(stderr, "Warning: Invalid UTF8 sequence.\n"); fprintf(stderr, "Warning: Invalid UTF8 sequence.\n");
// Resynchronise (skip everything starting with 0x10xxxxxx): // Resynchronise (skip everything starting with 0x10xxxxxx):
while ((**ptr & 0xc0) == 0x80) resyncUTF8(ptr);
*ptr++;
return 0; return 0;
} }
wchar_t
getCharFromStringN(const unsigned char **ptr, const unsigned char *end) {
int numBytes;
if (**ptr < 0x80) {
numBytes = 1;
} else if ((**ptr & 0xe0) == 0xc0) {
numBytes = 2;
} else if ((**ptr & 0xf0) == 0xe0) {
numBytes = 3;
} else if ((**ptr & 0xf8) == 0xf0) {
numBytes = 4;
} else
goto err;
if (*ptr + numBytes > end)
goto err;
return getCharFromString(ptr);
err:
*ptr = end;
return 0;
}
// Get one line from a string.
// A line is terminated with either CRLF (DOS/Windows),
// LF (Unix, MacOS X), or CR (old MacOS).
// The end of the string is reached when **startNext == '\0'.
// NULL is returned if the string is not valid UTF8. In this case
// *end points to the first invalid character (or the character before if
// it was a LF), and *startNext to the start of the next (possibly invalid
// too) character.
unsigned char *
getLineFromString(const unsigned char *start, const unsigned char **end,
const unsigned char **startNext) {
const unsigned char *ptr = start;
const unsigned char *lastPtr;
wchar_t ch;
// Search for the first newline.
for (;;) {
if (*ptr == '\0') {
*end = ptr;
*startNext = ptr;
return (unsigned char *) start;
}
lastPtr = ptr;
ch = getCharFromString(&ptr);
if (ch == '\0') {
// Bad string
*end = lastPtr;
*startNext = ptr;
return NULL;
}
if (ch == '\n') {
*end = lastPtr;
if (*ptr == '\0'){
// LF at the end of the string.
*startNext = ptr;
return (unsigned char *) start;
}
ch = getCharFromString(&ptr);
if (ch == '\0') {
// Bad string
return NULL;
}
if (ch == '\r') {
// LFCR
*startNext = ptr;
} else {
// LF
*startNext = *end;
}
return (unsigned char *) start;
} else if (ch == '\r') {
*end = lastPtr;
*startNext = ptr;
return (unsigned char *) start;
} // else: a normal character
}
}
size_t
utf8StringCount(const unsigned char *start) {
size_t count = 0;
wchar_t ch;
for (;;) {
ch = getCharFromString(&start);
if (ch == '\0')
return count;
count++;
}
}
size_t
utf8StringCountN(const unsigned char *start, const unsigned char *end) {
size_t count = 0;
wchar_t ch;
for (;;) {
ch = getCharFromStringN(&start, end);
if (ch == '\0')
return count;
count++;
}
}
unsigned char *
skipUTF8Chars(const unsigned char *ptr, size_t num) {
wchar_t ch;
const unsigned char *oldPtr;
while (num--) {
oldPtr = ptr;
ch = getCharFromString(&ptr);
if (ch == '\0')
return (unsigned char *) oldPtr;
}
return (unsigned char *) ptr;
}
+8
View File
@@ -51,6 +51,14 @@ extern BOOLEAN GetStringContents (STRING String, STRINGPTR StringBuf,
BOOLEAN AppendSpace); BOOLEAN AppendSpace);
wchar_t getCharFromString(const unsigned char **ptr); wchar_t getCharFromString(const unsigned char **ptr);
wchar_t getCharFromStringN(const unsigned char **ptr,
const unsigned char *end);
unsigned char *getLineFromString(const unsigned char *start,
const unsigned char **end, const unsigned char **startNext);
size_t utf8StringCount(const unsigned char *start);
size_t utf8StringCountN(const unsigned char *start,
const unsigned char *end);
unsigned char *skipUTF8Chars(const unsigned char *ptr, size_t num);
#endif /* _STRLIB_H */ #endif /* _STRLIB_H */