[Scummvm-cvs-logs] scummvm master -> c9e74d6d54bf59b3587eea0785ce31df5d46615b

m-kiewitz m_kiewitz at users.sourceforge.net
Sat Nov 1 23:36:18 CET 2014


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
c9e74d6d54 SCI: text16 GetLongest() changes fixes bug #5334


Commit: c9e74d6d54bf59b3587eea0785ce31df5d46615b
    https://github.com/scummvm/scummvm/commit/c9e74d6d54bf59b3587eea0785ce31df5d46615b
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2014-11-01T23:36:29+01:00

Commit Message:
SCI: text16 GetLongest() changes fixes bug #5334
also fixes bug #5159
also fixes Japanese line wrapping (hopefully)

Changed paths:
    engines/sci/graphics/text16.cpp
    engines/sci/graphics/text16.h



diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp
index 808ce45..66cff42 100644
--- a/engines/sci/graphics/text16.cpp
+++ b/engines/sci/graphics/text16.cpp
@@ -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++;
-	}
 
-	// Text without spaces, probably Kanji/Japanese
-	if (maxChars == 0) {
-		maxChars = curCharCount;
+		// still fits, remember width
+		curWidth = tempWidth;
 
-		uint16 nextChar;
+		// go to next character
+		curCharCount++; textPtr++;
+		if (curChar > 0xFF) {
+			// Double-Byte
+			curCharCount++; textPtr++;
+		 }
+	}
 
-		// 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
+	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?");
+
+				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);
diff --git a/engines/sci/graphics/text16.h b/engines/sci/graphics/text16.h
index ab0cb13..715891b 100644
--- a/engines/sci/graphics/text16.h
+++ b/engines/sci/graphics/text16.h
@@ -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);






More information about the Scummvm-git-logs mailing list