mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-14 16:07:39 +00:00
SCI: text16 GetLongest() changes fixes bug #5334
also fixes bug #5159 also fixes Japanese line wrapping (hopefully)
This commit is contained in:
parent
c4e40fc83f
commit
c9e74d6d54
@ -143,7 +143,8 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1
|
||||
return textCodeSize;
|
||||
}
|
||||
|
||||
static const uint16 text16_punctuationSjis[] = {
|
||||
// Has actually punctuation and characters in it, that may not be the first in a line
|
||||
static const uint16 text16_shiftJIS_punctuation[] = {
|
||||
0x9F82, 0xA182, 0xA382, 0xA582, 0xA782, 0xC182, 0xA782, 0xC182, 0xE182, 0xE382, 0xE582, 0xEC82,
|
||||
0x4083, 0x4283, 0x4483, 0x4683, 0x4883, 0x6283, 0x8383, 0x8583, 0x8783, 0x8E83, 0x9583, 0x9683,
|
||||
0x5B81, 0x4181, 0x4281, 0x7681, 0x7881, 0x4981, 0x4881, 0
|
||||
@ -151,10 +152,21 @@ static const uint16 text16_punctuationSjis[] = {
|
||||
|
||||
// return max # of chars to fit maxwidth with full words, does not include
|
||||
// breaking space
|
||||
int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId) {
|
||||
// Also adjusts text pointer to the new position for the caller
|
||||
//
|
||||
// Special cases in games:
|
||||
// Laura Bow 2 - Credits in the game menu - all the text lines start with spaces (bug #5159)
|
||||
// Act 6 Coroner questionaire - the text of all control buttons has trailing spaces
|
||||
// "Detective Ryan Hanrahan O'Riley" contains even more spaces (bug #5334)
|
||||
// Conquests of Camelot - talking with Cobb - one text box of the dialogue contains a longer word,
|
||||
// that will be broken into 2 lines (bug #5159)
|
||||
int16 GfxText16::GetLongest(const char *&textPtr, int16 maxWidth, GuiResourceId orgFontId) {
|
||||
uint16 curChar = 0;
|
||||
int16 maxChars = 0, curCharCount = 0;
|
||||
uint16 width = 0;
|
||||
const char *textStartPtr = textPtr;
|
||||
const char *lastSpacePtr = NULL;
|
||||
int16 lastSpaceCharCount = 0;
|
||||
int16 curCharCount = 0, resultCharCount = 0;
|
||||
uint16 curWidth = 0, tempWidth = 0;
|
||||
GuiResourceId previousFontId = GetFontId();
|
||||
int16 previousPenColor = _ports->_curPort->penClr;
|
||||
|
||||
@ -162,35 +174,34 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
|
||||
if (!_font)
|
||||
return 0;
|
||||
|
||||
while (width <= maxWidth) {
|
||||
curChar = (*(const byte *)text++);
|
||||
while (1) {
|
||||
curChar = (*(const byte *)textPtr);
|
||||
if (_font->isDoubleByte(curChar)) {
|
||||
curChar |= (*(const byte *)text++) << 8;
|
||||
curCharCount++;
|
||||
curChar |= (*(const byte *)textPtr + 1) << 8;
|
||||
}
|
||||
switch (curChar) {
|
||||
case 0x7C:
|
||||
if (getSciVersion() >= SCI_VERSION_1_1) {
|
||||
curCharCount++;
|
||||
curCharCount += CodeProcessing(text, orgFontId, previousPenColor, false);
|
||||
curCharCount++; textPtr++;
|
||||
curCharCount += CodeProcessing(textPtr, orgFontId, previousPenColor, false);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
// We need to add 0xD, 0xA and 0xD 0xA to curCharCount and then exit
|
||||
// which means, we split text like
|
||||
// 'Mature, experienced software analyst available.' 0xD 0xA
|
||||
// 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2)
|
||||
// and 0xA '-------' 0xA (which is the official sierra subtitle separator)
|
||||
// which means, we split text like for example
|
||||
// - 'Mature, experienced software analyst available.' 0xD 0xA
|
||||
// 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2)
|
||||
// - 0xA '-------' 0xA (which is the official sierra subtitle separator) (found in multilingual versions)
|
||||
// Sierra did it the same way.
|
||||
case 0xD:
|
||||
// Check, if 0xA is following, if so include it as well
|
||||
if ((*(const unsigned char *)text) == 0xA)
|
||||
curCharCount++;
|
||||
if ((*(const byte *)textPtr + 1) == 0xA)
|
||||
curCharCount++; textPtr++;
|
||||
// it's meant to pass through here
|
||||
case 0xA:
|
||||
case 0x9781: // this one is used by SQ4/japanese as line break as well
|
||||
curCharCount++;
|
||||
curCharCount++; textPtr++;
|
||||
// and it's also meant to pass through here
|
||||
case 0:
|
||||
SetFont(previousFontId);
|
||||
@ -198,55 +209,90 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
|
||||
return curCharCount;
|
||||
|
||||
case ' ':
|
||||
maxChars = curCharCount; // return count up to (but not including) breaking space
|
||||
lastSpaceCharCount = curCharCount; // return count up to (but not including) breaking space
|
||||
lastSpacePtr = textPtr + 1; // remember position right after the current space
|
||||
break;
|
||||
}
|
||||
// Sometimes this can go off the screen, like for example bug #3040161.
|
||||
// However, we only perform this for non-Japanese games, as these require
|
||||
// special handling, done after this loop.
|
||||
if (width + _font->getCharWidth(curChar) > maxWidth && g_sci->getLanguage() != Common::JA_JPN)
|
||||
tempWidth += _font->getCharWidth(curChar);
|
||||
|
||||
// Width is too large? -> break out
|
||||
if (tempWidth > maxWidth)
|
||||
break;
|
||||
width += _font->getCharWidth(curChar);
|
||||
curCharCount++;
|
||||
|
||||
// still fits, remember width
|
||||
curWidth = tempWidth;
|
||||
|
||||
// go to next character
|
||||
curCharCount++; textPtr++;
|
||||
if (curChar > 0xFF) {
|
||||
// Double-Byte
|
||||
curCharCount++; textPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
// Text without spaces, probably Kanji/Japanese
|
||||
if (maxChars == 0) {
|
||||
maxChars = curCharCount;
|
||||
if (lastSpaceCharCount) {
|
||||
// Break and at least one space was found before that
|
||||
resultCharCount = lastSpaceCharCount;
|
||||
|
||||
// additionally skip over all spaces, that are following that space, but don't count them for displaying purposes
|
||||
textPtr = lastSpacePtr;
|
||||
while (*textPtr == ' ')
|
||||
textPtr++;
|
||||
|
||||
} else {
|
||||
// Break without spaces found, we split the very first word - may also be Kanji/Japanese
|
||||
if (curChar > 0xFF) {
|
||||
// current charracter is Japanese
|
||||
|
||||
// PC-9801 SCI actually added the last character, which shouldn't fit anymore, still onto the
|
||||
// screen in case maxWidth wasn't fully reached with the last character
|
||||
if (maxWidth == curWidth) {
|
||||
curCharCount -= 2; textPtr -= 2;
|
||||
if (textPtr < textStartPtr)
|
||||
error("Seeking back went too far, data corruption?");
|
||||
|
||||
uint16 nextChar;
|
||||
|
||||
// We remove the last char only, if maxWidth was actually equal width
|
||||
// before adding the last char. Otherwise we won't get the same cutting
|
||||
// as in sierra pc98 sci.
|
||||
if (maxWidth == (width - _font->getCharWidth(curChar))) {
|
||||
maxChars--;
|
||||
if (curChar > 0xFF)
|
||||
maxChars--;
|
||||
nextChar = curChar;
|
||||
} else {
|
||||
nextChar = (*(const byte *)text++);
|
||||
if (_font->isDoubleByte(nextChar))
|
||||
nextChar |= (*(const byte *)text++) << 8;
|
||||
}
|
||||
// sierra checked the following character against a punctuation kanji table
|
||||
if (nextChar > 0xFF) {
|
||||
// if the character is punctuation, we go back one character
|
||||
uint nonBreakingNr = 0;
|
||||
while (text16_punctuationSjis[nonBreakingNr]) {
|
||||
if (text16_punctuationSjis[nonBreakingNr] == nextChar) {
|
||||
maxChars--;
|
||||
if (curChar > 0xFF)
|
||||
maxChars--; // go back 2 chars, when last char was double byte
|
||||
curChar = (*(const byte *)textPtr);
|
||||
if (!_font->isDoubleByte(curChar))
|
||||
error("Non double byte while seeking back");
|
||||
curChar |= (*(const byte *)textPtr + 1) << 8;
|
||||
}
|
||||
|
||||
// But it also checked, if the current character is not inside a punctuation table and it even
|
||||
// went backwards in case it found multiple ones inside that table.
|
||||
uint nonBreakingPos = 0;
|
||||
|
||||
while (1) {
|
||||
// Look up if character shouldn't be the first on a new line
|
||||
nonBreakingPos = 0;
|
||||
while (text16_shiftJIS_punctuation[nonBreakingPos]) {
|
||||
if (text16_shiftJIS_punctuation[nonBreakingPos] == curChar)
|
||||
break;
|
||||
nonBreakingPos++;
|
||||
}
|
||||
if (!text16_shiftJIS_punctuation[nonBreakingPos]) {
|
||||
// character is fine
|
||||
break;
|
||||
}
|
||||
nonBreakingNr++;
|
||||
// Character is not acceptable, seek backward in the text
|
||||
curCharCount -= 2; textPtr -= 2;
|
||||
if (textPtr < textStartPtr)
|
||||
error("Seeking back went too far, data corruption?");
|
||||
|
||||
curChar = (*(const byte *)textPtr);
|
||||
if (!_font->isDoubleByte(curChar))
|
||||
error("Non double byte while seeking back");
|
||||
curChar |= (*(const byte *)textPtr + 1) << 8;
|
||||
}
|
||||
// include the current character
|
||||
curCharCount += 2; textPtr += 2;
|
||||
}
|
||||
|
||||
// We split the word in that case
|
||||
resultCharCount = curCharCount;
|
||||
}
|
||||
SetFont(previousFontId);
|
||||
_ports->penColor(previousPenColor);
|
||||
return maxChars;
|
||||
return resultCharCount;
|
||||
}
|
||||
|
||||
void GfxText16::Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont) {
|
||||
@ -328,15 +374,16 @@ int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId
|
||||
// rect.right=found widest line with RTextWidth and GetLongest
|
||||
// rect.bottom=num. lines * GetPointSize
|
||||
rect.right = (maxWidth ? maxWidth : 192);
|
||||
const char *curPos = text;
|
||||
while (*curPos) {
|
||||
charCount = GetLongest(curPos, rect.right, fontId);
|
||||
const char *curTextPos = text; // in work position for GetLongest()
|
||||
const char *curTextLine = text; // starting point of current line
|
||||
while (*curTextPos) {
|
||||
charCount = GetLongest(curTextPos, rect.right, fontId);
|
||||
if (charCount == 0)
|
||||
break;
|
||||
Width(curPos, 0, charCount, fontId, textWidth, textHeight, false);
|
||||
Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, false);
|
||||
maxTextWidth = MAX(textWidth, maxTextWidth);
|
||||
totalHeight += textHeight;
|
||||
curPos += charCount;
|
||||
curTextLine = curTextPos;
|
||||
}
|
||||
rect.bottom = totalHeight;
|
||||
rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth);
|
||||
@ -410,6 +457,8 @@ void GfxText16::Box(const char *text, bool show, const Common::Rect &rect, TextA
|
||||
GuiResourceId previousFontId = GetFontId();
|
||||
int16 previousPenColor = _ports->_curPort->penClr;
|
||||
bool doubleByteMode = false;
|
||||
const char *curTextPos = text;
|
||||
const char *curTextLine = text;
|
||||
|
||||
if (fontId != -1)
|
||||
SetFont(fontId);
|
||||
@ -426,11 +475,11 @@ void GfxText16::Box(const char *text, bool show, const Common::Rect &rect, TextA
|
||||
_codeRefTempRect.left = _codeRefTempRect.top = -1;
|
||||
|
||||
maxTextWidth = 0;
|
||||
while (*text) {
|
||||
charCount = GetLongest(text, rect.width(), fontId);
|
||||
while (*curTextPos) {
|
||||
charCount = GetLongest(curTextPos, rect.width(), fontId);
|
||||
if (charCount == 0)
|
||||
break;
|
||||
Width(text, 0, charCount, fontId, textWidth, textHeight, true);
|
||||
Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, true);
|
||||
maxTextWidth = MAX<int16>(maxTextWidth, textWidth);
|
||||
switch (alignment) {
|
||||
case SCI_TEXT16_ALIGNMENT_RIGHT:
|
||||
@ -449,13 +498,13 @@ void GfxText16::Box(const char *text, bool show, const Common::Rect &rect, TextA
|
||||
_ports->moveTo(rect.left + offset, rect.top + hline);
|
||||
|
||||
if (show) {
|
||||
Show(text, 0, charCount, fontId, previousPenColor);
|
||||
Show(curTextLine, 0, charCount, fontId, previousPenColor);
|
||||
} else {
|
||||
Draw(text, 0, charCount, fontId, previousPenColor);
|
||||
Draw(curTextLine, 0, charCount, fontId, previousPenColor);
|
||||
}
|
||||
|
||||
hline += textHeight;
|
||||
text += charCount;
|
||||
curTextLine = curTextPos;
|
||||
}
|
||||
SetFont(previousFontId);
|
||||
_ports->penColor(previousPenColor);
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
|
||||
void ClearChar(int16 chr);
|
||||
|
||||
int16 GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId);
|
||||
int16 GetLongest(const char *&text, int16 maxWidth, GuiResourceId orgFontId);
|
||||
void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont);
|
||||
void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight);
|
||||
void ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor);
|
||||
|
Loading…
x
Reference in New Issue
Block a user