Arquivos
tdesktop/Telegram/SourceFiles/editor/scene/scene_emoji_document.cpp
T

133 linhas
3.4 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "editor/scene/scene_emoji_document.h"
#include "ui/emoji_config.h"
#include "ui/painter.h"
#include <QTextBlock>
#include <QTextCursor>
namespace Editor {
EmojiDocument::EmojiDocument(QObject *parent)
: QTextDocument(parent) {
}
QVariant EmojiDocument::loadResource(int type, const QUrl &name) {
if (type != QTextDocument::ImageResource
|| name.scheme() != u"emoji"_q) {
return QTextDocument::loadResource(type, name);
}
const auto i = _cache.find(name);
if (i != _cache.end()) {
return i->second;
}
auto result = QVariant();
if (const auto emoji = Ui::Emoji::FromUrl(name.toDisplayString())) {
const auto factor = style::DevicePixelRatio();
const auto logical = QFontMetrics(defaultFont()).height();
const auto source = Ui::Emoji::GetSizeLarge();
auto image = QImage(
QSize(logical, logical) * factor,
QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(factor);
image.fill(Qt::transparent);
{
auto p = QPainter(&image);
auto hq = PainterHighQualityEnabler(p);
const auto sourceLogical = source / float64(factor);
const auto scale = logical / sourceLogical;
p.scale(scale, scale);
Ui::Emoji::Draw(p, emoji, source, 0, 0);
}
result = QVariant(QPixmap::fromImage(std::move(image)));
}
_cache.emplace(name, result);
return result;
}
void ReplaceEmoji(QTextDocument *doc) {
QSignalBlocker blocker(doc);
const auto fontHeight = QFontMetrics(doc->defaultFont()).height();
auto cursor = QTextCursor(doc);
auto block = doc->begin();
while (block.isValid()) {
auto text = block.text();
auto start = text.constData();
auto end = start + text.size();
auto ch = start;
while (ch < end) {
auto emojiLength = 0;
const auto emoji = Ui::Emoji::Find(ch, end, &emojiLength);
if (!emoji || emojiLength <= 0) {
++ch;
continue;
}
const auto pos = block.position() + int(ch - start);
cursor.setPosition(pos);
cursor.setPosition(
pos + emojiLength,
QTextCursor::KeepAnchor);
auto format = QTextImageFormat();
format.setName(emoji->toUrl());
format.setWidth(fontHeight);
format.setHeight(fontHeight);
format.setVerticalAlignment(
QTextCharFormat::AlignBaseline);
cursor.insertImage(format);
block = doc->findBlock(pos);
text = block.text();
start = text.constData();
end = start + text.size();
ch = start + (pos - block.position()) + 1;
continue;
}
block = block.next();
}
}
QString RecoverTextFromDocument(QTextDocument *doc) {
auto result = QString();
auto block = doc->begin();
while (block.isValid()) {
if (block != doc->begin()) {
result += '\n';
}
auto it = block.begin();
while (!it.atEnd()) {
const auto fragment = it.fragment();
if (!fragment.isValid()) {
++it;
continue;
}
const auto text = fragment.text();
const auto format = fragment.charFormat();
for (const auto &ch : text) {
if (ch == QChar::ObjectReplacementCharacter) {
if (format.isImageFormat()) {
const auto name = format.toImageFormat().name();
if (const auto emoji = Ui::Emoji::FromUrl(name)) {
result += emoji->text();
continue;
}
}
}
result += ch;
}
++it;
}
block = block.next();
}
return result;
}
} // namespace Editor