Merge pull request #1487 from pestoffne/fix/editor-input-utf8

Fixed input of long UTF-8 symbols in editor (#1423)
fix-squashed-planets
Mateusz Przybył 2022-02-25 17:09:27 +01:00 committed by GitHub
commit 6aebf60300
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 18 deletions

View File

@ -156,11 +156,17 @@ std::wstring StrUtils::Utf8StringToUnicode(const std::string &str)
{
std::wstring result;
unsigned int pos = 0;
int len;
while (pos < str.size())
{
int len = StrUtils::Utf8CharSizeAt(str, pos);
if (len == 0)
try
{
len = StrUtils::Utf8CharSizeAt(str, pos);
}
catch (std::out_of_range &e)
{
break;
}
std::string ch = str.substr(pos, len);
result += static_cast<wchar_t>(StrUtils::Utf8CharToUnicode(ch));
@ -172,21 +178,24 @@ std::wstring StrUtils::Utf8StringToUnicode(const std::string &str)
int StrUtils::Utf8CharSizeAt(const std::string &str, unsigned int pos)
{
if (pos >= str.size())
return 0;
throw std::out_of_range("Index is greater than size");
const char c = str[pos];
if((c & 0xF8) == 0xF0)
return 4;
if((c & 0xF0) == 0xE0)
return 3;
if((c & 0xE0) == 0xC0)
if((c & 0b1000'0000) == 0b0000'0000)
return 1;
if((c & 0b1110'0000) == 0b1100'0000)
return 2;
if((c & 0b1111'0000) == 0b1110'0000)
return 3;
if((c & 0b1111'1000) == 0b1111'0000)
return 4;
// Invalid char - unexpected continuation byte
if((c & 0xC0) == 0x80)
if (isUtf8ContinuationByte(c))
throw std::invalid_argument("Unexpected UTF-8 continuation byte");
return 1;
// (c & 0b1111'1000) == 0b1111'1000 is true here
throw std::invalid_argument("Byte value has no sense in UTF-8");
}
std::size_t StrUtils::Utf8StringLength(const std::string &str)
@ -201,3 +210,7 @@ std::size_t StrUtils::Utf8StringLength(const std::string &str)
return result;
}
bool StrUtils::isUtf8ContinuationByte(char c)
{
return (c & 0b1100'0000) == 0b1000'0000;
}

View File

@ -87,5 +87,8 @@ int Utf8CharSizeAt(const std::string &str, unsigned int pos);
//! Returns the length in characters of UTF-8 string \a str
std::size_t Utf8StringLength(const std::string &str);
//! Returns true if char is continuation UTF-8 byte
bool isUtf8ContinuationByte(char c);
} // namespace StrUtil

View File

@ -1112,7 +1112,14 @@ int CText::GetCharSizeAt(Gfx::FontType font, const std::string& text, unsigned i
}
else
{
len = StrUtils::Utf8CharSizeAt(text, index);
try
{
len = StrUtils::Utf8CharSizeAt(text, index);
}
catch (std::invalid_argument &e)
{
len = 1;
}
}
return len;
}

View File

@ -27,6 +27,7 @@
#include "common/logger.h"
#include "common/make_unique.h"
#include "common/stringutils.h"
#include "common/resources/inputstream.h"
#include "common/resources/outputstream.h"
@ -492,7 +493,10 @@ bool CEdit::EventProcess(const Event &event)
if ( event.type == EVENT_TEXT_INPUT && !bControl && m_bFocus )
{
auto data = event.GetData<TextInputData>();
Insert(data->text[0]); // TODO: insert utf-8 char
for ( char c : data->text )
{
Insert(c);
}
SendModifEvent();
return true;
}
@ -2258,7 +2262,7 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect)
{
int character;
if ( move == -1 ) // back?
if ( move == -1 ) // back
{
if ( bWord )
{
@ -2303,12 +2307,18 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect)
}
else
{
m_cursor1 --;
if ( m_cursor1 < 0 ) m_cursor1 = 0;
if ( m_cursor1 > 0 )
{
m_cursor1 --;
while ( m_cursor1 > 0 && StrUtils::isUtf8ContinuationByte(m_text[m_cursor1]) )
{
m_cursor1 --;
}
}
}
}
if ( move == 1 ) // advance?
if ( move == 1 ) // advance
{
if ( bWord )
{
@ -2353,8 +2363,14 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect)
}
else
{
m_cursor1 ++;
if ( m_cursor1 > m_len ) m_cursor1 = m_len;
if ( m_cursor1 < m_len )
{
m_cursor1 ++;
while ( m_cursor1 < m_len && StrUtils::isUtf8ContinuationByte(m_text[m_cursor1]) )
{
m_cursor1 ++;
}
}
}
}
@ -2784,6 +2800,11 @@ void CEdit::DeleteOne(int dir)
}
if ( m_cursor1 > m_cursor2 ) Math::Swap(m_cursor1, m_cursor2);
// Expands selection to delete integer number of UTF-8 symbols
while ( m_cursor1 > 0 && StrUtils::isUtf8ContinuationByte(m_text[m_cursor1]) ) m_cursor1 --;
while ( m_cursor2 < m_len && StrUtils::isUtf8ContinuationByte(m_text[m_cursor2]) ) m_cursor2 ++;
hole = m_cursor2-m_cursor1;
end = m_len-hole;
for ( i=m_cursor1 ; i<end ; i++ )