COMMON: add UnicodeBiDiText wrapper

This commit is contained in:
BLooperZ 2020-05-11 19:18:37 +03:00 committed by Eugene Sandulenko
parent 6a653312e2
commit ec83715b43
9 changed files with 148 additions and 104 deletions

View file

@ -30,7 +30,6 @@ MODULE_OBJS := \
rational.o \ rational.o \
rendermode.o \ rendermode.o \
str.o \ str.o \
str-bidi.o \
str-enc.o \ str-enc.o \
stream.o \ stream.o \
system.o \ system.o \
@ -38,6 +37,7 @@ MODULE_OBJS := \
tokenizer.o \ tokenizer.o \
translation.o \ translation.o \
unarj.o \ unarj.o \
unicode-bidi.o \
unzip.o \ unzip.o \
ustr.o \ ustr.o \
util.o \ util.o \

View file

@ -1,83 +0,0 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/str-bidi.h"
#include "common/textconsole.h"
#ifdef USE_FRIBIDI
#include <fribidi/fribidi.h>
#endif
namespace Common {
String convertBiDiString(const String &input, const Common::CodePage page) {
return convertBiDiU32String(input.decode(page)).encode(page);
}
U32String convertBiDiU32String(const U32String &input) {
#ifdef USE_FRIBIDI
int buff_length = (input.size() + 2) * 2; // it's more than enough, but it's better to be on the safe side
FriBidiChar *visual_str = (FriBidiChar *)malloc(buff_length * sizeof(FriBidiChar));
FriBidiCharType pbase_dir = FRIBIDI_TYPE_ON;
if (!fribidi_log2vis(
/* input */
(const FriBidiChar *)input.c_str(),
input.size(),
&pbase_dir,
/* output */
visual_str,
NULL, // position_L_to_V_list,
NULL, // position_V_to_L_list,
NULL // embedding_level_list
)) {
warning("convertBiDiU32String: calling fribidi_log2vis failed");
free(visual_str);
return input;
}
U32String result = U32String(visual_str, input.size());
free(visual_str);
return result;
#else
warning("convertBiDiU32String: Fribidi not available, using input string as fallback");
return input;
#endif
}
int getVisualPosition(const U32String &str, int pos) {
Common::U32String suffix(str.c_str() + pos + 1);
Common::U32String visual_str = Common::convertBiDiU32String(str);
Common::U32String visual_prefix(visual_str.c_str(), suffix.size());
Common::U32String visual_suffix = Common::convertBiDiU32String(suffix);
return visual_prefix == visual_suffix ? suffix.size() : pos;
}
int getVisualPosition(const String &str, const Common::CodePage page, int logicalPos) {
return getVisualPosition(str.decode(page), logicalPos);
}
} // End of namespace Common

View file

@ -33,7 +33,7 @@
#include "common/fs.h" #include "common/fs.h"
#include "common/system.h" #include "common/system.h"
#include "common/textconsole.h" #include "common/textconsole.h"
#include "common/str-bidi.h" #include "common/unicode-bidi.h"
#ifdef USE_TRANSLATION #ifdef USE_TRANSLATION

106
common/unicode-bidi.cpp Normal file
View file

