aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-11-05 23:59:18 +0100
committerdec05eba <dec05eba@protonmail.com>2022-11-05 23:59:18 +0100
commitf7246d83d2f43e0088e2a01ff6305ac7e25f21fe (patch)
tree293bb9545f85374885c478a04089c6c983b6194a
parent5836c731bd57a6d892f77d7d0c52e6bf74bde0a1 (diff)
Fix possible crash on backspace in edit text with invalid utf8
-rw-r--r--TODO3
-rw-r--r--images/troonjak.pngbin11574 -> 0 bytes
-rw-r--r--src/Text.cpp44
3 files changed, 31 insertions, 16 deletions
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
--- a/images/troonjak.png
+++ /dev/null
Binary files 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<TextElement> 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;