diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 1b8ce6cbc..4cfb04451 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/image/image.h" #include "ui/cached_round_corners.h" #include "window/window_session_controller.h" +#include "media/clip/media_clip_reader.h" #include "main/main_session.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" @@ -143,10 +144,7 @@ private: int32 count, const QString &title, int titleWidth, - bool installed, - bool official, - bool unread, - bool archived, + Data::StickersSetFlags flagsOverride, bool removed, int32 pixw, int32 pixh); @@ -154,6 +152,10 @@ private: bool isRecentSet() const; bool isMasksSet() const; + bool isWebm() const; + bool isInstalled() const; + bool isUnread() const; + bool isArchived() const; const not_null set; DocumentData *sticker = nullptr; @@ -162,16 +164,14 @@ private: int32 count = 0; QString title; int titleWidth = 0; - bool installed = false; - bool official = false; - bool unread = false; - bool archived = false; + Data::StickersSetFlags flagsOverride; bool removed = false; int32 pixw = 0; int32 pixh = 0; anim::value yadd; std::unique_ptr ripple; std::unique_ptr lottie; + Media::Clip::ReaderPointer webm; }; struct MegagroupSet { inline bool operator==(const MegagroupSet &other) const { @@ -221,6 +221,8 @@ private: void setActionSel(int32 actionSel); float64 aboveShadowOpacity() const; void validateLottieAnimation(not_null row); + void validateWebmAnimation(not_null row); + void validateAnimation(not_null row); void updateRowThumbnail(not_null row); void readVisibleSets(); @@ -229,8 +231,12 @@ private: void rebuildAppendSet(not_null set, int maxNameWidth); void fillSetCover(not_null set, DocumentData **outSticker, int *outWidth, int *outHeight) const; int fillSetCount(not_null set) const; - QString fillSetTitle(not_null set, int maxNameWidth, int *outTitleWidth) const; - void fillSetFlags(not_null set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived); + [[nodiscard]] QString fillSetTitle( + not_null set, + int maxNameWidth, + int *outTitleWidth) const; + [[nodiscard]] Data::StickersSetFlags fillSetFlags( + not_null set) const; void rebuildMegagroupSet(); void fixupMegagroupSetAddress(); void handleMegagroupSetAddressChange(); @@ -1030,10 +1036,7 @@ StickersBox::Inner::Row::Row( int32 count, const QString &title, int titleWidth, - bool installed, - bool official, - bool unread, - bool archived, + Data::StickersSetFlags flagsOverride, bool removed, int32 pixw, int32 pixh) @@ -1042,10 +1045,7 @@ StickersBox::Inner::Row::Row( , count(count) , title(title) , titleWidth(titleWidth) -, installed(installed) -, official(official) -, unread(unread) -, archived(archived) +, flagsOverride(flagsOverride) , removed(removed) , pixw(pixw) , pixh(pixh) { @@ -1062,6 +1062,22 @@ bool StickersBox::Inner::Row::isMasksSet() const { return (set->flags & SetFlag::Masks); } +bool StickersBox::Inner::Row::isWebm() const { + return (set->flags & SetFlag::Webm); +} + +bool StickersBox::Inner::Row::isInstalled() const { + return (flagsOverride & SetFlag::Installed); +} + +bool StickersBox::Inner::Row::isUnread() const { + return (flagsOverride & SetFlag::Unread); +} + +bool StickersBox::Inner::Row::isArchived() const { + return (flagsOverride & SetFlag::Archived); +} + StickersBox::Inner::Inner( QWidget *parent, not_null controller, @@ -1302,7 +1318,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null row, int index) { p.setPen(st::contactsNameFg); p.drawTextLeft(namex, namey, width(), row->title, row->titleWidth); - if (row->unread) { + if (row->isUnread()) { p.setPen(Qt::NoPen); p.setBrush(st::stickersFeaturedUnreadBg); @@ -1344,7 +1360,7 @@ void StickersBox::Inner::paintRowThumbnail( row->stickerMedia->thumbnailWanted(origin); } } - validateLottieAnimation(row); + validateAnimation(row); if (!row->lottie) { const auto thumb = row->thumbnailMedia ? row->thumbnailMedia->image() @@ -1380,6 +1396,7 @@ void StickersBox::Inner::paintRowThumbnail( void StickersBox::Inner::validateLottieAnimation(not_null row) { if (row->lottie || !ChatHelpers::HasLottieThumbnail( + row->set->flags, row->thumbnailMedia.get(), row->stickerMedia.get())) { return; @@ -1401,6 +1418,25 @@ void StickersBox::Inner::validateLottieAnimation(not_null row) { }, lifetime()); } +void StickersBox::Inner::validateWebmAnimation(not_null row) { + if (row->webm + || !ChatHelpers::HasWebmThumbnail( + row->set->flags, + row->thumbnailMedia.get(), + row->stickerMedia.get())) { + return; + } + row->webm = ChatHelpers::WebmThumbnail( + row->thumbnailMedia.get(), + row->stickerMedia.get(), + [=](Media::Clip::Notification) { updateRowThumbnail(row); }); +} + +void StickersBox::Inner::validateAnimation(not_null row) { + validateWebmAnimation(row); + validateLottieAnimation(row); +} + void StickersBox::Inner::updateRowThumbnail(not_null row) { const auto rowTop = [&] { if (row == _megagroupSelectedSet.get()) { @@ -1429,7 +1465,7 @@ void StickersBox::Inner::updateRowThumbnail(not_null row) { void StickersBox::Inner::paintFakeButton(Painter &p, not_null row, int index) { auto removeButton = (_isInstalled && !row->removed); auto rect = relativeButtonRect(removeButton); - if (!_isInstalled && row->installed && !row->archived && !row->removed) { + if (!_isInstalled && row->isInstalled() && !row->isArchived() && !row->removed) { // Checkbox after installed from Trending or Archived. int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (rect.width() + st::stickersFeaturedInstalled.width()) / 2); int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2; @@ -1516,7 +1552,7 @@ void StickersBox::Inner::setActionDown(int newActionDown) { auto rippleMask = Ui::RippleAnimation::ellipseMask(QSize(rippleSize, rippleSize)); ensureRipple(st::stickersRemove.ripple, std::move(rippleMask), removeButton); } - } else if (!row->installed || row->archived || row->removed) { + } else if (!row->isInstalled() || row->isArchived() || row->removed) { auto rippleSize = QSize(_addWidth - st::stickersTrendingAdd.width, st::stickersTrendingAdd.height); auto rippleMask = Ui::RippleAnimation::roundRectMask(rippleSize, st::roundRadiusSmall); ensureRipple(st::stickersTrendingAdd.ripple, std::move(rippleMask), removeButton); @@ -1649,7 +1685,7 @@ void StickersBox::Inner::updateSelected() { selected = selectedIndex; local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight); const auto row = _rows[selectedIndex].get(); - if (!_megagroupSet && (_isInstalled || !row->installed || row->archived || row->removed)) { + if (!_megagroupSet && (_isInstalled || !row->isInstalled() || row->isArchived() || row->removed)) { auto removeButton = (_isInstalled && !row->removed); auto rect = myrtlrect(relativeButtonRect(removeButton)); actionSel = rect.contains(local) ? selectedIndex : -1; @@ -1952,8 +1988,10 @@ void StickersBox::Inner::rebuildMegagroupSet() { auto sticker = (DocumentData*)nullptr; auto pixw = 0, pixh = 0; fillSetCover(set, &sticker, &pixw, &pixh); - auto installed = true, official = false, unread = false, archived = false, removed = false; - if (!_megagroupSelectedSet || _megagroupSelectedSet->set->id != set->id) { + auto flagsOverride = SetFlag::Installed; + auto removed = false; + if (!_megagroupSelectedSet + || _megagroupSelectedSet->set->id != set->id) { _megagroupSetField->setText(set->shortName); _megagroupSetField->finishAnimating(); } @@ -1963,10 +2001,7 @@ void StickersBox::Inner::rebuildMegagroupSet() { count, title, titleWidth, - installed, - official, - unread, - archived, + flagsOverride, removed, pixw, pixh); @@ -2095,13 +2130,14 @@ void StickersBox::Inner::updateRows() { } } if (!row->isRecentSet()) { - auto wasInstalled = row->installed; - auto wasArchived = row->archived; - fillSetFlags(set, &row->installed, &row->official, &row->unread, &row->archived); + auto wasInstalled = row->isInstalled(); + auto wasArchived = row->isArchived(); + row->flagsOverride = fillSetFlags(set); if (_isInstalled) { - row->archived = false; + row->flagsOverride &= ~SetFlag::Archived; } - if (row->installed != wasInstalled || row->archived != wasArchived) { + if (row->isInstalled() != wasInstalled + || row->isArchived() != wasArchived) { row->ripple.reset(); } } @@ -2143,11 +2179,11 @@ int StickersBox::Inner::countMaxNameWidth() const { void StickersBox::Inner::rebuildAppendSet( not_null set, int maxNameWidth) { - bool installed = true, official = true, unread = false, archived = false, removed = false; - if (set->id != Data::Stickers::CloudRecentSetId) { - fillSetFlags(set, &installed, &official, &unread, &archived); - } - if (_isInstalled && archived) { + auto flagsOverride = (set->id != Data::Stickers::CloudRecentSetId) + ? fillSetFlags(set) + : SetFlag::Installed; + auto removed = false; + if (_isInstalled && (flagsOverride & SetFlag::Archived)) { return; } @@ -2176,10 +2212,7 @@ void StickersBox::Inner::rebuildAppendSet( raw->count = count; raw->title = title; raw->titleWidth = titleWidth; - raw->installed = installed; - raw->official = official; - raw->unread = unread; - raw->archived = archived; + raw->flagsOverride = flagsOverride; raw->removed = removed; raw->pixw = pixw; raw->pixh = pixh; @@ -2200,10 +2233,7 @@ void StickersBox::Inner::rebuildAppendSet( count, title, titleWidth, - installed, - official, - unread, - archived, + flagsOverride, removed, pixw, pixh)); @@ -2289,20 +2319,12 @@ QString StickersBox::Inner::fillSetTitle( return result; } -void StickersBox::Inner::fillSetFlags( - not_null set, - bool *outInstalled, - bool *outOfficial, - bool *outUnread, - bool *outArchived) { - *outInstalled = (set->flags & SetFlag::Installed); - *outOfficial = (set->flags & SetFlag::Official); - *outArchived = (set->flags & SetFlag::Archived); - if (_section == Section::Featured) { - *outUnread = (set->flags & SetFlag::Unread); - } else { - *outUnread = false; - } +Data::StickersSetFlags StickersBox::Inner::fillSetFlags( + not_null set) const { + const auto result = set->flags; + return (_section == Section::Featured) + ? result + : (result & ~SetFlag::Unread); } template @@ -2319,7 +2341,7 @@ StickersSetsOrder StickersBox::Inner::collectSets(Check check) const { StickersSetsOrder StickersBox::Inner::getOrder() const { return collectSets([](Row *row) { - return !row->archived && !row->removed && !row->isRecentSet(); + return !row->isArchived() && !row->removed && !row->isRecentSet(); }); } @@ -2394,7 +2416,7 @@ void StickersBox::Inner::readVisibleSets() { int rowTo = ceilclamp(itemsVisibleBottom, _rowHeight, 0, _rows.size()); for (int i = rowFrom; i < rowTo; ++i) { const auto row = _rows[i].get(); - if (!row->unread) { + if (!row->isUnread()) { continue; } if ((i * _rowHeight < itemsVisibleTop) diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index 3ff413bc7..778016663 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" // GifPauseReason. #include "main/main_session.h" #include "main/main_session_settings.h" +#include "media/clip/media_clip_reader.h" #include "apiwrap.h" #include "api/api_toggling_media.h" // Api::ToggleFavedSticker #include "styles/style_chat_helpers.h" @@ -97,6 +98,7 @@ struct StickerIcon { uint64 setId = 0; StickersSet *set = nullptr; mutable std::unique_ptr lottie; + mutable Media::Clip::ReaderPointer webm; mutable QPixmap savedFrame; DocumentData *sticker = nullptr; ChannelData *megagroup = nullptr; @@ -157,6 +159,8 @@ private: int newSelected, ValidateIconAnimations animations); void validateIconLottieAnimation(const StickerIcon &icon); + void validateIconWebmAnimation(const StickerIcon &icon); + void validateIconAnimation(const StickerIcon &icon); void refreshIconsGeometry(ValidateIconAnimations animations); void updateSelected(); @@ -792,6 +796,7 @@ void StickersListWidget::Footer::validateIconLottieAnimation( if (icon.lottie || !icon.sticker || !HasLottieThumbnail( + icon.set ? icon.set->flags : Data::StickersSetFlags(), icon.thumbnailMedia.get(), icon.stickerMedia.get())) { return; @@ -817,6 +822,30 @@ void StickersListWidget::Footer::validateIconLottieAnimation( }, icon.lifetime); } +void StickersListWidget::Footer::validateIconWebmAnimation( + const StickerIcon &icon) { + icon.ensureMediaCreated(); + if (icon.webm + || !icon.sticker + || !HasWebmThumbnail( + icon.set ? icon.set->flags : Data::StickersSetFlags(), + icon.thumbnailMedia.get(), + icon.stickerMedia.get())) { + return; + } + const auto id = icon.setId; + icon.webm = WebmThumbnail( + icon.thumbnailMedia.get(), + icon.stickerMedia.get(), + [=](Media::Clip::Notification) { updateSetIcon(id); }); +} + +void StickersListWidget::Footer::validateIconAnimation( + const StickerIcon &icon) { + validateIconWebmAnimation(icon); + validateIconLottieAnimation(icon); +} + void StickersListWidget::Footer::updateSetIcon(uint64 setId) { enumerateVisibleIcons([&](const StickerIcon &icon, int x) { if (icon.setId != setId) { @@ -832,7 +861,7 @@ void StickersListWidget::Footer::paintSetIcon( int x) const { if (icon.sticker) { icon.ensureMediaCreated(); - const_cast(this)->validateIconLottieAnimation(icon); + const_cast(this)->validateIconAnimation(icon); const auto origin = icon.sticker->stickerSetOrigin(); const auto thumb = icon.thumbnailMedia ? icon.thumbnailMedia->image() diff --git a/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp b/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp index ed7a11731..b7d45af42 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_file_origin.h" #include "storage/cache/storage_cache_database.h" +#include "media/clip/media_clip_reader.h" #include "ui/effects/path_shift_gradient.h" #include "main/main_session.h" @@ -130,10 +131,12 @@ not_null LottieAnimationFromDocument( } bool HasLottieThumbnail( + Data::StickersSetFlags flags, Data::StickersSetThumbnailView *thumb, Data::DocumentMedia *media) { if (thumb) { - return !thumb->content().isEmpty(); + return !(flags & Data::StickersSetFlag::Webm) + && !thumb->content().isEmpty(); } else if (!media) { return false; } @@ -189,6 +192,44 @@ std::unique_ptr LottieThumbnail( box); } +bool HasWebmThumbnail( + Data::StickersSetFlags flags, + Data::StickersSetThumbnailView *thumb, + Data::DocumentMedia *media) { + if (thumb) { + return (flags & Data::StickersSetFlag::Webm) + && !thumb->content().isEmpty(); + } else if (!media) { + return false; + } + const auto document = media->owner(); + if (const auto info = document->sticker()) { + if (!info->isWebm()) { + return false; + } + media->automaticLoad(document->stickerSetOrigin(), nullptr); + if (!media->loaded()) { + return false; + } + return document->bigFileBaseCacheKey().valid(); + } + return false; +} + +Media::Clip::ReaderPointer WebmThumbnail( + Data::StickersSetThumbnailView *thumb, + Data::DocumentMedia *media, + Fn callback) { + return thumb + ? ::Media::Clip::MakeReader( + thumb->content(), + std::move(callback)) + : ::Media::Clip::MakeReader( + media->owner()->location(), + media->bytes(), + std::move(callback)); +} + bool PaintStickerThumbnailPath( QPainter &p, not_null media, diff --git a/Telegram/SourceFiles/chat_helpers/stickers_lottie.h b/Telegram/SourceFiles/chat_helpers/stickers_lottie.h index 3a24b6422..20407423a 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_lottie.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_lottie.h @@ -7,12 +7,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +namespace base { +template +class Flags; +} // namespace base + namespace Storage { namespace Cache { struct Key; } // namespace Cache } // namespace Storage +namespace Media::Clip { +class ReaderPointer; +enum class Notification; +} // namespace Media::Clip + namespace Lottie { class SinglePlayer; class MultiPlayer; @@ -33,6 +43,8 @@ class PathShiftGradient; namespace Data { class DocumentMedia; class StickersSetThumbnailView; +enum class StickersSetFlag; +using StickersSetFlags = base::flags; } // namespace Data namespace ChatHelpers { @@ -70,6 +82,7 @@ enum class StickerLottieSize : uchar { QSize box); [[nodiscard]] bool HasLottieThumbnail( + Data::StickersSetFlags flags, Data::StickersSetThumbnailView *thumb, Data::DocumentMedia *media); [[nodiscard]] std::unique_ptr LottieThumbnail( @@ -79,6 +92,15 @@ enum class StickerLottieSize : uchar { QSize box, std::shared_ptr renderer = nullptr); +[[nodiscard]] bool HasWebmThumbnail( + Data::StickersSetFlags flags, + Data::StickersSetThumbnailView *thumb, + Data::DocumentMedia *media); +[[nodiscard]] Media::Clip::ReaderPointer WebmThumbnail( + Data::StickersSetThumbnailView *thumb, + Data::DocumentMedia *media, + Fn callback); + bool PaintStickerThumbnailPath( QPainter &p, not_null media, diff --git a/Telegram/SourceFiles/data/data_document_media.h b/Telegram/SourceFiles/data/data_document_media.h index 5a2fea7c7..799687466 100644 --- a/Telegram/SourceFiles/data/data_document_media.h +++ b/Telegram/SourceFiles/data/data_document_media.h @@ -14,7 +14,7 @@ class FileLoader; namespace Media { namespace Clip { -enum Notification : int; +enum class Notification; class ReaderPointer; } // namespace Clip } // namespace Media diff --git a/Telegram/SourceFiles/data/stickers/data_stickers_set.cpp b/Telegram/SourceFiles/data/stickers/data_stickers_set.cpp index 3e4895190..3fccebd02 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers_set.cpp +++ b/Telegram/SourceFiles/data/stickers/data_stickers_set.cpp @@ -49,7 +49,8 @@ StickersSetFlags ParseStickersSetFlags(const MTPDstickerSet &data) { return (data.is_archived() ? Flag::Archived : Flag()) | (data.is_official() ? Flag::Official : Flag()) | (data.is_masks() ? Flag::Masks : Flag()) - | (data.vinstalled_date() ? Flag::Installed : Flag()); + | (data.vinstalled_date() ? Flag::Installed : Flag()) + | (data.is_gifs() ? Flag::Webm : Flag()); } StickersSet::StickersSet( diff --git a/Telegram/SourceFiles/data/stickers/data_stickers_set.h b/Telegram/SourceFiles/data/stickers/data_stickers_set.h index 03fc0c019..01ecbf581 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers_set.h +++ b/Telegram/SourceFiles/data/stickers/data_stickers_set.h @@ -54,6 +54,7 @@ enum class StickersSetFlag { Featured = (1 << 5), Unread = (1 << 6), Special = (1 << 7), + Webm = (1 << 8), }; inline constexpr bool is_flag_type(StickersSetFlag) { return true; }; using StickersSetFlags = base::flags; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 3b6ce3231..64370851e 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -393,7 +393,7 @@ void Gif::unloadHeavyPart() { void Gif::clipCallback(Media::Clip::Notification notification) { using namespace Media::Clip; switch (notification) { - case NotificationReinit: { + case Notification::Reinit: { if (_gif) { if (_gif->state() == State::Error) { _gif.setBad(); @@ -416,7 +416,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) { update(); } break; - case NotificationRepaint: { + case Notification::Repaint: { if (_gif && !_gif->currentDisplayed()) { update(); } @@ -1583,7 +1583,7 @@ void Game::unloadHeavyPart() { void Game::clipCallback(Media::Clip::Notification notification) { using namespace Media::Clip; switch (notification) { - case NotificationReinit: { + case Notification::Reinit: { if (_gif) { if (_gif->state() == State::Error) { _gif.setBad(); @@ -1610,7 +1610,7 @@ void Game::clipCallback(Media::Clip::Notification notification) { update(); } break; - case NotificationRepaint: { + case Notification::Repaint: { if (_gif && !_gif->currentDisplayed()) { update(); } diff --git a/Telegram/SourceFiles/media/clip/media_clip_reader.cpp b/Telegram/SourceFiles/media/clip/media_clip_reader.cpp index f27f01397..e0ccdfa0f 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_reader.cpp +++ b/Telegram/SourceFiles/media/clip/media_clip_reader.cpp @@ -133,12 +133,12 @@ void Reader::init(const Core::FileLocation &location, const QByteArray &data) { Reader::Frame *Reader::frameToShow(int32 *index) const { // 0 means not ready int step = _step.loadAcquire(), i; - if (step == WaitingForDimensionsStep) { + if (step == kWaitingForDimensionsStep) { if (index) *index = 0; return nullptr; - } else if (step == WaitingForRequestStep) { + } else if (step == kWaitingForRequestStep) { i = 0; - } else if (step == WaitingForFirstFrameStep) { + } else if (step == kWaitingForFirstFrameStep) { i = 0; } else { i = (step / 2) % 3; @@ -149,12 +149,12 @@ Reader::Frame *Reader::frameToShow(int32 *index) const { // 0 means not ready Reader::Frame *Reader::frameToWrite(int32 *index) const { // 0 means not ready int32 step = _step.loadAcquire(), i; - if (step == WaitingForDimensionsStep) { + if (step == kWaitingForDimensionsStep) { i = 0; - } else if (step == WaitingForRequestStep) { + } else if (step == kWaitingForRequestStep) { if (index) *index = 0; return nullptr; - } else if (step == WaitingForFirstFrameStep) { + } else if (step == kWaitingForFirstFrameStep) { i = 0; } else { i = ((step + 2) / 2) % 3; @@ -165,7 +165,9 @@ Reader::Frame *Reader::frameToWrite(int32 *index) const { // 0 means not ready Reader::Frame *Reader::frameToWriteNext(bool checkNotWriting, int32 *index) const { int32 step = _step.loadAcquire(), i; - if (step == WaitingForDimensionsStep || step == WaitingForRequestStep || (checkNotWriting && (step % 2))) { + if (step == kWaitingForDimensionsStep + || step == kWaitingForRequestStep + || (checkNotWriting && (step % 2))) { if (index) *index = 0; return nullptr; } @@ -176,10 +178,10 @@ Reader::Frame *Reader::frameToWriteNext(bool checkNotWriting, int32 *index) cons void Reader::moveToNextShow() const { int32 step = _step.loadAcquire(); - if (step == WaitingForDimensionsStep) { - } else if (step == WaitingForRequestStep) { - _step.storeRelease(WaitingForFirstFrameStep); - } else if (step == WaitingForFirstFrameStep) { + if (step == kWaitingForDimensionsStep) { + } else if (step == kWaitingForRequestStep) { + _step.storeRelease(kWaitingForFirstFrameStep); + } else if (step == kWaitingForFirstFrameStep) { } else if (!(step % 2)) { _step.storeRelease(step + 1); } @@ -187,10 +189,10 @@ void Reader::moveToNextShow() const { void Reader::moveToNextWrite() const { int32 step = _step.loadAcquire(); - if (step == WaitingForDimensionsStep) { - _step.storeRelease(WaitingForRequestStep); - } else if (step == WaitingForRequestStep) { - } else if (step == WaitingForFirstFrameStep) { + if (step == kWaitingForDimensionsStep) { + _step.storeRelease(kWaitingForRequestStep); + } else if (step == kWaitingForRequestStep) { + } else if (step == kWaitingForFirstFrameStep) { _step.storeRelease(0); // Force paint the first frame so moveToNextShow() is called. @@ -200,7 +202,10 @@ void Reader::moveToNextWrite() const { } } -void Reader::callback(Reader *reader, qint32 threadIndex, qint32 notification) { +void Reader::SafeCallback( + Reader *reader, + int threadIndex, + Notification notification) { // Check if reader is not deleted already if (managers.size() > threadIndex && managers.at(threadIndex)->carries(reader) && reader->_callback) { reader->_callback(Notification(notification)); @@ -211,7 +216,7 @@ void Reader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, Image if (managers.size() <= _threadIndex) error(); if (_state == State::Error) return; - if (_step.loadAcquire() == WaitingForRequestStep) { + if (_step.loadAcquire() == kWaitingForRequestStep) { int factor = style::DevicePixelRatio(); FrameRequest request; request.factor = factor; @@ -613,23 +618,29 @@ bool Manager::carries(Reader *reader) const { return _readerPointers.contains(reader); } -Manager::ReaderPointers::iterator Manager::unsafeFindReaderPointer(ReaderPrivate *reader) { - ReaderPointers::iterator it = _readerPointers.find(reader->_interface); +auto Manager::unsafeFindReaderPointer(ReaderPrivate *reader) +-> ReaderPointers::iterator { + const auto it = _readerPointers.find(reader->_interface); // could be a new reader which was realloced in the same address - return (it == _readerPointers.cend() || it.key()->_private == reader) ? it : _readerPointers.end(); + return (it == _readerPointers.cend() || it.key()->_private == reader) + ? it + : _readerPointers.end(); } -Manager::ReaderPointers::const_iterator Manager::constUnsafeFindReaderPointer(ReaderPrivate *reader) const { - ReaderPointers::const_iterator it = _readerPointers.constFind(reader->_interface); +auto Manager::constUnsafeFindReaderPointer(ReaderPrivate *reader) const +-> ReaderPointers::const_iterator { + const auto it = _readerPointers.constFind(reader->_interface); // could be a new reader which was realloced in the same address - return (it == _readerPointers.cend() || it.key()->_private == reader) ? it : _readerPointers.cend(); + return (it == _readerPointers.cend() || it.key()->_private == reader) + ? it + : _readerPointers.cend(); } void Manager::callback(Reader *reader, Notification notification) { crl::on_main([=, threadIndex = reader->threadIndex()] { - Reader::callback(reader, threadIndex, notification); + Reader::SafeCallback(reader, threadIndex, notification); }); } @@ -639,14 +650,14 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, c if (result == ProcessResult::Error) { if (it != _readerPointers.cend()) { it.key()->error(); - callback(it.key(), NotificationReinit); + callback(it.key(), Notification::Reinit); _readerPointers.erase(it); } return false; } else if (result == ProcessResult::Finished) { if (it != _readerPointers.cend()) { it.key()->finished(); - callback(it.key(), NotificationReinit); + callback(it.key(), Notification::Reinit); } return false; } @@ -682,14 +693,14 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, c if (result == ProcessResult::Started) { reader->startedAt(ms); it.key()->moveToNextWrite(); - callback(it.key(), NotificationReinit); + callback(it.key(), Notification::Reinit); } } else if (result == ProcessResult::Paused) { it.key()->moveToNextWrite(); - callback(it.key(), NotificationReinit); + callback(it.key(), Notification::Reinit); } else if (result == ProcessResult::Repaint) { it.key()->moveToNextWrite(); - callback(it.key(), NotificationRepaint); + callback(it.key(), Notification::Repaint); } return true; } diff --git a/Telegram/SourceFiles/media/clip/media_clip_reader.h b/Telegram/SourceFiles/media/clip/media_clip_reader.h index b4ea5a3e9..430acb28d 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_reader.h +++ b/Telegram/SourceFiles/media/clip/media_clip_reader.h @@ -39,15 +39,19 @@ struct FrameRequest { RectParts corners = RectPart::AllCorners; }; -enum ReaderSteps : int { - WaitingForDimensionsStep = -3, // before ReaderPrivate read the first image and got the original frame size - WaitingForRequestStep = -2, // before Reader got the original frame size and prepared the frame request - WaitingForFirstFrameStep = -1, // before ReaderPrivate got the frame request and started waiting for the 1-2 delay -}; +// Before ReaderPrivate read the first image and got the original frame size. +inline constexpr auto kWaitingForDimensionsStep = -3; -enum Notification : int { - NotificationReinit, - NotificationRepaint, +// Before Reader got the original frame size and prepared the frame request. +inline constexpr auto kWaitingForRequestStep = -2; + +// Before ReaderPrivate got the frame request +// and started waiting for the 1-2 delay. +inline constexpr auto kWaitingForFirstFrameStep = -1; + +enum class Notification { + Reinit, + Repaint, }; class ReaderPrivate; @@ -64,7 +68,10 @@ public: Reader(const QByteArray &data, Callback &&callback); // Reader can be already deleted. - static void callback(Reader *reader, qint32 threadIndex, qint32 notification); + static void SafeCallback( + Reader *reader, + int threadIndex, + Notification notification); void start(int framew, int frameh, int outerw, int outerh, ImageRoundRadius radius, RectParts corners); QPixmap current(int framew, int frameh, int outerw, int outerh, ImageRoundRadius radius, RectParts corners, crl::time ms); @@ -94,7 +101,7 @@ public: State state() const; bool started() const { auto step = _step.loadAcquire(); - return (step == WaitingForFirstFrameStep) || (step >= 0); + return (step == kWaitingForFirstFrameStep) || (step >= 0); } bool ready() const; @@ -120,7 +127,7 @@ private: mutable int _height = 0; // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3 - mutable QAtomicInt _step = WaitingForDimensionsStep; + mutable QAtomicInt _step = kWaitingForDimensionsStep; struct Frame { void clear() { pix = QPixmap(); diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index f87611eff..c88648948 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -1897,7 +1897,7 @@ QSize Gif::countFrameSize() const { void Gif::clipCallback(Media::Clip::Notification notification) { using namespace Media::Clip; switch (notification) { - case NotificationReinit: { + case Notification::Reinit: { if (_gif) { if (_gif->state() == State::Error) { _gif.setBad(); @@ -1926,7 +1926,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) { update(); } break; - case NotificationRepaint: { + case Notification::Repaint: { if (_gif && !_gif->currentDisplayed()) { update(); } diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.cpp index 9faf52242..e1d1a51f1 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_single_media_preview.cpp @@ -133,7 +133,7 @@ void SingleMediaPreview::clipCallback( Media::Clip::Notification notification) { using namespace Media::Clip; switch (notification) { - case NotificationReinit: { + case Notification::Reinit: { if (_gifPreview && _gifPreview->state() == State::Error) { _gifPreview.setBad(); } @@ -152,7 +152,7 @@ void SingleMediaPreview::clipCallback( update(); } break; - case NotificationRepaint: { + case Notification::Repaint: { if (_gifPreview && !_gifPreview->currentDisplayed()) { update(); } diff --git a/Telegram/SourceFiles/window/window_media_preview.cpp b/Telegram/SourceFiles/window/window_media_preview.cpp index 4ee042b5d..dcdfd9571 100644 --- a/Telegram/SourceFiles/window/window_media_preview.cpp +++ b/Telegram/SourceFiles/window/window_media_preview.cpp @@ -391,7 +391,7 @@ void MediaPreviewWidget::clipCallback( Media::Clip::Notification notification) { using namespace Media::Clip; switch (notification) { - case NotificationReinit: { + case Notification::Reinit: { if (_gifThumbnail && _gifThumbnail->state() == State::Error) { _gifThumbnail.setBad(); } @@ -413,7 +413,7 @@ void MediaPreviewWidget::clipCallback( update(); } break; - case NotificationRepaint: { + case Notification::Repaint: { if ((_gif && _gif->started() && !_gif->currentDisplayed()) || (_gifThumbnail && _gifThumbnail->started()