Files
tdesktop/Telegram/lib_ui/ui/text/text_custom_emoji.cpp
allhaileris afb81b8278
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
init
2026-02-16 15:50:16 +03:00

236 lines
5.3 KiB
C++

// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include "ui/text/text_custom_emoji.h"
#include "ui/style/style_core.h"
#include "ui/text/text_utilities.h"
#include "ui/text/text.h"
#include "ui/emoji_config.h"
namespace Ui::Emoji {
int GetCustomSizeNormal() {
const auto full = GetSizeNormal();
const auto esize = full / style::DevicePixelRatio();
return Ui::Text::AdjustCustomEmojiSize(esize);
}
int GetCustomSizeLarge() {
const auto full = GetSizeLarge();
const auto esize = full / style::DevicePixelRatio();
return Ui::Text::AdjustCustomEmojiSize(esize);
}
int GetCustomSkipNormal() {
const auto full = GetSizeNormal();
const auto esize = full / style::DevicePixelRatio();
return (esize - GetCustomSizeNormal()) / 2;
}
int GetCustomSkipLarge() {
const auto full = GetSizeLarge();
const auto esize = full / style::DevicePixelRatio();
return (esize - GetCustomSizeLarge()) / 2;
}
} // namespace Ui::Emoji
namespace Ui::Text {
int AdjustCustomEmojiSize(int emojiSize) {
return base::SafeRound(emojiSize * 1.12);
}
ShiftedEmoji::ShiftedEmoji(
std::unique_ptr<Ui::Text::CustomEmoji> wrapped,
QPoint shift)
: _wrapped(std::move(wrapped))
, _shift(shift) {
}
int ShiftedEmoji::width() {
return _wrapped->width();
}
QString ShiftedEmoji::entityData() {
return _wrapped->entityData();
}
void ShiftedEmoji::paint(QPainter &p, const Context &context) {
auto copy = context;
copy.position += _shift;
_wrapped->paint(p, copy);
}
void ShiftedEmoji::unload() {
_wrapped->unload();
}
bool ShiftedEmoji::ready() {
return _wrapped->ready();
}
bool ShiftedEmoji::readyInDefaultState() {
return _wrapped->readyInDefaultState();
}
FirstFrameEmoji::FirstFrameEmoji(std::unique_ptr<CustomEmoji> wrapped)
: _wrapped(std::move(wrapped)) {
}
int FirstFrameEmoji::width() {
return _wrapped->width();
}
QString FirstFrameEmoji::entityData() {
return _wrapped->entityData();
}
void FirstFrameEmoji::paint(QPainter &p, const Context &context) {
const auto was = context.internal.forceFirstFrame;
context.internal.forceFirstFrame = true;
_wrapped->paint(p, context);
context.internal.forceFirstFrame = was;
}
void FirstFrameEmoji::unload() {
_wrapped->unload();
}
bool FirstFrameEmoji::ready() {
return _wrapped->ready();
}
bool FirstFrameEmoji::readyInDefaultState() {
return _wrapped->readyInDefaultState();
}
LimitedLoopsEmoji::LimitedLoopsEmoji(
std::unique_ptr<CustomEmoji> wrapped,
int limit,
bool stopOnLast)
: _wrapped(std::move(wrapped))
, _limit(limit)
, _stopOnLast(stopOnLast) {
}
int LimitedLoopsEmoji::width() {
return _wrapped->width();
}
QString LimitedLoopsEmoji::entityData() {
return _wrapped->entityData();
}
void LimitedLoopsEmoji::paint(QPainter &p, const Context &context) {
if (_played < _limit) {
if (_wrapped->readyInDefaultState()) {
if (_inLoop) {
_inLoop = false;
++_played;
}
} else if (_wrapped->ready()) {
_inLoop = true;
}
}
if (_played == _limit) {
const auto wasFirst = context.internal.forceFirstFrame;
const auto wasLast = context.internal.forceLastFrame;
(_stopOnLast
? context.internal.forceLastFrame
: context.internal.forceFirstFrame) = true;
_wrapped->paint(p, context);
context.internal.forceFirstFrame = wasFirst;
context.internal.forceLastFrame = wasLast;
} else if (_played + 1 == _limit && _inLoop && _stopOnLast) {
const auto wasLast = context.internal.overrideFirstWithLastFrame;
context.internal.overrideFirstWithLastFrame = true;
_wrapped->paint(p, context);
context.internal.overrideFirstWithLastFrame = wasLast;
} else {
_wrapped->paint(p, context);
}
}
void LimitedLoopsEmoji::unload() {
_wrapped->unload();
_inLoop = false;
_played = 0;
}
bool LimitedLoopsEmoji::ready() {
return _wrapped->ready();
}
bool LimitedLoopsEmoji::readyInDefaultState() {
return _wrapped->readyInDefaultState();
}
std::unique_ptr<CustomEmoji> MakeCustomEmoji(
QStringView data,
const MarkedContext &context) {
if (auto simple = TryMakeSimpleEmoji(data)) {
return simple;
} else if (const auto &factory = context.customEmojiFactory) {
return factory(data, context);
}
return nullptr;
}
PaletteDependentCustomEmoji::PaletteDependentCustomEmoji(
Fn<QImage()> factory,
QString entity,
QMargins padding)
: _factory(std::move(factory))
, _entity(std::move(entity))
, _padding(padding) {
}
int PaletteDependentCustomEmoji::width() {
if (_frame.isNull()) {
validateFrame();
}
return _padding.left()
+ (_frame.width() / style::DevicePixelRatio())
+ _padding.right();
}
QString PaletteDependentCustomEmoji::entityData() {
return _entity;
}
void PaletteDependentCustomEmoji::paint(
QPainter &p,
const Context &context) {
validateFrame();
p.drawImage(
context.position + QPoint(_padding.left(), _padding.top()),
_frame);
}
void PaletteDependentCustomEmoji::unload() {
_frame = QImage();
}
bool PaletteDependentCustomEmoji::ready() {
return true;
}
bool PaletteDependentCustomEmoji::readyInDefaultState() {
return true;
}
void PaletteDependentCustomEmoji::validateFrame() {
const auto version = style::PaletteVersion();
if (_frame.isNull() || _paletteVersion != version) {
_paletteVersion = version;
_frame = _factory();
}
}
} // namespace Ui::Text