diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index c301910ee1..4d42c28980 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -115,6 +115,9 @@ EditCaptionBox::EditCaptionBox( _refreshThumbnail(); } } else { + if (!image) { + image = Image::BlankMedia(); + } int32 maxW = 0, maxH = 0; if (_animated) { int32 limitW = st::sendMediaPreviewSize; @@ -201,7 +204,9 @@ EditCaptionBox::EditCaptionBox( ? _thumbnailImage->loaded() : true; subscribe(Auth().downloaderTaskFinished(), [=] { - if (!_thumbnailImageLoaded && _thumbnailImage->loaded()) { + if (!_thumbnailImageLoaded + && _thumbnailImage + && _thumbnailImage->loaded()) { _thumbnailImageLoaded = true; _refreshThumbnail(); update(); diff --git a/Telegram/SourceFiles/history/media/history_media_gif.cpp b/Telegram/SourceFiles/history/media/history_media_gif.cpp index fbb58893ba..74dfb67e45 100644 --- a/Telegram/SourceFiles/history/media/history_media_gif.cpp +++ b/Telegram/SourceFiles/history/media/history_media_gif.cpp @@ -347,12 +347,22 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM if (good) { good->load({}); } - if (const auto normal = _data->thumbnail()) { - if (normal->loaded()) { - p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); - } else if (const auto blurred = _data->thumbnailInline()) { - p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); - } + const auto normal = _data->thumbnail(); + if (normal && normal->loaded()) { + p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners)); + } else if (const auto blurred = _data->thumbnailInline()) { + p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners)); + } else if (!isRound) { + const auto roundTop = (roundCorners & RectPart::TopLeft); + const auto roundBottom = (roundCorners & RectPart::BottomLeft); + const auto margin = inWebPage + ? st::buttonRadius + : st::historyMessageRadius; + const auto parts = roundCorners + | RectPart::NoTopBottom + | (roundTop ? RectPart::Top : RectPart::None) + | (roundBottom ? RectPart::Bottom : RectPart::None); + App::roundRect(p, rthumb.marginsAdded({ 0, roundTop ? 0 : margin, 0, roundBottom ? 0 : margin }), st::imageBg, roundRadius, parts); } } } diff --git a/Telegram/SourceFiles/history/media/history_media_photo.cpp b/Telegram/SourceFiles/history/media/history_media_photo.cpp index ad9e3d4ed5..4579658436 100644 --- a/Telegram/SourceFiles/history/media/history_media_photo.cpp +++ b/Telegram/SourceFiles/history/media/history_media_photo.cpp @@ -528,7 +528,7 @@ void HistoryPhoto::validateGroupedCache( ? _data->thumbnailSmall().get() : _data->thumbnailInline() ? _data->thumbnailInline() - : Image::Blank().get(); + : Image::BlankMedia().get(); *cacheKey = key; *cache = image->pixNoCache(_realParent->fullId(), pixWidth, pixHeight, options, width, height); diff --git a/Telegram/SourceFiles/history/media/history_media_video.cpp b/Telegram/SourceFiles/history/media/history_media_video.cpp index 64dbe3da47..6df2165c55 100644 --- a/Telegram/SourceFiles/history/media/history_media_video.cpp +++ b/Telegram/SourceFiles/history/media/history_media_video.cpp @@ -183,11 +183,22 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, Tim if (good) { good->load({}); } - if (const auto normal = _data->thumbnail()) { - const auto use = (normal->loaded() || !_data->thumbnailInline()) - ? normal - : _data->thumbnailInline(); - p.drawPixmap(rthumb.topLeft(), use->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners)); + const auto normal = _data->thumbnail(); + if (normal && normal->loaded()) { + p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners)); + } else if (const auto blurred = _data->thumbnailInline()) { + p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners)); + } else { + const auto roundTop = (roundCorners & RectPart::TopLeft); + const auto roundBottom = (roundCorners & RectPart::BottomLeft); + const auto margin = inWebPage + ? st::buttonRadius + : st::historyMessageRadius; + const auto parts = roundCorners + | RectPart::NoTopBottom + | (roundTop ? RectPart::Top : RectPart::None) + | (roundBottom ? RectPart::Bottom : RectPart::None); + App::roundRect(p, rthumb.marginsAdded({ 0, roundTop ? 0 : margin, 0, roundBottom ? 0 : margin }), st::imageBg, roundRadius, parts); } } if (selected) { @@ -496,7 +507,13 @@ void HistoryVideo::validateGroupedCache( const auto pixHeight = pixSize.height() * cIntRetinaFactor(); *cacheKey = key; - *cache = (image ? image : Image::Blank().get())->pixNoCache(_realParent->fullId(), pixWidth, pixHeight, options, width, height); + *cache = (image ? image : Image::BlankMedia().get())->pixNoCache( + _realParent->fullId(), + pixWidth, + pixHeight, + options, + width, + height); } void HistoryVideo::setStatusSize(int newSize) const { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 66477619c4..618f2e8982 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1810,12 +1810,12 @@ void OverlayWidget::initAnimation() { auto h = _doc->dimensions.height(); _current = (_doc->hasThumbnail() ? _doc->thumbnail() - : Image::Blank().get())->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor()); + : Image::Empty().get())->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor()); _current.setDevicePixelRatio(cRetinaFactor()); } else if (_doc->hasThumbnail()) { _current = _doc->thumbnail()->pixNoCache(fileOrigin(), _doc->thumbnail()->width(), _doc->thumbnail()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize); } else { - _current = Image::Blank().get()->pixNoCache({}, Image::Blank()->width(), Image::Blank()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize); + _current = Image::Empty()->pixNoCache({}, Image::Empty()->width(), Image::Empty()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize); } } @@ -1830,12 +1830,12 @@ void OverlayWidget::createClipReader() { int h = _doc->dimensions.height(); _current = (_doc->hasThumbnail() ? _doc->thumbnail() - : Image::Blank().get())->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor()); + : Image::Empty().get())->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor()); _current.setDevicePixelRatio(cRetinaFactor()); } else if (_doc->hasThumbnail()) { _current = _doc->thumbnail()->pixNoCache(fileOrigin(), _doc->thumbnail()->width(), _doc->thumbnail()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize); } else { - _current = Image::Blank()->pixNoCache({}, Image::Blank()->width(), Image::Blank()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize); + _current = Image::Empty()->pixNoCache({}, Image::Empty()->width(), Image::Empty()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize); } auto mode = (_doc->isVideoFile() || _doc->isVideoMessage()) ? Media::Clip::Reader::Mode::Video @@ -2100,7 +2100,7 @@ void OverlayWidget::validatePhotoCurrentImage() { validatePhotoImage(_photo->thumbnailInline(), true); if (_current.isNull()) { _photo->loadThumbnailSmall(fileOrigin()); - validatePhotoImage(Image::Blank().get(), true); + validatePhotoImage(Image::Empty(), true); } } diff --git a/Telegram/SourceFiles/ui/image/image.cpp b/Telegram/SourceFiles/ui/image/image.cpp index 055a70e65e..e6fc79460b 100644 --- a/Telegram/SourceFiles/ui/image/image.cpp +++ b/Telegram/SourceFiles/ui/image/image.cpp @@ -40,7 +40,7 @@ int64 ComputeUsage(const QImage &image) { return ComputeUsage(image.size()); } -Core::MediaActiveCache &ActiveCache() { +[[nodiscard]] Core::MediaActiveCache &ActiveCache() { static auto Instance = Core::MediaActiveCache( kMemoryForCache, [](const Image *image) { image->unload(); }); @@ -85,7 +85,7 @@ void ClearAll() { ImagePtr Create(const QString &file, QByteArray format) { if (file.startsWith(qstr("http://"), Qt::CaseInsensitive) || file.startsWith(qstr("https://"), Qt::CaseInsensitive)) { - const auto key = file; + const auto &key = file; auto i = WebUrlImages.constFind(key); if (i == WebUrlImages.cend()) { i = WebUrlImages.insert( @@ -208,7 +208,7 @@ QSize getImageSize(const QVector &attributes) { ImagePtr Create(const MTPDwebDocument &document) { const auto size = getImageSize(document.vattributes.v); if (size.isEmpty()) { - return Image::Blank(); + return ImagePtr(); } // We don't use size from WebDocument, because it is not reliable. @@ -227,7 +227,7 @@ ImagePtr Create(const MTPDwebDocument &document) { ImagePtr Create(const MTPDwebDocumentNoProxy &document) { const auto size = getImageSize(document.vattributes.v); if (size.isEmpty()) { - return Image::Blank(); + return ImagePtr(); } return Create(qs(document.vurl), size.width(), size.height()); @@ -236,7 +236,7 @@ ImagePtr Create(const MTPDwebDocumentNoProxy &document) { ImagePtr Create(const MTPDwebDocument &document, QSize box) { //const auto size = getImageSize(document.vattributes.v); //if (size.isEmpty()) { - // return Image::Blank(); + // return ImagePtr(); //} // We don't use size from WebDocument, because it is not reliable. @@ -254,7 +254,7 @@ ImagePtr Create(const MTPDwebDocument &document, QSize box) { ImagePtr Create(const MTPDwebDocumentNoProxy &document, QSize box) { //const auto size = getImageSize(document.vattributes.v); //if (size.isEmpty()) { - // return Image::Blank(); + // return ImagePtr(); //} return Create(qs(document.vurl), box); @@ -337,8 +337,8 @@ void Image::replaceSource(std::unique_ptr &&source) { _source = std::move(source); } -ImagePtr Image::Blank() { - static const auto blankImage = [] { +not_null Image::Empty() { + static auto result = [] { const auto factor = cIntRetinaFactor(); auto data = QImage( factor, @@ -346,15 +346,27 @@ ImagePtr Image::Blank() { QImage::Format_ARGB32_Premultiplied); data.fill(Qt::transparent); data.setDevicePixelRatio(cRetinaFactor()); - return Create( - std::move(data), - "GIF"); + return Image(std::make_unique(std::move(data), "GIF")); }(); - return blankImage; + return &result; +} + +not_null Image::BlankMedia() { + static auto result = [] { + const auto factor = cIntRetinaFactor(); + auto data = QImage( + factor, + factor, + QImage::Format_ARGB32_Premultiplied); + data.fill(Qt::black); + data.setDevicePixelRatio(cRetinaFactor()); + return Image(std::make_unique(std::move(data), "GIF")); + }(); + return &result; } bool Image::isNull() const { - return (this == Blank().get()); + return (this == Empty()); } const QPixmap &Image::pix( @@ -655,7 +667,7 @@ QPixmap Image::pixNoCache( if (h <= 0 && height() > 0) { h = qRound(width() * w / float64(height())); } - return Blank()->pixNoCache(origin, w, h, options, outerw, outerh); + return Empty()->pixNoCache(origin, w, h, options, outerw, outerh); } if (isNull() && outerw > 0 && outerh > 0) { @@ -713,7 +725,7 @@ QPixmap Image::pixColoredNoCache( checkSource(); if (_data.isNull()) { - return Blank()->pix(origin); + return Empty()->pix(origin); } auto img = _data; @@ -737,7 +749,7 @@ QPixmap Image::pixBlurredColoredNoCache( checkSource(); if (_data.isNull()) { - return Blank()->pix(origin); + return Empty()->pix(origin); } auto img = prepareBlur(_data); @@ -828,6 +840,8 @@ void Image::invalidateSizeCache() const { } Image::~Image() { - unload(); - ActiveCache().remove(this); + if (this != Empty() && this != BlankMedia()) { + unload(); + ActiveCache().remove(this); + } } diff --git a/Telegram/SourceFiles/ui/image/image.h b/Telegram/SourceFiles/ui/image/image.h index fcca87d0ca..609fbdacc3 100644 --- a/Telegram/SourceFiles/ui/image/image.h +++ b/Telegram/SourceFiles/ui/image/image.h @@ -100,7 +100,8 @@ public: void replaceSource(std::unique_ptr &&source); - static ImagePtr Blank(); + static not_null Empty(); // 1x1 transparent + static not_null BlankMedia(); // 1x1 black QImage original() const; diff --git a/Telegram/SourceFiles/ui/image/image_location.cpp b/Telegram/SourceFiles/ui/image/image_location.cpp index 21e3798e68..d50f47ff9d 100644 --- a/Telegram/SourceFiles/ui/image/image_location.cpp +++ b/Telegram/SourceFiles/ui/image/image_location.cpp @@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/image/image.h" #include "platform/platform_specific.h" -ImagePtr::ImagePtr() : _data(Image::Blank().get()) { +ImagePtr::ImagePtr() : _data(Image::Empty()) { } ImagePtr::ImagePtr(not_null data) : _data(data) {