From b36cb661292aef6dd246b267a48cc4dca1cef26f Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 31 Jan 2019 20:43:40 +0300 Subject: [PATCH] overlays: Allow use of extended ascii8 - Use custom string conversion to ensure overlay deals with extended ascii whenever possible - Improves language compatibility greatly and avoids empty spaces for unknown glyphs --- rpcs3/Emu/RSX/Overlays/overlay_controls.h | 10 +-- rpcs3/Emu/RSX/Overlays/overlay_osk.cpp | 6 +- rpcs3/Emu/RSX/Overlays/overlays.cpp | 78 +++++++++++++---------- rpcs3/Emu/RSX/Overlays/overlays.h | 24 ++++--- 4 files changed, 64 insertions(+), 54 deletions(-) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index bb23f54e20..1b4f06b464 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -248,7 +248,7 @@ namespace rsx return{}; stbtt_aligned_quad quad; - stbtt_GetPackedQuad(pack_info.data(), width, height, c, &x_advance, &y_advance, &quad, true); + stbtt_GetPackedQuad(pack_info.data(), width, height, u8(c), &x_advance, &y_advance, &quad, true); return quad; } @@ -270,10 +270,11 @@ namespace rsx { if (char c = text[i++]; c && (i <= char_limit)) { - if ((u32)c >= char_count) + if (u8(c) >= char_count) { // Unsupported glyph, render null for now c = ' '; + c = ' '; } switch (c) @@ -1017,7 +1018,7 @@ namespace rsx last_word = text_width; } - if ((u32)c > renderer->char_count) + if (u8(c) > renderer->char_count) { // Non-existent glyph text_width += renderer->em_size; @@ -1041,7 +1042,6 @@ namespace rsx max_w = std::max(max_w, text_width); width = (u16)ceilf(max_w); } - }; struct animation_base @@ -1376,7 +1376,7 @@ namespace rsx { label() {} - label(const char *text) + label(const std::string& text) { this->text = text; } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp b/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp index 5744c4e4e7..12dfde19aa 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp @@ -123,7 +123,7 @@ namespace rsx else { m_preview.set_text(initial_text); - m_preview.caret_position = initial_text.length(); + m_preview.caret_position = ::narrow(initial_text.length()); m_preview.fore_color.a = 1.f; } @@ -406,7 +406,7 @@ namespace rsx void osk_dialog::on_text_changed() { - const auto ws = utf8_to_utf16(m_preview.text); + const auto ws = ascii8_to_utf16(m_preview.text); const auto length = (ws.length() + 1) * sizeof(char16_t); memcpy(osk_text, ws.c_str(), length); @@ -660,7 +660,7 @@ namespace rsx // Narrow to utf-8 as native does not have support for non-ascii glyphs // TODO: Full multibyte string support in all of rsx::overlays (kd-11) - initialize_layout(layout, utf16_to_utf8(message), utf16_to_utf8(init_text)); + initialize_layout(layout, utf16_to_ascii8(message), utf16_to_ascii8(init_text)); } } } diff --git a/rpcs3/Emu/RSX/Overlays/overlays.cpp b/rpcs3/Emu/RSX/Overlays/overlays.cpp index f913e6e77d..fb367d8a7d 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlays.cpp @@ -2,54 +2,66 @@ #include "overlays.h" #include "../GSRender.h" -#include -#include - -#if _MSC_VER >= 1900 -// Stupid MSVC bug when T is set to char16_t -std::string utf16_to_utf8(const std::u16string& utf16_string) +std::string utf8_to_ascii8(const std::string& utf8_string) { - // Strip extended codes - auto tmp = utf16_string; - for (auto &c : tmp) + std::vector out; + out.reserve(utf8_string.length() + 1); + + for (u32 index = 0; index < utf8_string.length(); ++index) { - if (c > 0xFF) c = '#'; + const auto code = (u8)utf8_string[index]; + if (code <= 0x7F) + { + out.push_back(code); + continue; + } + + auto extra_bytes = (code <= 0xDF) ? 1u : (code <= 0xEF) ? 2u : 3u; + index += extra_bytes; + + if (extra_bytes > 1 || (code & 0x1C)) + { + // Needs more bits than we could represent with extended ASCII anyway + out.push_back('#'); + continue; + } + + u8 out_code = ((code & 0x3) << 6) | (u8(utf8_string[index]) & 0x3F); + out.push_back(out_code); } - std::wstring_convert, int16_t> convert; - auto p = reinterpret_cast(tmp.data()); - return convert.to_bytes(p, p + utf16_string.size()); + out.push_back(0); + return { reinterpret_cast(out.data()) }; } -std::u16string utf8_to_utf16(const std::string& utf8_string) +std::string utf16_to_ascii8(const std::u16string& utf16_string) { - std::wstring_convert, int16_t> convert; - auto ws = convert.from_bytes(utf8_string); - return reinterpret_cast(ws.c_str()); -} + // Strip extended codes, map to '#' instead (placeholder) + std::vector out; + out.reserve(utf16_string.length() + 1); -#else - -std::string utf16_to_utf8(const std::u16string& utf16_string) -{ - // Strip extended codes - auto tmp = utf16_string; - for (auto &c : tmp) + for (const auto& code : utf16_string) { - if (c > 0xFF) c = '#'; + out.push_back(code > 0xFF ? '#': (u8)code); } - std::wstring_convert, char16_t> convert; - return convert.to_bytes(tmp); + out.push_back(0); + return { reinterpret_cast(out.data()) }; } -std::u16string utf8_to_utf16(const std::string& utf8_string) +std::u16string ascii8_to_utf16(const std::string& ascii_string) { - std::wstring_convert, char16_t> convert; - return convert.from_bytes(utf8_string); -} + std::vector out; + out.reserve(ascii_string.length() + 1); -#endif + for (const auto& code : ascii_string) + { + out.push_back(code > 0xFF ? '#' : (char16_t)code); + } + + out.push_back(0); + return { out.data() }; +} namespace rsx { diff --git a/rpcs3/Emu/RSX/Overlays/overlays.h b/rpcs3/Emu/RSX/Overlays/overlays.h index b4129aa96c..b527b3f4f9 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.h +++ b/rpcs3/Emu/RSX/Overlays/overlays.h @@ -17,8 +17,9 @@ #include "Utilities/Timer.h" // Utils -std::string utf16_to_utf8(const std::u16string& utf16_string); -std::u16string utf8_to_utf16(const std::string& utf8_string); +std::string utf8_to_ascii8(const std::string& utf8_string); +std::string utf16_to_ascii8(const std::u16string& utf16_string); +std::u16string ascii8_to_utf16(const std::string& utf8_string); extern u64 get_system_time(); // Definition of user interface implementations @@ -495,7 +496,7 @@ namespace rsx std::unique_ptr icon_data; public: - save_dialog_entry(const char* text1, const char* text2, u8 resource_id, const std::vector& icon_buf) + save_dialog_entry(const std::string& text1, const std::string& text2, u8 resource_id, const std::vector& icon_buf) { std::unique_ptr image = std::make_unique(); image->set_size(160, 110); @@ -519,16 +520,14 @@ namespace rsx std::unique_ptr text_stack = std::make_unique(); std::unique_ptr padding = std::make_unique(); - std::unique_ptr header_text = std::make_unique