@ -0,0 +1,106 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/ustr.h"
#include "common/unicode-bidi.h"
#include "common/textconsole.h"
#ifdef USE_FRIBIDI
#include <fribidi/fribidi.h>
#endif
namespace Common {
UnicodeBiDiText::UnicodeBiDiText(const Common::U32String &str) : logical(str), _log_to_vis_index(NULL), _vis_to_log_index(NULL) {
initWithU32String(str);
}
UnicodeBiDiText::UnicodeBiDiText(const Common::String &str, const Common::CodePage page) : logical(str), _log_to_vis_index(NULL), _vis_to_log_index(NULL) {
initWithU32String(str.decode(page));
}
UnicodeBiDiText::~UnicodeBiDiText() {
delete[] _log_to_vis_index;
delete[] _vis_to_log_index;
}
uint32 UnicodeBiDiText::getVisualPosition(uint32 logicalPos) const {
if (NULL != _log_to_vis_index && logicalPos < size()) {
return _log_to_vis_index[logicalPos];
}
return logicalPos;
}
uint32 UnicodeBiDiText::getLogicalPosition(uint32 visualPos) const {
if (NULL != _log_to_vis_index && visualPos < size()) {
return _vis_to_log_index[visualPos];
}
return visualPos;
}
void UnicodeBiDiText::initWithU32String(const U32String &input) {
#ifdef USE_FRIBIDI
uint32 input_size = input.size();
uint32 buff_length = (input_size + 2) * 2; // it's more than enough, but it's better to be on the safe side
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];
FriBidiCharType pbase_dir = FRIBIDI_TYPE_ON;
if (!fribidi_log2vis(
/* input */
(const FriBidiChar *)input.c_str(),
input_size,
&pbase_dir,
/* output */
visual_str,
(FriBidiStrIndex *)_log_to_vis_index, // position_L_to_V_list,
(FriBidiStrIndex *)_vis_to_log_index, // position_V_to_L_list,
NULL // embedding_level_list
)) {
warning("initWithU32String: calling fribidi_log2vis failed");
delete[] visual_str;
delete[] _log_to_vis_index;
delete[] _vis_to_log_index;
visual = input;
_log_to_vis_index = NULL;
_vis_to_log_index = NULL;
} else {
visual = U32String(visual_str, input.size());
delete[] visual_str;
}
#else
warning("initWithU32String: Fribidi not available, using input string as fallback");
visual = input;
#endif
}
String convertBiDiString(const String &input, const Common::CodePage page) {
return convertBiDiU32String(input.decode(page)).visual.encode(page);
}
UnicodeBiDiText convertBiDiU32String(const U32String &input) {
return UnicodeBiDiText(input);
}
} // End of namespace Common

View file

@ -25,20 +25,30 @@
#include "common/str.h" #include "common/str.h"
#include "common/ustr.h" #include "common/ustr.h"
#include "common/str-enc.h"
namespace Common { namespace Common {
/* class UnicodeBiDiText {
* Wrapper for GNU FriBidi implementation of the Unicode Bidirectional Algorithm private:
* For LTR (Left To Right) languages, returns the original input uint32 *_log_to_vis_index; // from fribidi conversion
* For RTL (Right To Left) languages, returns visual representation of a logical single-line input uint32 *_vis_to_log_index; // from fribidi conversion
*/ void initWithU32String(const Common::U32String &str);
U32String convertBiDiU32String(const U32String &input); public:
String convertBiDiString(const String &input, const Common::CodePage page); const Common::U32String logical; // original string, ordered logically
Common::U32String visual; // from fribidi conversion, ordered visually
int getVisualPosition(const U32String &str, int pos); UnicodeBiDiText(const Common::U32String &str);
int getVisualPosition(const String &str, const Common::CodePage page, int pos); UnicodeBiDiText(const Common::String &str, const Common::CodePage page);
~UnicodeBiDiText();
uint32 getVisualPosition(uint32 logicalPos) const;
uint32 getLogicalPosition(uint32 visualPos) const;
uint32 size() const { return logical.size(); }
};
/* just call the constructor for convenience */
UnicodeBiDiText convertBiDiU32String(const U32String &input);
String convertBiDiString(const String &input, const Common::CodePage page);
} // End of namespace Common } // End of namespace Common

View file

