aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;