diff --git a/ui/text/custom_emoji_instance.cpp b/ui/text/custom_emoji_instance.cpp index 1a5d004..aa567ab 100644 --- a/ui/text/custom_emoji_instance.cpp +++ b/ui/text/custom_emoji_instance.cpp @@ -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(); + 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(); diff --git a/ui/text/custom_emoji_instance.h b/ui/text/custom_emoji_instance.h index 4ba9b31..4d65ec0 100644 --- a/ui/text/custom_emoji_instance.h +++ b/ui/text/custom_emoji_instance.h @@ -234,6 +234,7 @@ public: [[nodiscard]] bool hasImagePreview() const; [[nodiscard]] Preview imagePreview() const; void updatePreview(Preview preview); + void setColored(); void incrementUsage(not_null object); void decrementUsage(not_null object); @@ -246,15 +247,10 @@ private: std::variant _state; base::flat_set> _usage; Fn 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, Fn repaint); diff --git a/ui/text/text_custom_emoji.h b/ui/text/text_custom_emoji.h index f960d40..052fcff 100644 --- a/ui/text/text_custom_emoji.h +++ b/ui/text/text_custom_emoji.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include @@ -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.;