@ -23,6 +23,7 @@
#include "common/ustr.h" #include "common/ustr.h"
#include "common/memorypool.h" #include "common/memorypool.h"
#include "common/util.h" #include "common/util.h"
#include "unicode-bidi.h"
namespace Common { namespace Common {
@ -94,6 +95,10 @@ U32String::U32String(const String &str) : _size(0), _str(_storage) {
initWithCStr(str.c_str(), str.size()); initWithCStr(str.c_str(), str.size());
} }
U32String::U32String(const UnicodeBiDiText &txt) : _size(0), _str(_storage) {
initWithCStr(txt.visual.c_str(), txt.visual.size());
}
U32String::~U32String() { U32String::~U32String() {
decRefCount(_extern._refCount); decRefCount(_extern._refCount);
} }

View file

@ -29,6 +29,7 @@
namespace Common { namespace Common {
class String; class String;
class UnicodeBiDiText;
/** /**
* Very simple string class for UTF-32 strings in ScummVM. The main intention * Very simple string class for UTF-32 strings in ScummVM. The main intention
@ -103,6 +104,9 @@ public:
/** Construct a copy of the given string. */ /** Construct a copy of the given string. */
U32String(const U32String &str); U32String(const U32String &str);
/** Construct a copy of the given unicode BiDi converted string. */
U32String(const UnicodeBiDiText &txt);
/** Construct a new string from the given NULL-terminated C string. */ /** Construct a new string from the given NULL-terminated C string. */
explicit U32String(const char *str); explicit U32String(const char *str);

View file

@ -25,7 +25,7 @@
#include "common/keyboard.h" #include "common/keyboard.h"
#include "common/macresman.h" #include "common/macresman.h"
#include "common/winexe_pe.h" #include "common/winexe_pe.h"
#include "common/str-bidi.h" #include "common/unicode-bidi.h"
#include "graphics/primitives.h" #include "graphics/primitives.h"
#include "graphics/font.h" #include "graphics/font.h"
@ -744,12 +744,12 @@ static void drawFilledRoundRect(ManagedSurface *surface, Common::Rect &rect, int
drawRoundRect(rect, arc, color, true, drawPixelPlain, surface); drawRoundRect(rect, arc, color, true, drawPixelPlain, surface);
} }
static void underlineAccelerator(ManagedSurface *dst, const Font *font, const Common::U32String &str, int x, int y, int shortcutPos, uint32 color) { static void underlineAccelerator(ManagedSurface *dst, const Font *font, const Common::UnicodeBiDiText &txt, int x, int y, int shortcutPos, uint32 color) {
if (shortcutPos == -1) if (shortcutPos == -1)
return; return;
int visualPos = getVisualPosition(str, shortcutPos); int visualPos = txt.getVisualPosition(shortcutPos);
Common::U32String s = Common::convertBiDiU32String(str); Common::U32String s(txt.visual);
// Erase characters only if it is not end of the string // Erase characters only if it is not end of the string
if ((uint)(visualPos + 1) < s.size()) if ((uint)(visualPos + 1) < s.size())
@ -813,9 +813,10 @@ bool MacMenu::draw(ManagedSurface *g, bool forceRedraw) {
if (it->unicode) { if (it->unicode) {
int accOff = _align == kTextAlignRight ? it->bbox.width() - _font->getStringWidth(it->unicodeText) : 0; int accOff = _align == kTextAlignRight ? it->bbox.width() - _font->getStringWidth(it->unicodeText) : 0;
Common::UnicodeBiDiText utxt(it->unicodeText);
_font->drawString(&_screen, convertBiDiU32String(it->unicodeText), x, y, it->bbox.width(), color, _align); _font->drawString(&_screen, utxt.visual, x, y, it->bbox.width(), color, _align);
underlineAccelerator(&_screen, _font, it->unicodeText, x + accOff, y, it->shortcutPos, color); underlineAccelerator(&_screen, _font, utxt, x + accOff, y, it->shortcutPos, color);
} else { } else {
const Font *font = getMenuFont(it->style); const Font *font = getMenuFont(it->style);
@ -896,8 +897,9 @@ void MacMenu::renderSubmenu(MacMenuSubMenu *menu, bool recursive) {
} }
if (menu->items[i]->unicode) { if (menu->items[i]->unicode) {
_font->drawString(s, convertBiDiU32String(unicodeText), tx, ty, r->width(), color, _align); Common::UnicodeBiDiText utxt(unicodeText);
underlineAccelerator(s, _font, unicodeText, tx + accOff, ty, shortcutPos, color); _font->drawString(s, utxt.visual, tx, ty, r->width(), color, _align);
underlineAccelerator(s, _font, utxt, tx + accOff, ty, shortcutPos, color);
} else { } else {
const Font *font = getMenuFont(menu->items[i]->style); const Font *font = getMenuFont(menu->items[i]->style);

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#include "common/str-bidi.h" #include "common/unicode-bidi.h"
#include "graphics/macgui/macfontmanager.h" #include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/mactext.h" #include "graphics/macgui/mactext.h"