Support colored custom emoji.

This commit is contained in:
John Preston 2022-08-31 12:27:50 +04:00
parent 6dc6309269
commit 51657b3c8a
3 changed files with 54 additions and 10 deletions

View file

@ -37,6 +37,25 @@ void PaintScaledImage(
const QRect &target,
const Cache::Frame &frame,
const Context &context) {
const auto colored = context.colored;
const auto cache = colored ? &colored->cache : nullptr;
auto q = std::optional<QPainter>();
if (colored) {
const auto ratio = style::DevicePixelRatio();
if (cache->width() < target.width() * ratio
|| cache->height() < target.height() * ratio) {
colored->cache = QImage(
std::max(cache->width(), target.width() * ratio),
std::max(cache->height(), target.height() * ratio),
QImage::Format_ARGB32_Premultiplied);
cache->setDevicePixelRatio(ratio);
}
q.emplace(cache);
q->setCompositionMode(QPainter::CompositionMode_Source);
q->fillRect(QRect(QPoint(), target.size()), Qt::transparent);
q->translate(-target.topLeft());
}
const auto to = q ? &*q : &p;
if (context.scaled) {
const auto sx = anim::interpolate(
target.width() / 2,
@ -47,14 +66,21 @@ void PaintScaledImage(
: anim::interpolate(target.height() / 2, 0, context.scale);
const auto scaled = target.marginsRemoved({ sx, sy, sx, sy });
if (frame.source.isNull()) {
p.drawImage(scaled, *frame.image);
to->drawImage(scaled, *frame.image);
} else {
p.drawImage(scaled, *frame.image, frame.source);
to->drawImage(scaled, *frame.image, frame.source);
}
} else if (frame.source.isNull()) {
p.drawImage(target, *frame.image);
to->drawImage(target, *frame.image);
} else {
p.drawImage(target, *frame.image, frame.source);
to->drawImage(target, *frame.image, frame.source);
}
if (q) {
q.reset();
const auto ratio = style::DevicePixelRatio();
const auto source = QRect(QPoint(), target.size() * ratio);
style::colorizeImage(*cache, colored->color, cache, source);
p.drawImage(target, *cache, source);
}
}
@ -631,6 +657,9 @@ QString Instance::entityData() const {
}
void Instance::paint(QPainter &p, const Context &context) {
const auto colored = (context.colored && !_colored)
? base::take(context.colored)
: nullptr;
v::match(_state, [&](Loading &state) {
state.paint(p, context);
load(state);
@ -655,6 +684,9 @@ void Instance::paint(QPainter &p, const Context &context) {
_repaintLater(this, { result.next, result.duration });
}
});
if (colored) {
context.colored = colored;
}
}
bool Instance::ready() {
@ -730,6 +762,15 @@ void Instance::updatePreview(Preview preview) {
}, [](const Cached &) {});
}
void Instance::setColored() {
if (!_colored) {
_colored = true;
if (ready()) {
_repaintLater(this, { .when = crl::now() + 1 });
}
}
}
void Instance::repaint() {
for (const auto &object : _usage) {
object->repaint();

View file

@ -234,6 +234,7 @@ public:
[[nodiscard]] bool hasImagePreview() const;
[[nodiscard]] Preview imagePreview() const;
void updatePreview(Preview preview);
void setColored();
void incrementUsage(not_null<Object*> object);
void decrementUsage(not_null<Object*> object);
@ -246,15 +247,10 @@ private:
std::variant<Loading, Caching, Cached> _state;
base::flat_set<not_null<Object*>> _usage;
Fn<void(not_null<Instance*> that, RepaintRequest)> _repaintLater;
bool _colored = false;
};
class Delegate {
public:
[[nodiscard]] virtual bool paused() = 0;
virtual ~Delegate() = default;
};
class Object final : public Ui::Text::CustomEmoji {
public:
Object(not_null<Instance*> instance, Fn<void()> repaint);

View file

@ -7,6 +7,7 @@
#pragma once
#include <QtGui/QColor>
#include <QtGui/QImage>
#include <QtCore/QSize>
#include <QtCore/QPoint>
@ -18,8 +19,14 @@ namespace Ui::Text {
[[nodiscard]] int AdjustCustomEmojiSize(int emojiSize);
struct CustomEmojiColored {
QColor color;
QImage cache;
};
struct CustomEmojiPaintContext {
QColor preview;
mutable CustomEmojiColored *colored = nullptr;
QSize size; // Required only when scaled = true, for path scaling.
crl::time now = 0;
float64 scale = 0.;