mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Forget least used images gradually.
This commit is contained in:
parent
595134cab5
commit
f8eef7c9a6
10 changed files with 273 additions and 124 deletions
69
Telegram/SourceFiles/base/last_used_cache.h
Normal file
69
Telegram/SourceFiles/base/last_used_cache.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
template <typename Entry>
|
||||||
|
class last_used_cache {
|
||||||
|
public:
|
||||||
|
void up(Entry entry);
|
||||||
|
void remove(Entry entry);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
Entry take_lowest();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<Entry> _queue;
|
||||||
|
std::unordered_map<Entry, typename std::list<Entry>::iterator> _map;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Entry>
|
||||||
|
void last_used_cache<Entry>::up(Entry entry) {
|
||||||
|
if (!_queue.empty() && _queue.back() == entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto i = _map.find(entry);
|
||||||
|
if (i != end(_map)) {
|
||||||
|
_queue.splice(end(_queue), _queue, i->second);
|
||||||
|
} else {
|
||||||
|
_map.emplace(entry, _queue.insert(end(_queue), entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Entry>
|
||||||
|
void last_used_cache<Entry>::remove(Entry entry) {
|
||||||
|
const auto i = _map.find(entry);
|
||||||
|
if (i != end(_map)) {
|
||||||
|
_queue.erase(i->second);
|
||||||
|
_map.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Entry>
|
||||||
|
void last_used_cache<Entry>::clear() {
|
||||||
|
_queue.clear();
|
||||||
|
_map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Entry>
|
||||||
|
Entry last_used_cache<Entry>::take_lowest() {
|
||||||
|
if (_queue.empty()) {
|
||||||
|
return Entry();
|
||||||
|
}
|
||||||
|
auto result = std::move(_queue.front());
|
||||||
|
_queue.erase(begin(_queue));
|
||||||
|
_map.erase(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base
|
|
@ -691,9 +691,11 @@ StickersListWidget::StickersListWidget(QWidget *parent, not_null<Window::Control
|
||||||
_previewTimer.setSingleShot(true);
|
_previewTimer.setSingleShot(true);
|
||||||
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
|
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
|
||||||
|
|
||||||
subscribe(Auth().downloaderTaskFinished(), [this] {
|
subscribe(Auth().downloaderTaskFinished(), [=] {
|
||||||
update();
|
if (isVisible()) {
|
||||||
readVisibleSets();
|
update();
|
||||||
|
readVisibleSets();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::ChannelStickersChanged, [this](const Notify::PeerUpdate &update) {
|
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::ChannelStickersChanged, [this](const Notify::PeerUpdate &update) {
|
||||||
if (update.peer == _megagroupSet) {
|
if (update.peer == _megagroupSet) {
|
||||||
|
|
|
@ -246,7 +246,6 @@ enum {
|
||||||
WaitForSkippedTimeout = 1000, // 1s wait for skipped seq or pts in updates
|
WaitForSkippedTimeout = 1000, // 1s wait for skipped seq or pts in updates
|
||||||
WaitForChannelGetDifference = 1000, // 1s wait after show channel history before sending getChannelDifference
|
WaitForChannelGetDifference = 1000, // 1s wait after show channel history before sending getChannelDifference
|
||||||
|
|
||||||
MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory
|
|
||||||
IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle
|
IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle
|
||||||
|
|
||||||
SendViewsTimeout = 1000, // send views each second
|
SendViewsTimeout = 1000, // send views each second
|
||||||
|
|
84
Telegram/SourceFiles/core/media_active_cache.h
Normal file
84
Telegram/SourceFiles/core/media_active_cache.h
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/last_used_cache.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
class MediaActiveCache {
|
||||||
|
public:
|
||||||
|
template <typename Unload>
|
||||||
|
MediaActiveCache(int64 limit, Unload &&unload);
|
||||||
|
|
||||||
|
void up(Type *entry);
|
||||||
|
void remove(Type *entry);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void increment(int64 amount);
|
||||||
|
void decrement(int64 amount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Unload>
|
||||||
|
void check(Unload &&unload);
|
||||||
|
|
||||||
|
base::last_used_cache<Type*> _cache;
|
||||||
|
SingleQueuedInvokation _delayed;
|
||||||
|
int64 _usage = 0;
|
||||||
|
int64 _limit = 0;
|
||||||
|
Fn<void(Type*)> _unload;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
template <typename Unload>
|
||||||
|
MediaActiveCache<Type>::MediaActiveCache(int64 limit, Unload &&unload)
|
||||||
|
: _delayed([=] { check(unload); })
|
||||||
|
, _limit(limit) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
void MediaActiveCache<Type>::up(Type *entry) {
|
||||||
|
_cache.up(entry);
|
||||||
|
_delayed.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
void MediaActiveCache<Type>::remove(Type *entry) {
|
||||||
|
_cache.remove(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
void MediaActiveCache<Type>::clear() {
|
||||||
|
_cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
void MediaActiveCache<Type>::increment(int64 amount) {
|
||||||
|
_usage += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
void MediaActiveCache<Type>::decrement(int64 amount) {
|
||||||
|
_usage -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
template <typename Unload>
|
||||||
|
void MediaActiveCache<Type>::check(Unload &&unload) {
|
||||||
|
while (_usage > _limit) {
|
||||||
|
if (const auto entry = _cache.take_lowest()) {
|
||||||
|
unload(entry);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Images
|
|
@ -1262,7 +1262,6 @@ void History::mainViewRemoved(
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::newItemAdded(not_null<HistoryItem*> item) {
|
void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||||
Images::CheckCacheSize();
|
|
||||||
item->indexAsNewItem();
|
item->indexAsNewItem();
|
||||||
if (const auto from = item->from() ? item->from()->asUser() : nullptr) {
|
if (const auto from = item->from() ? item->from()->asUser() : nullptr) {
|
||||||
if (from == item->author()) {
|
if (from == item->author()) {
|
||||||
|
|
|
@ -2856,7 +2856,6 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onScroll() {
|
void HistoryWidget::onScroll() {
|
||||||
Images::CheckCacheSize();
|
|
||||||
preloadHistoryIfNeeded();
|
preloadHistoryIfNeeded();
|
||||||
visibleAreaUpdated();
|
visibleAreaUpdated();
|
||||||
if (!_synteticScrollEvent) {
|
if (!_synteticScrollEvent) {
|
||||||
|
|
|
@ -8,27 +8,51 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
|
|
||||||
#include "ui/image/image_source.h"
|
#include "ui/image/image_source.h"
|
||||||
|
#include "core/media_active_cache.h"
|
||||||
#include "storage/cache/storage_cache_database.h"
|
#include "storage/cache/storage_cache_database.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
|
|
||||||
|
using namespace Images;
|
||||||
|
|
||||||
namespace Images {
|
namespace Images {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// After 64MB of unpacked images we try to clear some memory.
|
||||||
|
constexpr auto kMemoryForCache = 64 * 1024 * 1024;
|
||||||
|
|
||||||
QMap<QString, Image*> LocalFileImages;
|
QMap<QString, Image*> LocalFileImages;
|
||||||
QMap<QString, Image*> WebUrlImages;
|
QMap<QString, Image*> WebUrlImages;
|
||||||
QMap<StorageKey, Image*> StorageImages;
|
QMap<StorageKey, Image*> StorageImages;
|
||||||
QMap<StorageKey, Image*> WebCachedImages;
|
QMap<StorageKey, Image*> WebCachedImages;
|
||||||
QMap<StorageKey, Image*> GeoPointImages;
|
QMap<StorageKey, Image*> GeoPointImages;
|
||||||
|
|
||||||
int64 GlobalAcquiredSize = 0;
|
int64 ComputeUsage(QSize size) {
|
||||||
int64 LocalAcquiredSize = 0;
|
return int64(size.width()) * size.height() * 4;
|
||||||
|
|
||||||
uint64 PixKey(int width, int height, Images::Options options) {
|
|
||||||
return static_cast<uint64>(width) | (static_cast<uint64>(height) << 24) | (static_cast<uint64>(options) << 48);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 SinglePixKey(Images::Options options) {
|
int64 ComputeUsage(const QPixmap &image) {
|
||||||
|
return ComputeUsage(image.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 ComputeUsage(const QImage &image) {
|
||||||
|
return ComputeUsage(image.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::MediaActiveCache<const Image> &ActiveCache() {
|
||||||
|
static auto Instance = Core::MediaActiveCache<const Image>(
|
||||||
|
kMemoryForCache,
|
||||||
|
[](const Image *image) { image->forget(); });
|
||||||
|
return Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 PixKey(int width, int height, Options options) {
|
||||||
|
return static_cast<uint64>(width)
|
||||||
|
| (static_cast<uint64>(height) << 24)
|
||||||
|
| (static_cast<uint64>(options) << 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 SinglePixKey(Options options) {
|
||||||
return PixKey(0, 0, options);
|
return PixKey(0, 0, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,24 +71,16 @@ void ClearRemote() {
|
||||||
for (auto image : base::take(GeoPointImages)) {
|
for (auto image : base::take(GeoPointImages)) {
|
||||||
delete image;
|
delete image;
|
||||||
}
|
}
|
||||||
LocalAcquiredSize = GlobalAcquiredSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearAll() {
|
void ClearAll() {
|
||||||
|
ActiveCache().clear();
|
||||||
for (auto image : base::take(LocalFileImages)) {
|
for (auto image : base::take(LocalFileImages)) {
|
||||||
delete image;
|
delete image;
|
||||||
}
|
}
|
||||||
ClearRemote();
|
ClearRemote();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckCacheSize() {
|
|
||||||
const auto now = GlobalAcquiredSize;
|
|
||||||
if (GlobalAcquiredSize > LocalAcquiredSize + MemoryForImageCache) {
|
|
||||||
Auth().data().forgetMedia();
|
|
||||||
LocalAcquiredSize = GlobalAcquiredSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagePtr Create(const QString &file, QByteArray format) {
|
ImagePtr Create(const QString &file, QByteArray format) {
|
||||||
if (file.startsWith(qstr("http://"), Qt::CaseInsensitive)
|
if (file.startsWith(qstr("http://"), Qt::CaseInsensitive)
|
||||||
|| file.startsWith(qstr("https://"), Qt::CaseInsensitive)) {
|
|| file.startsWith(qstr("https://"), Qt::CaseInsensitive)) {
|
||||||
|
@ -312,11 +328,11 @@ ImagePtr Create(const GeoPointLocation &location) {
|
||||||
|
|
||||||
} // namespace Images
|
} // namespace Images
|
||||||
|
|
||||||
Image::Image(std::unique_ptr<Images::Source> &&source)
|
Image::Image(std::unique_ptr<Source> &&source)
|
||||||
: _source(std::move(source)) {
|
: _source(std::move(source)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::replaceSource(std::unique_ptr<Images::Source> &&source) {
|
void Image::replaceSource(std::unique_ptr<Source> &&source) {
|
||||||
_source = std::move(source);
|
_source = std::move(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +345,7 @@ ImagePtr Image::Blank() {
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
data.fill(Qt::transparent);
|
data.fill(Qt::transparent);
|
||||||
data.setDevicePixelRatio(cRetinaFactor());
|
data.setDevicePixelRatio(cRetinaFactor());
|
||||||
return Images::Create(
|
return Create(
|
||||||
std::move(data),
|
std::move(data),
|
||||||
"GIF");
|
"GIF");
|
||||||
}();
|
}();
|
||||||
|
@ -352,16 +368,14 @@ const QPixmap &Image::pix(
|
||||||
w *= cIntRetinaFactor();
|
w *= cIntRetinaFactor();
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
auto options = Images::Option::Smooth | Images::Option::None;
|
auto options = Option::Smooth | Option::None;
|
||||||
auto k = Images::PixKey(w, h, options);
|
auto k = PixKey(w, h, options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend()) {
|
if (i == _sizesCache.cend()) {
|
||||||
auto p = pixNoCache(origin, w, h, options);
|
auto p = pixNoCache(origin, w, h, options);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -380,29 +394,27 @@ const QPixmap &Image::pixRounded(
|
||||||
w *= cIntRetinaFactor();
|
w *= cIntRetinaFactor();
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
auto options = Images::Option::Smooth | Images::Option::None;
|
auto options = Option::Smooth | Option::None;
|
||||||
auto cornerOptions = [](RectParts corners) {
|
auto cornerOptions = [](RectParts corners) {
|
||||||
return (corners & RectPart::TopLeft ? Images::Option::RoundedTopLeft : Images::Option::None)
|
return (corners & RectPart::TopLeft ? Option::RoundedTopLeft : Option::None)
|
||||||
| (corners & RectPart::TopRight ? Images::Option::RoundedTopRight : Images::Option::None)
|
| (corners & RectPart::TopRight ? Option::RoundedTopRight : Option::None)
|
||||||
| (corners & RectPart::BottomLeft ? Images::Option::RoundedBottomLeft : Images::Option::None)
|
| (corners & RectPart::BottomLeft ? Option::RoundedBottomLeft : Option::None)
|
||||||
| (corners & RectPart::BottomRight ? Images::Option::RoundedBottomRight : Images::Option::None);
|
| (corners & RectPart::BottomRight ? Option::RoundedBottomRight : Option::None);
|
||||||
};
|
};
|
||||||
if (radius == ImageRoundRadius::Large) {
|
if (radius == ImageRoundRadius::Large) {
|
||||||
options |= Images::Option::RoundedLarge | cornerOptions(corners);
|
options |= Option::RoundedLarge | cornerOptions(corners);
|
||||||
} else if (radius == ImageRoundRadius::Small) {
|
} else if (radius == ImageRoundRadius::Small) {
|
||||||
options |= Images::Option::RoundedSmall | cornerOptions(corners);
|
options |= Option::RoundedSmall | cornerOptions(corners);
|
||||||
} else if (radius == ImageRoundRadius::Ellipse) {
|
} else if (radius == ImageRoundRadius::Ellipse) {
|
||||||
options |= Images::Option::Circled | cornerOptions(corners);
|
options |= Option::Circled | cornerOptions(corners);
|
||||||
}
|
}
|
||||||
auto k = Images::PixKey(w, h, options);
|
auto k = PixKey(w, h, options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend()) {
|
if (i == _sizesCache.cend()) {
|
||||||
auto p = pixNoCache(origin, w, h, options);
|
auto p = pixNoCache(origin, w, h, options);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -419,16 +431,14 @@ const QPixmap &Image::pixCircled(
|
||||||
w *= cIntRetinaFactor();
|
w *= cIntRetinaFactor();
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
auto options = Images::Option::Smooth | Images::Option::Circled;
|
auto options = Option::Smooth | Option::Circled;
|
||||||
auto k = Images::PixKey(w, h, options);
|
auto k = PixKey(w, h, options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend()) {
|
if (i == _sizesCache.cend()) {
|
||||||
auto p = pixNoCache(origin, w, h, options);
|
auto p = pixNoCache(origin, w, h, options);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -445,16 +455,14 @@ const QPixmap &Image::pixBlurredCircled(
|
||||||
w *= cIntRetinaFactor();
|
w *= cIntRetinaFactor();
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
auto options = Images::Option::Smooth | Images::Option::Circled | Images::Option::Blurred;
|
auto options = Option::Smooth | Option::Circled | Option::Blurred;
|
||||||
auto k = Images::PixKey(w, h, options);
|
auto k = PixKey(w, h, options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend()) {
|
if (i == _sizesCache.cend()) {
|
||||||
auto p = pixNoCache(origin, w, h, options);
|
auto p = pixNoCache(origin, w, h, options);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -471,16 +479,14 @@ const QPixmap &Image::pixBlurred(
|
||||||
w *= cIntRetinaFactor();
|
w *= cIntRetinaFactor();
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
auto options = Images::Option::Smooth | Images::Option::Blurred;
|
auto options = Option::Smooth | Option::Blurred;
|
||||||
auto k = Images::PixKey(w, h, options);
|
auto k = PixKey(w, h, options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend()) {
|
if (i == _sizesCache.cend()) {
|
||||||
auto p = pixNoCache(origin, w, h, options);
|
auto p = pixNoCache(origin, w, h, options);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -498,16 +504,14 @@ const QPixmap &Image::pixColored(
|
||||||
w *= cIntRetinaFactor();
|
w *= cIntRetinaFactor();
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
auto options = Images::Option::Smooth | Images::Option::Colored;
|
auto options = Option::Smooth | Option::Colored;
|
||||||
auto k = Images::PixKey(w, h, options);
|
auto k = PixKey(w, h, options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend()) {
|
if (i == _sizesCache.cend()) {
|
||||||
auto p = pixColoredNoCache(origin, add, w, h, true);
|
auto p = pixColoredNoCache(origin, add, w, h, true);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -525,16 +529,14 @@ const QPixmap &Image::pixBlurredColored(
|
||||||
w *= cIntRetinaFactor();
|
w *= cIntRetinaFactor();
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
auto options = Images::Option::Blurred | Images::Option::Smooth | Images::Option::Colored;
|
auto options = Option::Blurred | Option::Smooth | Option::Colored;
|
||||||
auto k = Images::PixKey(w, h, options);
|
auto k = PixKey(w, h, options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend()) {
|
if (i == _sizesCache.cend()) {
|
||||||
auto p = pixBlurredColoredNoCache(origin, add, w, h);
|
auto p = pixBlurredColoredNoCache(origin, add, w, h);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -557,36 +559,34 @@ const QPixmap &Image::pixSingle(
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto options = Images::Option::Smooth | Images::Option::None;
|
auto options = Option::Smooth | Option::None;
|
||||||
auto cornerOptions = [](RectParts corners) {
|
auto cornerOptions = [](RectParts corners) {
|
||||||
return (corners & RectPart::TopLeft ? Images::Option::RoundedTopLeft : Images::Option::None)
|
return (corners & RectPart::TopLeft ? Option::RoundedTopLeft : Option::None)
|
||||||
| (corners & RectPart::TopRight ? Images::Option::RoundedTopRight : Images::Option::None)
|
| (corners & RectPart::TopRight ? Option::RoundedTopRight : Option::None)
|
||||||
| (corners & RectPart::BottomLeft ? Images::Option::RoundedBottomLeft : Images::Option::None)
|
| (corners & RectPart::BottomLeft ? Option::RoundedBottomLeft : Option::None)
|
||||||
| (corners & RectPart::BottomRight ? Images::Option::RoundedBottomRight : Images::Option::None);
|
| (corners & RectPart::BottomRight ? Option::RoundedBottomRight : Option::None);
|
||||||
};
|
};
|
||||||
if (radius == ImageRoundRadius::Large) {
|
if (radius == ImageRoundRadius::Large) {
|
||||||
options |= Images::Option::RoundedLarge | cornerOptions(corners);
|
options |= Option::RoundedLarge | cornerOptions(corners);
|
||||||
} else if (radius == ImageRoundRadius::Small) {
|
} else if (radius == ImageRoundRadius::Small) {
|
||||||
options |= Images::Option::RoundedSmall | cornerOptions(corners);
|
options |= Option::RoundedSmall | cornerOptions(corners);
|
||||||
} else if (radius == ImageRoundRadius::Ellipse) {
|
} else if (radius == ImageRoundRadius::Ellipse) {
|
||||||
options |= Images::Option::Circled | cornerOptions(corners);
|
options |= Option::Circled | cornerOptions(corners);
|
||||||
}
|
}
|
||||||
if (colored) {
|
if (colored) {
|
||||||
options |= Images::Option::Colored;
|
options |= Option::Colored;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto k = Images::SinglePixKey(options);
|
auto k = SinglePixKey(options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
||||||
if (i != _sizesCache.cend()) {
|
if (i != _sizesCache.cend()) {
|
||||||
Images::GlobalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
ActiveCache().decrement(ComputeUsage(*i));
|
||||||
}
|
}
|
||||||
auto p = pixNoCache(origin, w, h, options, outerw, outerh, colored);
|
auto p = pixNoCache(origin, w, h, options, outerw, outerh, colored);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -608,33 +608,31 @@ const QPixmap &Image::pixBlurredSingle(
|
||||||
h *= cIntRetinaFactor();
|
h *= cIntRetinaFactor();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto options = Images::Option::Smooth | Images::Option::Blurred;
|
auto options = Option::Smooth | Option::Blurred;
|
||||||
auto cornerOptions = [](RectParts corners) {
|
auto cornerOptions = [](RectParts corners) {
|
||||||
return (corners & RectPart::TopLeft ? Images::Option::RoundedTopLeft : Images::Option::None)
|
return (corners & RectPart::TopLeft ? Option::RoundedTopLeft : Option::None)
|
||||||
| (corners & RectPart::TopRight ? Images::Option::RoundedTopRight : Images::Option::None)
|
| (corners & RectPart::TopRight ? Option::RoundedTopRight : Option::None)
|
||||||
| (corners & RectPart::BottomLeft ? Images::Option::RoundedBottomLeft : Images::Option::None)
|
| (corners & RectPart::BottomLeft ? Option::RoundedBottomLeft : Option::None)
|
||||||
| (corners & RectPart::BottomRight ? Images::Option::RoundedBottomRight : Images::Option::None);
|
| (corners & RectPart::BottomRight ? Option::RoundedBottomRight : Option::None);
|
||||||
};
|
};
|
||||||
if (radius == ImageRoundRadius::Large) {
|
if (radius == ImageRoundRadius::Large) {
|
||||||
options |= Images::Option::RoundedLarge | cornerOptions(corners);
|
options |= Option::RoundedLarge | cornerOptions(corners);
|
||||||
} else if (radius == ImageRoundRadius::Small) {
|
} else if (radius == ImageRoundRadius::Small) {
|
||||||
options |= Images::Option::RoundedSmall | cornerOptions(corners);
|
options |= Option::RoundedSmall | cornerOptions(corners);
|
||||||
} else if (radius == ImageRoundRadius::Ellipse) {
|
} else if (radius == ImageRoundRadius::Ellipse) {
|
||||||
options |= Images::Option::Circled | cornerOptions(corners);
|
options |= Option::Circled | cornerOptions(corners);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto k = Images::SinglePixKey(options);
|
auto k = SinglePixKey(options);
|
||||||
auto i = _sizesCache.constFind(k);
|
auto i = _sizesCache.constFind(k);
|
||||||
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
||||||
if (i != _sizesCache.cend()) {
|
if (i != _sizesCache.cend()) {
|
||||||
Images::GlobalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
ActiveCache().decrement(ComputeUsage(*i));
|
||||||
}
|
}
|
||||||
auto p = pixNoCache(origin, w, h, options, outerw, outerh);
|
auto p = pixNoCache(origin, w, h, options, outerw, outerh);
|
||||||
p.setDevicePixelRatio(cRetinaFactor());
|
p.setDevicePixelRatio(cRetinaFactor());
|
||||||
i = _sizesCache.insert(k, p);
|
i = _sizesCache.insert(k, p);
|
||||||
if (!p.isNull()) {
|
ActiveCache().increment(ComputeUsage(*i));
|
||||||
Images::GlobalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
@ -643,7 +641,7 @@ QPixmap Image::pixNoCache(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
int w,
|
int w,
|
||||||
int h,
|
int h,
|
||||||
Images::Options options,
|
Options options,
|
||||||
int outerw,
|
int outerw,
|
||||||
int outerh,
|
int outerh,
|
||||||
const style::color *colored) const {
|
const style::color *colored) const {
|
||||||
|
@ -679,27 +677,27 @@ QPixmap Image::pixNoCache(
|
||||||
p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::imageBgTransparent);
|
p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::imageBgTransparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto corners = [](Images::Options options) {
|
auto corners = [](Options options) {
|
||||||
return ((options & Images::Option::RoundedTopLeft) ? RectPart::TopLeft : RectPart::None)
|
return ((options & Option::RoundedTopLeft) ? RectPart::TopLeft : RectPart::None)
|
||||||
| ((options & Images::Option::RoundedTopRight) ? RectPart::TopRight : RectPart::None)
|
| ((options & Option::RoundedTopRight) ? RectPart::TopRight : RectPart::None)
|
||||||
| ((options & Images::Option::RoundedBottomLeft) ? RectPart::BottomLeft : RectPart::None)
|
| ((options & Option::RoundedBottomLeft) ? RectPart::BottomLeft : RectPart::None)
|
||||||
| ((options & Images::Option::RoundedBottomRight) ? RectPart::BottomRight : RectPart::None);
|
| ((options & Option::RoundedBottomRight) ? RectPart::BottomRight : RectPart::None);
|
||||||
};
|
};
|
||||||
if (options & Images::Option::Circled) {
|
if (options & Option::Circled) {
|
||||||
Images::prepareCircle(result);
|
prepareCircle(result);
|
||||||
} else if (options & Images::Option::RoundedLarge) {
|
} else if (options & Option::RoundedLarge) {
|
||||||
Images::prepareRound(result, ImageRoundRadius::Large, corners(options));
|
prepareRound(result, ImageRoundRadius::Large, corners(options));
|
||||||
} else if (options & Images::Option::RoundedSmall) {
|
} else if (options & Option::RoundedSmall) {
|
||||||
Images::prepareRound(result, ImageRoundRadius::Small, corners(options));
|
prepareRound(result, ImageRoundRadius::Small, corners(options));
|
||||||
}
|
}
|
||||||
if (options & Images::Option::Colored) {
|
if (options & Option::Colored) {
|
||||||
Assert(colored != nullptr);
|
Assert(colored != nullptr);
|
||||||
result = Images::prepareColored(*colored, std::move(result));
|
result = prepareColored(*colored, std::move(result));
|
||||||
}
|
}
|
||||||
return App::pixmapFromImageInPlace(std::move(result));
|
return App::pixmapFromImageInPlace(std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
return App::pixmapFromImageInPlace(Images::prepare(_data, w, h, options, outerw, outerh, colored));
|
return App::pixmapFromImageInPlace(prepare(_data, w, h, options, outerw, outerh, colored));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap Image::pixColoredNoCache(
|
QPixmap Image::pixColoredNoCache(
|
||||||
|
@ -719,12 +717,12 @@ QPixmap Image::pixColoredNoCache(
|
||||||
|
|
||||||
auto img = _data;
|
auto img = _data;
|
||||||
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) {
|
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) {
|
||||||
return App::pixmapFromImageInPlace(Images::prepareColored(add, std::move(img)));
|
return App::pixmapFromImageInPlace(prepareColored(add, std::move(img)));
|
||||||
}
|
}
|
||||||
if (h <= 0) {
|
if (h <= 0) {
|
||||||
return App::pixmapFromImageInPlace(Images::prepareColored(add, img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)));
|
return App::pixmapFromImageInPlace(prepareColored(add, img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)));
|
||||||
}
|
}
|
||||||
return App::pixmapFromImageInPlace(Images::prepareColored(add, img.scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)));
|
return App::pixmapFromImageInPlace(prepareColored(add, img.scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap Image::pixBlurredColoredNoCache(
|
QPixmap Image::pixBlurredColoredNoCache(
|
||||||
|
@ -741,14 +739,14 @@ QPixmap Image::pixBlurredColoredNoCache(
|
||||||
return Blank()->pix(origin);
|
return Blank()->pix(origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto img = Images::prepareBlur(_data);
|
auto img = prepareBlur(_data);
|
||||||
if (h <= 0) {
|
if (h <= 0) {
|
||||||
img = img.scaledToWidth(w, Qt::SmoothTransformation);
|
img = img.scaledToWidth(w, Qt::SmoothTransformation);
|
||||||
} else {
|
} else {
|
||||||
img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return App::pixmapFromImageInPlace(Images::prepareColored(add, img));
|
return App::pixmapFromImageInPlace(prepareColored(add, img));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Storage::Cache::Key> Image::cacheKey() const {
|
std::optional<Storage::Cache::Key> Image::cacheKey() const {
|
||||||
|
@ -765,20 +763,18 @@ void Image::checkSource() const {
|
||||||
if (_data.isNull() && !data.isNull()) {
|
if (_data.isNull() && !data.isNull()) {
|
||||||
invalidateSizeCache();
|
invalidateSizeCache();
|
||||||
_data = std::move(data);
|
_data = std::move(data);
|
||||||
if (!_data.isNull()) {
|
ActiveCache().increment(ComputeUsage(_data));
|
||||||
Images::GlobalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActiveCache().up(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::forget() const {
|
void Image::forget() const {
|
||||||
_source->takeLoaded();
|
_source->takeLoaded();
|
||||||
_source->forget();
|
_source->forget();
|
||||||
invalidateSizeCache();
|
invalidateSizeCache();
|
||||||
if (!_data.isNull()) {
|
ActiveCache().decrement(ComputeUsage(_data));
|
||||||
Images::GlobalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
|
_data = QImage();
|
||||||
_data = QImage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::setDelayedStorageLocation(
|
void Image::setDelayedStorageLocation(
|
||||||
|
@ -796,14 +792,14 @@ void Image::setImageBytes(const QByteArray &bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::invalidateSizeCache() const {
|
void Image::invalidateSizeCache() const {
|
||||||
|
auto &cache = ActiveCache();
|
||||||
for (const auto &image : std::as_const(_sizesCache)) {
|
for (const auto &image : std::as_const(_sizesCache)) {
|
||||||
if (!image.isNull()) {
|
cache.decrement(ComputeUsage(image));
|
||||||
Images::GlobalAcquiredSize -= int64(image.width()) * image.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_sizesCache.clear();
|
_sizesCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::~Image() {
|
Image::~Image() {
|
||||||
forget();
|
forget();
|
||||||
|
ActiveCache().remove(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ namespace Images {
|
||||||
|
|
||||||
void ClearRemote();
|
void ClearRemote();
|
||||||
void ClearAll();
|
void ClearAll();
|
||||||
void CheckCacheSize();
|
|
||||||
|
|
||||||
ImagePtr Create(const QString &file, QByteArray format);
|
ImagePtr Create(const QString &file, QByteArray format);
|
||||||
ImagePtr Create(const QString &url, QSize box);
|
ImagePtr Create(const QString &url, QSize box);
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
'<(src_loc)/base/flat_set.h',
|
'<(src_loc)/base/flat_set.h',
|
||||||
'<(src_loc)/base/functors.h',
|
'<(src_loc)/base/functors.h',
|
||||||
'<(src_loc)/base/index_based_iterator.h',
|
'<(src_loc)/base/index_based_iterator.h',
|
||||||
|
'<(src_loc)/base/last_used_cache.h',
|
||||||
'<(src_loc)/base/match_method.h',
|
'<(src_loc)/base/match_method.h',
|
||||||
'<(src_loc)/base/observer.cpp',
|
'<(src_loc)/base/observer.cpp',
|
||||||
'<(src_loc)/base/observer.h',
|
'<(src_loc)/base/observer.h',
|
||||||
|
|
|
@ -119,6 +119,7 @@
|
||||||
<(src_loc)/core/launcher.h
|
<(src_loc)/core/launcher.h
|
||||||
<(src_loc)/core/main_queue_processor.cpp
|
<(src_loc)/core/main_queue_processor.cpp
|
||||||
<(src_loc)/core/main_queue_processor.h
|
<(src_loc)/core/main_queue_processor.h
|
||||||
|
<(src_loc)/core/media_active_cache.h
|
||||||
<(src_loc)/core/mime_type.cpp
|
<(src_loc)/core/mime_type.cpp
|
||||||
<(src_loc)/core/mime_type.h
|
<(src_loc)/core/mime_type.h
|
||||||
<(src_loc)/core/single_timer.cpp
|
<(src_loc)/core/single_timer.cpp
|
||||||
|
|
Loading…
Add table
Reference in a new issue