mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-31 06:35:14 +00:00
Keep document byte data only in DocumentMedia.
This commit is contained in:
@@ -44,17 +44,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace {
|
||||
|
||||
// Updated Mar 3, 2020: Increase the size of the memory cache for media, to prevent items still being displayed from being unloaded.
|
||||
constexpr auto kMemoryForCache = 128 * 1024 * 1024; // was 32, updated to 128
|
||||
const auto kAnimatedStickerDimensions = QSize(512, 512);
|
||||
|
||||
Core::MediaActiveCache<DocumentData> &ActiveCache() {
|
||||
static auto Instance = Core::MediaActiveCache<DocumentData>(
|
||||
kMemoryForCache,
|
||||
[](DocumentData *document) { document->unload(); });
|
||||
return Instance;
|
||||
}
|
||||
|
||||
QString JoinStringList(const QStringList &list, const QString &separator) {
|
||||
const auto count = list.size();
|
||||
if (!count) {
|
||||
@@ -320,11 +311,12 @@ void DocumentOpenClickHandler::Open(
|
||||
}
|
||||
LaunchWithWarning(location.name(), context);
|
||||
};
|
||||
const auto media = data->createMediaView();
|
||||
const auto &location = data->location(true);
|
||||
if (data->isTheme() && data->loaded(true)) {
|
||||
if (data->isTheme() && media->loaded(true)) {
|
||||
Core::App().showDocument(data, context);
|
||||
location.accessDisable();
|
||||
} else if (data->canBePlayed()) {
|
||||
} else if (media->canBePlayed()) {
|
||||
if (data->isAudioFile()
|
||||
|| data->isVoiceMessage()
|
||||
|| data->isVideoMessage()) {
|
||||
@@ -458,7 +450,6 @@ DocumentData::DocumentData(not_null<Data::Session*> owner, DocumentId id)
|
||||
DocumentData::~DocumentData() {
|
||||
destroyLoader();
|
||||
unload();
|
||||
ActiveCache().remove(this);
|
||||
}
|
||||
|
||||
Data::Session &DocumentData::owner() const {
|
||||
@@ -578,7 +569,6 @@ void DocumentData::validateLottieSticker() {
|
||||
}
|
||||
|
||||
void DocumentData::setDataAndCache(const QByteArray &data) {
|
||||
_data = data;
|
||||
if (const auto media = activeMediaView()) {
|
||||
media->setBytes(data);
|
||||
}
|
||||
@@ -744,16 +734,13 @@ void DocumentData::unload() {
|
||||
//
|
||||
//_thumbnail->unload();
|
||||
_replyPreview = nullptr;
|
||||
if (!_data.isEmpty()) {
|
||||
ActiveCache().decrement(_data.size());
|
||||
_data.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentData::automaticLoad(
|
||||
Data::FileOrigin origin,
|
||||
const HistoryItem *item) {
|
||||
if (status != FileReady || loaded() || cancelled()) {
|
||||
const auto media = activeMediaView();
|
||||
if (status != FileReady || !media || media->loaded() || cancelled()) {
|
||||
return;
|
||||
} else if (!item && type != StickerDocument && !isAnimation()) {
|
||||
return;
|
||||
@@ -794,10 +781,6 @@ void DocumentData::automaticLoadSettingsChanged() {
|
||||
_flags &= ~Flag::DownloadCancelled;
|
||||
}
|
||||
|
||||
bool DocumentData::loaded(bool check) const {
|
||||
return !rawBytes().isEmpty() || !filepath(check).isEmpty();
|
||||
}
|
||||
|
||||
void DocumentData::finishLoad() {
|
||||
const auto guard = gsl::finally([&] {
|
||||
destroyLoader();
|
||||
@@ -807,18 +790,11 @@ void DocumentData::finishLoad() {
|
||||
return;
|
||||
}
|
||||
setLocation(FileLocation(_loader->fileName()));
|
||||
ActiveCache().decrement(_data.size());
|
||||
_data = _loader->bytes();
|
||||
ActiveCache().increment(_data.size());
|
||||
|
||||
setGoodThumbnailDataReady();
|
||||
if (const auto media = activeMediaView()) {
|
||||
media->setBytes(_loader->bytes());
|
||||
media->checkStickerLarge(_loader.get());
|
||||
}
|
||||
if (!_data.isEmpty()) {
|
||||
ActiveCache().up(this);
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentData::destroyLoader() const {
|
||||
@@ -854,7 +830,7 @@ float64 DocumentData::progress() const {
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
return loading() ? _loader->currentProgress() : (loaded() ? 1. : 0.);
|
||||
return loading() ? _loader->currentProgress() : 0.;
|
||||
}
|
||||
|
||||
int DocumentData::loadOffset() const {
|
||||
@@ -909,13 +885,13 @@ void DocumentData::save(
|
||||
const QString &toFile,
|
||||
LoadFromCloudSetting fromCloud,
|
||||
bool autoLoading) {
|
||||
if (loaded(true)) {
|
||||
if (const auto media = activeMediaView(); media->loaded(true)) {
|
||||
auto &l = location(true);
|
||||
if (!toFile.isEmpty()) {
|
||||
if (!rawBytes().isEmpty()) {
|
||||
if (!media->bytes().isEmpty()) {
|
||||
QFile f(toFile);
|
||||
f.open(QIODevice::WriteOnly);
|
||||
f.write(rawBytes());
|
||||
f.write(media->bytes());
|
||||
f.close();
|
||||
|
||||
setLocation(FileLocation(toFile));
|
||||
@@ -1108,13 +1084,6 @@ QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform) {
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray DocumentData::rawBytes() const {
|
||||
if (!_data.isEmpty()) {
|
||||
ActiveCache().up(const_cast<DocumentData*>(this));
|
||||
}
|
||||
return _data;
|
||||
}
|
||||
|
||||
const FileLocation &DocumentData::location(bool check) const {
|
||||
if (check && !_location.check()) {
|
||||
const auto location = Local::readFileLocation(mediaKey());
|
||||
@@ -1272,12 +1241,6 @@ bool DocumentData::canBeStreamed() const {
|
||||
return hasRemoteLocation() && supportsStreaming();
|
||||
}
|
||||
|
||||
bool DocumentData::canBePlayed() const {
|
||||
return !(_flags & Flag::StreamingPlaybackFailed)
|
||||
&& useStreamingLoader()
|
||||
&& (loaded() || canBeStreamed());
|
||||
}
|
||||
|
||||
void DocumentData::setInappPlaybackFailed() {
|
||||
_flags |= Flag::StreamingPlaybackFailed;
|
||||
}
|
||||
@@ -1294,9 +1257,10 @@ auto DocumentData::createStreamingLoader(
|
||||
return nullptr;
|
||||
}
|
||||
if (!forceRemoteLoader) {
|
||||
const auto media = activeMediaView();
|
||||
const auto &location = this->location(true);
|
||||
if (!rawBytes().isEmpty()) {
|
||||
return Media::Streaming::MakeBytesLoader(rawBytes());
|
||||
if (media && !media->bytes().isEmpty()) {
|
||||
return Media::Streaming::MakeBytesLoader(media->bytes());
|
||||
} else if (!location.isEmpty() && location.accessEnable()) {
|
||||
auto result = Media::Streaming::MakeFileLoader(location.name());
|
||||
location.accessDisable();
|
||||
@@ -1574,15 +1538,10 @@ void DocumentData::collectLocalData(not_null<DocumentData*> local) {
|
||||
}
|
||||
|
||||
_owner->cache().copyIfEmpty(local->cacheKey(), cacheKey());
|
||||
if (!local->_data.isEmpty()) {
|
||||
ActiveCache().decrement(_data.size());
|
||||
_data = local->_data;
|
||||
const auto localMedia = local->activeMediaView();
|
||||
if (!localMedia->bytes().isEmpty()) {
|
||||
if (const auto media = activeMediaView()) {
|
||||
media->setBytes(local->_data);
|
||||
}
|
||||
ActiveCache().increment(_data.size());
|
||||
if (!_data.isEmpty()) {
|
||||
ActiveCache().up(this);
|
||||
media->setBytes(localMedia->bytes());
|
||||
}
|
||||
}
|
||||
if (!local->_location.inMediaCache() && !local->_location.isEmpty()) {
|
||||
@@ -1672,13 +1631,13 @@ website ws wsc wsf wsh xbap xll xnk xs");
|
||||
}
|
||||
|
||||
base::binary_guard ReadImageAsync(
|
||||
not_null<DocumentData*> document,
|
||||
not_null<Data::DocumentMedia*> media,
|
||||
FnMut<QImage(QImage)> postprocess,
|
||||
FnMut<void(QImage&&)> done) {
|
||||
auto result = base::binary_guard();
|
||||
crl::async([
|
||||
bytes = document->rawBytes(),
|
||||
path = document->filepath(),
|
||||
bytes = media->bytes(),
|
||||
path = media->owner()->filepath(),
|
||||
postprocess = std::move(postprocess),
|
||||
guard = result.make_guard(),
|
||||
callback = std::move(done)
|
||||
|
@@ -100,7 +100,6 @@ public:
|
||||
const HistoryItem *item);
|
||||
void automaticLoadSettingsChanged();
|
||||
|
||||
[[nodiscard]] bool loaded(bool check = false) const;
|
||||
[[nodiscard]] bool loading() const;
|
||||
[[nodiscard]] QString loadingFilePath() const;
|
||||
[[nodiscard]] bool displayLoading() const;
|
||||
@@ -120,7 +119,6 @@ public:
|
||||
void setWaitingForAlbum();
|
||||
[[nodiscard]] bool waitingForAlbum() const;
|
||||
|
||||
[[nodiscard]] QByteArray rawBytes() const;
|
||||
[[nodiscard]] const FileLocation &location(bool check = false) const;
|
||||
void setLocation(const FileLocation &loc);
|
||||
|
||||
@@ -225,12 +223,12 @@ public:
|
||||
const QString &songPerformer);
|
||||
[[nodiscard]] QString composeNameString() const;
|
||||
|
||||
[[nodiscard]] bool canBePlayed() const;
|
||||
[[nodiscard]] bool canBeStreamed() const;
|
||||
[[nodiscard]] auto createStreamingLoader(
|
||||
Data::FileOrigin origin,
|
||||
bool forceRemoteLoader) const
|
||||
-> std::unique_ptr<Media::Streaming::Loader>;
|
||||
[[nodiscard]] bool useStreamingLoader() const;
|
||||
|
||||
void setInappPlaybackFailed();
|
||||
[[nodiscard]] bool inappPlaybackFailed() const;
|
||||
@@ -291,7 +289,6 @@ private:
|
||||
void handleLoaderUpdates();
|
||||
void destroyLoader() const;
|
||||
|
||||
[[nodiscard]] bool useStreamingLoader() const;
|
||||
bool saveFromDataChecked();
|
||||
|
||||
// Two types of location: from MTProto by dc+access or from web by url
|
||||
@@ -312,7 +309,6 @@ private:
|
||||
not_null<Data::Session*> _owner;
|
||||
|
||||
FileLocation _location;
|
||||
QByteArray _data;
|
||||
std::unique_ptr<DocumentAdditionalData> _additional;
|
||||
int32 _duration = -1;
|
||||
mutable Flags _flags = kStreamingSupportedUnknown;
|
||||
@@ -440,7 +436,7 @@ QString FileExtension(const QString &filepath);
|
||||
bool IsValidMediaFile(const QString &filepath);
|
||||
bool IsExecutableName(const QString &filepath);
|
||||
base::binary_guard ReadImageAsync(
|
||||
not_null<DocumentData*> document,
|
||||
not_null<Data::DocumentMedia*> media,
|
||||
FnMut<QImage(QImage)> postprocess,
|
||||
FnMut<void(QImage&&)> done);
|
||||
|
||||
|
@@ -82,8 +82,7 @@ enum class FileType {
|
||||
} // namespace
|
||||
|
||||
DocumentMedia::DocumentMedia(not_null<DocumentData*> owner)
|
||||
: _owner(owner)
|
||||
, _bytes(owner->rawBytes()) {
|
||||
: _owner(owner) {
|
||||
}
|
||||
|
||||
DocumentMedia::~DocumentMedia() = default;
|
||||
@@ -140,8 +139,7 @@ void DocumentMedia::checkStickerLarge() {
|
||||
if (data->animated || !loaded()) {
|
||||
return;
|
||||
}
|
||||
const auto bytes = _owner->rawBytes();
|
||||
if (bytes.isEmpty()) {
|
||||
if (_bytes.isEmpty()) {
|
||||
const auto &loc = _owner->location(true);
|
||||
if (loc.accessEnable()) {
|
||||
_sticker = std::make_unique<Image>(
|
||||
@@ -150,11 +148,11 @@ void DocumentMedia::checkStickerLarge() {
|
||||
}
|
||||
} else {
|
||||
auto format = QByteArray();
|
||||
auto image = App::readImage(bytes, &format, false);
|
||||
auto image = App::readImage(_bytes, &format, false);
|
||||
_sticker = std::make_unique<Image>(
|
||||
std::make_unique<Images::LocalFileSource>(
|
||||
QString(),
|
||||
bytes,
|
||||
_bytes,
|
||||
format,
|
||||
std::move(image)));
|
||||
}
|
||||
@@ -171,7 +169,19 @@ QByteArray DocumentMedia::bytes() const {
|
||||
}
|
||||
|
||||
bool DocumentMedia::loaded(bool check) const {
|
||||
return !_bytes.isEmpty() || _owner->loaded(check);// checkLoadedTo(this);
|
||||
return !_bytes.isEmpty() || !_owner->filepath(check).isEmpty();
|
||||
}
|
||||
|
||||
float64 DocumentMedia::progress() const {
|
||||
return (owner()->uploading() || owner()->loading())
|
||||
? owner()->progress()
|
||||
: (loaded() ? 1. : 0.);
|
||||
}
|
||||
|
||||
bool DocumentMedia::canBePlayed() const {
|
||||
return !owner()->inappPlaybackFailed()
|
||||
&& owner()->useStreamingLoader()
|
||||
&& (loaded() || owner()->canBeStreamed());
|
||||
}
|
||||
|
||||
void DocumentMedia::checkStickerSmall() {
|
||||
@@ -203,18 +213,19 @@ void DocumentMedia::checkStickerLarge(not_null<FileLoader*> loader) {
|
||||
if (_owner->sticker()
|
||||
&& !_sticker
|
||||
&& !loader->imageData().isNull()
|
||||
&& !_owner->rawBytes().isEmpty()) {
|
||||
&& !_bytes.isEmpty()) {
|
||||
_sticker = std::make_unique<Image>(
|
||||
std::make_unique<Images::LocalFileSource>(
|
||||
QString(),
|
||||
_owner->rawBytes(),
|
||||
_bytes,
|
||||
loader->imageFormat(),
|
||||
loader->imageData()));
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentMedia::GenerateGoodThumbnail(not_null<DocumentData*> document) {
|
||||
const auto data = document->rawBytes();
|
||||
void DocumentMedia::GenerateGoodThumbnail(
|
||||
not_null<DocumentData*> document,
|
||||
QByteArray data) {
|
||||
const auto type = document->isWallPaper()
|
||||
? FileType::WallPaper
|
||||
: document->isTheme()
|
||||
@@ -282,8 +293,9 @@ void DocumentMedia::ReadOrGenerateThumbnail(
|
||||
const auto active = document->activeMediaView();
|
||||
const auto got = [=](QByteArray value) {
|
||||
if (value.isEmpty()) {
|
||||
const auto bytes = active ? active->bytes() : QByteArray();
|
||||
crl::on_main(guard, [=] {
|
||||
GenerateGoodThumbnail(document);
|
||||
GenerateGoodThumbnail(document, bytes);
|
||||
});
|
||||
} else if (active) {
|
||||
crl::async([=] {
|
||||
|
@@ -35,6 +35,8 @@ public:
|
||||
void setBytes(const QByteArray &bytes);
|
||||
[[nodiscard]] QByteArray bytes() const;
|
||||
[[nodiscard]] bool loaded(bool check = false) const;
|
||||
[[nodiscard]] float64 progress() const;
|
||||
[[nodiscard]] bool canBePlayed() const;
|
||||
|
||||
// For DocumentData.
|
||||
static void CheckGoodThumbnail(not_null<DocumentData*> document);
|
||||
@@ -47,7 +49,9 @@ private:
|
||||
using Flags = base::flags<Flag>;
|
||||
|
||||
static void ReadOrGenerateThumbnail(not_null<DocumentData*> document);
|
||||
static void GenerateGoodThumbnail(not_null<DocumentData*> document);
|
||||
static void GenerateGoodThumbnail(
|
||||
not_null<DocumentData*> document,
|
||||
QByteArray data);
|
||||
|
||||
const not_null<DocumentData*> _owner;
|
||||
std::unique_ptr<Image> _goodThumbnail;
|
||||
|
Reference in New Issue
Block a user