From f7246d83d2f43e0088e2a01ff6305ac7e25f21fe Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 5 Nov 2022 23:59:18 +0100 Subject: Fix possible crash on backspace in edit text with invalid utf8 --- TODO | 3 ++- images/troonjak.png | Bin 11574 -> 0 bytes src/Text.cpp | 44 +++++++++++++++++++++++++++++--------------- 3 files changed, 31 insertions(+), 16 deletions(-) delete mode 100644 images/troonjak.png diff --git a/TODO b/TODO index 0a000a5..18d7630 100644 --- a/TODO +++ b/TODO @@ -243,4 +243,5 @@ The formatting of replying to a message with an image in matrix is a bit weird. Add ctrl+h to go back to the front page. Async load textures (not just images). This can be done efficiently by using different opengl contexts in different threads and making the context current right before a heavy opengl operation. All threads need to set their opengl context often. Downloading files should take into account the remove mime type if available. Fallback to file extension. -Text images atlas. \ No newline at end of file +Text images atlas. +Do not render invalid unicode. \ No newline at end of file diff --git a/images/troonjak.png b/images/troonjak.png deleted file mode 100644 index 75c33f5..0000000 Binary files a/images/troonjak.png and /dev/null differ diff --git a/src/Text.cpp b/src/Text.cpp index 192061f..0b6347d 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -510,21 +510,11 @@ namespace QuickMedia if(emoji_codepoint_combined == "1f441-fe0f-200d-1f5e8-fe0f") emoji_codepoint_combined = "1f441-200d-1f5e8"; - std::string image_url; - bool image_local = false; - if(emoji_codepoint_combined != "1f3f3-fe0f-200d-26a7-fe0f") { - image_url = "/usr/share/quickmedia/emoji/" + emoji_codepoint_combined + ".png"; - image_local = true; - } else { - image_url = "/usr/share/quickmedia/images/troonjak.png"; - image_local = true; - } - text_element.create_text("E"); text_element.text_type = TextElement::TextType::EMOJI; text_element.text = "E"; - text_element.url = std::move(image_url); - text_element.local = image_local; + text_element.url = "/usr/share/quickmedia/emoji/" + emoji_codepoint_combined + ".png"; + text_element.local = true; text_element.size = { (int)vspace, (int)vspace }; text_element.text_num_bytes = emoji_byte_length; text_elements.push_back(std::move(text_element)); @@ -602,6 +592,23 @@ namespace QuickMedia static mgl::vec2f vec2f_floor(mgl::vec2f value) { return mgl::vec2f((int)value.x, (int)value.y); } + + static size_t utf8_get_num_codepoints(const char *str, size_t size) { + size_t codepoint_index = 0; + for(size_t i = 0; i < size;) { + unsigned char *cp = (unsigned char*)&str[i]; + uint32_t codepoint; + size_t clen; + if(!mgl::utf8_decode(cp, size - i, &codepoint, &clen)) { + codepoint = *cp; + clen = 1; + } + + i += clen; + ++codepoint_index; + } + return codepoint_index; + } void Text::updateGeometry(bool update_even_if_not_dirty) { if(dirtyText) { @@ -1183,6 +1190,9 @@ namespace QuickMedia } else if(event.key.code == mgl::Keyboard::Backspace && caretIndex > 0) { + if(caretIndex < 0 || caretIndex > (int)vertices_linear.size()) + return; + const size_t str_index = get_string_index_from_caret_index(caretIndex); if(str_index > 0 && str_index <= str.size()) { const size_t codepoint_start = str_index - vertices_linear[caretIndex - 1].text_num_bytes; @@ -1195,6 +1205,9 @@ namespace QuickMedia } else if(event.key.code == mgl::Keyboard::Delete && !caretAtEnd) { + if(caretIndex < 0 || caretIndex >= (int)vertices_linear.size()) + return; + const size_t str_index = get_string_index_from_caret_index(caretIndex); const size_t codepoint_end = str_index + vertices_linear[caretIndex].text_num_bytes; if(str_index < str.size() && codepoint_end <= str.size()) { @@ -1266,10 +1279,11 @@ namespace QuickMedia std::vector new_text_elements; split_text_by_type(new_text_elements, stringToAdd); for(auto &text_element : new_text_elements) { - if(text_element.type == TextElement::Type::IMAGE || text_element.text_type == TextElement::TextType::EMOJI) + if(text_element.type == TextElement::Type::IMAGE || text_element.text_type == TextElement::TextType::EMOJI) { caretIndex += 1; - else - caretIndex += text_element.text_num_bytes; + } else { + caretIndex += utf8_get_num_codepoints(text_element.text.data(), text_element.text.size()); + } } dirty = true; dirtyText = true; -- cgit v1.2.3