1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
#include "emojis.hpp"
#include <sstream>
#include <utility>
#include <gdkmm/pixbufloader.h>
EmojiResource::EmojiResource(std::string filepath)
: m_filepath(std::move(filepath)) {}
EmojiResource::~EmojiResource() {
sqlite3_finalize(m_get_emoji_stmt);
sqlite3_close(m_db);
}
bool EmojiResource::Load() {
if (sqlite3_open(m_filepath.c_str(), &m_db) != SQLITE_OK) return false;
if (sqlite3_prepare_v2(m_db, "SELECT data FROM emoji_data WHERE emoji = ?", -1, &m_get_emoji_stmt, nullptr) != SQLITE_OK) return false;
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(m_db, "SELECT * FROM emoji_shortcodes", -1, &stmt, nullptr) != SQLITE_OK) return false;
while (sqlite3_step(stmt) == SQLITE_ROW) {
std::string shortcode = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
std::string emoji = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
m_shortcode_index[shortcode] = emoji;
m_pattern_shortcode_index[emoji].push_back(shortcode);
}
sqlite3_finalize(stmt);
std::sort(m_patterns.begin(), m_patterns.end(), [](const Glib::ustring &a, const Glib::ustring &b) {
return a.size() > b.size();
});
return true;
}
Glib::RefPtr<Gdk::Pixbuf> EmojiResource::GetPixBuf(const Glib::ustring &pattern) {
if (sqlite3_reset(m_get_emoji_stmt) != SQLITE_OK) return {};
if (sqlite3_bind_text(m_get_emoji_stmt, 1, pattern.c_str(), -1, nullptr) != SQLITE_OK) return {};
if (sqlite3_step(m_get_emoji_stmt) != SQLITE_ROW) return {};
if (const void *blob = sqlite3_column_blob(m_get_emoji_stmt, 0)) {
const int bytes = sqlite3_column_bytes(m_get_emoji_stmt, 0);
auto loader = Gdk::PixbufLoader::create();
loader->write(static_cast<const guint8 *>(blob), bytes);
loader->close();
return loader->get_pixbuf();
}
return {};
}
void EmojiResource::ReplaceEmojis(Glib::RefPtr<Gtk::TextBuffer> buf, int size) {
auto get_text = [&]() -> auto {
Gtk::TextBuffer::iterator a, b;
buf->get_bounds(a, b);
return buf->get_slice(a, b, true);
};
auto text = get_text();
int searchpos;
for (const auto &pattern : m_patterns) {
searchpos = 0;
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
while (true) {
size_t r = text.find(pattern, searchpos);
if (r == Glib::ustring::npos) break;
if (!pixbuf) {
pixbuf = GetPixBuf(pattern);
if (pixbuf)
pixbuf = pixbuf->scale_simple(size, size, Gdk::INTERP_BILINEAR);
else
break;
}
searchpos = static_cast<int>(r + pattern.size());
const auto start_it = buf->get_iter_at_offset(static_cast<int>(r));
const auto end_it = buf->get_iter_at_offset(static_cast<int>(r + pattern.size()));
auto it = buf->erase(start_it, end_it);
buf->insert_pixbuf(it, pixbuf);
int alen = static_cast<int>(text.size());
text = get_text();
int blen = static_cast<int>(text.size());
searchpos -= (alen - blen);
}
}
}
std::string EmojiResource::GetShortCodeForPattern(const Glib::ustring &pattern) {
auto it = m_pattern_shortcode_index.find(pattern);
if (it != m_pattern_shortcode_index.end())
return it->second.front();
return "";
}
const std::map<std::string, std::string> &EmojiResource::GetShortCodes() const {
return m_shortcode_index;
}
|