COMMON: Add String::forEachLine and convertBiDiStringByLines

`convertBiDiStringByLines` calls the BiDi algo for each line in isolation,
and returns a joined result.
That's needed to support BiDi in AGI, and might be needed for other engines
in the future.

In order to do that, a new utility function was added:
`String::forEachLine` which gets a function as input, and its arg(s) (if it has any),
and calls the function on each line, and returns a new string which is all
concatenation of all the lines results (with '\n' added between them).
This commit is contained in:
Zvika Haramaty 2021-03-02 13:41:16 +02:00 committed by Eugene Sandulenko
parent e094bef73b
commit dc5783c910
4 changed files with 63 additions and 2 deletions

View File

@ -410,6 +410,27 @@ String String::substr(size_t pos, size_t len) const {
return String(_str + pos, MIN((size_t)_size - pos, len));
}
String String::forEachLine(String(*func)(const String, va_list args), ...) const {
String result = "";
size_t index = findFirstOf('\n', 0);
size_t prev_index = 0;
va_list args;
va_start(args, func);
while (index != -1) {
String textLine = substr(prev_index, index - prev_index);
textLine = (*func)(textLine, args);
result = result + textLine + '\n';
prev_index = index + 1;
index = findFirstOf('\n', index + 1);
}
String textLine = substr(prev_index);
textLine = (*func)(textLine, args);
result = result + textLine;
va_end(args);
return result;
}
#pragma mark -
bool operator==(const char* y, const String &x) {

View File

@ -242,6 +242,9 @@ public:
/** Return a substring of this string */
String substr(size_t pos = 0, size_t len = npos) const;
/** Calls func on each line of the string, and returns a joined string */
String forEachLine(String(*func)(const String, va_list args), ...) const;
/** Python-like method **/
U32String decode(CodePage page = kUtf8) const;

View File

@ -38,6 +38,12 @@ UnicodeBiDiText::UnicodeBiDiText(const Common::String &str, const Common::CodePa
initWithU32String(str.decode(page));
}
UnicodeBiDiText::UnicodeBiDiText(const Common::String &str, const Common::CodePage page, uint *pbase_dir) : logical(str), _log_to_vis_index(NULL), _vis_to_log_index(NULL) {
_pbase_dir = *pbase_dir;
initWithU32String(str.decode(page));
*pbase_dir = _pbase_dir;
}
UnicodeBiDiText::~UnicodeBiDiText() {
delete[] _log_to_vis_index;
delete[] _vis_to_log_index;
@ -64,13 +70,12 @@ void UnicodeBiDiText::initWithU32String(const U32String &input) {
FriBidiChar *visual_str = new FriBidiChar[buff_length * sizeof(FriBidiChar)];
_log_to_vis_index = new uint32[input_size];
_vis_to_log_index = new uint32[input_size];
FriBidiParType pbase_dir = FRIBIDI_PAR_ON;
if (!fribidi_log2vis(
/* input */
(const FriBidiChar *)input.c_str(),
input_size,
&pbase_dir,
&_pbase_dir,
/* output */
visual_str,
(FriBidiStrIndex *)_log_to_vis_index, // position_L_to_V_list,
@ -99,6 +104,17 @@ void UnicodeBiDiText::initWithU32String(const U32String &input) {
}
Common::String bidiByLineHelper(Common::String line, va_list args) {
Common::CodePage page = va_arg(args, Common::CodePage);
uint32 *pbase_dir = va_arg(args, uint32*);
return UnicodeBiDiText(line, page, pbase_dir).visual.encode(page);
}
String convertBiDiStringByLines(const String &input, const Common::CodePage page) {
uint32 pbase_dir = SCUMMVM_FRIBIDI_PAR_ON;
return input.forEachLine(bidiByLineHelper, page, &pbase_dir);
}
String convertBiDiString(const String &input, const Common::Language lang) {
if (lang != Common::HE_ISR) //TODO: modify when we'll support other RTL languages, such as Arabic and Farsi
return input;

View File

@ -27,6 +27,21 @@
#include "common/ustr.h"
#include "common/language.h"
// SCUMMVM_FRIBIDI_PAR_ON: automatically check the text's direction
// SCUMMVM_FRIBIDI_PAR_LTR, SCUMMVM_FRIBIDI_PAR_RTL: enforce LTR or RTL direction
// if not USE_FRIBIDI, these defines values don't matter
#ifdef USE_FRIBIDI
#define SCUMMVM_FRIBIDI_PAR_ON FRIBIDI_PAR_ON
#define SCUMMVM_FRIBIDI_PAR_LTR FRIBIDI_PAR_LTR
#define SCUMMVM_FRIBIDI_PAR_RTL FRIBIDI_PAR_RTL
#else
#define SCUMMVM_FRIBIDI_PAR_ON 0
#define SCUMMVM_FRIBIDI_PAR_LTR 0
#define SCUMMVM_FRIBIDI_PAR_RTL 0
#endif
namespace Common {
class UnicodeBiDiText {
@ -34,12 +49,15 @@ private:
uint32 *_log_to_vis_index; // from fribidi conversion
uint32 *_vis_to_log_index; // from fribidi conversion
void initWithU32String(const Common::U32String &str);
Common::String bidiByLine(Common::String line, va_list args);
public:
const Common::U32String logical; // original string, ordered logically
Common::U32String visual; // from fribidi conversion, ordered visually
uint32 _pbase_dir;
UnicodeBiDiText(const Common::U32String &str);
UnicodeBiDiText(const Common::String &str, const Common::CodePage page);
UnicodeBiDiText(const Common::String &str, const Common::CodePage page, uint *pbase_dir);
~UnicodeBiDiText();
/**
@ -57,6 +75,9 @@ UnicodeBiDiText convertBiDiU32String(const U32String &input);
String convertBiDiString(const String &input, const Common::Language lang);
String convertBiDiString(const String &input, const Common::CodePage page);
// calls convertBiDiString for each line in isolation
String convertBiDiStringByLines(const String &input, const Common::CodePage page);
} // End of namespace Common
#endif