Utils: Cleanup MarkdownBrowser cache handling

Change-Id: I4eb7fa7247645a5b2a8db3b6164d0a40f258e14e
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2024-11-27 12:17:50 +01:00
parent a106c1ef99
commit 1ccac26eb7

View File

@@ -183,6 +183,18 @@ public:
, m_entries(1024 * 1024 * 10) // 10 MB max image cache size , m_entries(1024 * 1024 * 10) // 10 MB max image cache size
{} {}
static Entry::Pointer makeEntry(const QByteArray &data, qsizetype maxSize)
{
// If the image is larger than what we allow in our cache,
// we still want to create an entry, but one with an empty image.
// So we clear it here, but still create the entry, so the painter can
// correctly show the "broken image" placeholder instead.
if (data.size() > maxSize)
return std::make_shared<Entry>(QByteArray());
return std::make_shared<Entry>(data);
}
virtual QSizeF intrinsicSize( virtual QSizeF intrinsicSize(
QTextDocument *doc, int posInDocument, const QTextFormat &format) override QTextDocument *doc, int posInDocument, const QTextFormat &format) override
{ {
@@ -229,15 +241,12 @@ public:
painter->drawImage(rect, (*entryPtr)->movie.currentImage()); painter->drawImage(rect, (*entryPtr)->movie.currentImage());
} }
void set(const QString &name, QByteArray data) void set(const QString &name, const QByteArray &data)
{ {
if (data.size() > m_entries.maxCost()) set(name, makeEntry(data, m_entries.maxCost()));
data.clear();
set(name, std::make_shared<Entry>(data));
} }
void set(const QString &name, Entry::Pointer entry) void set(const QString &name, const Entry::Pointer &entry)
{ {
entry->moveToThread(thread()); entry->moveToThread(thread());
@@ -247,12 +256,17 @@ public:
} }
const qint64 size = qMax(1, entry->buffer.size()); const qint64 size = qMax(1, entry->buffer.size());
if (size > m_entries.maxCost()) {
return;
}
Entry::Pointer *entryPtr = new Entry::Pointer(entry); Entry::Pointer *entryPtr = new Entry::Pointer(entry);
if (m_entries.insert(name, entryPtr, size)) if (m_entries.insert(name, entryPtr, size))
m_redraw(); m_redraw();
} }
void setMaximumCacheSize(qsizetype maxSize) { m_entries.setMaxCost(maxSize); } void setMaximumCacheSize(qsizetype maxSize) { m_entries.setMaxCost(maxSize); }
qsizetype maximumCacheSize() const { return m_entries.maxCost(); }
private: private:
std::function<void()> m_redraw; std::function<void()> m_redraw;
@@ -310,7 +324,13 @@ public:
if (!m_loadRemoteImages) if (!m_loadRemoteImages)
remoteUrls.clear(); remoteUrls.clear();
Storage<std::pair<QUrl, QByteArray>> remoteData; struct RemoteData
{
QUrl url;
QByteArray data;
};
Storage<RemoteData> remoteData;
const LoopList remoteIterator(Utils::toList(remoteUrls)); const LoopList remoteIterator(Utils::toList(remoteUrls));
const LoopList localIterator(Utils::toList(localUrls)); const LoopList localIterator(Utils::toList(localUrls));
@@ -327,7 +347,7 @@ public:
query.setRequest(request); query.setRequest(request);
query.setNetworkAccessManager(m_networkAccessManager); query.setNetworkAccessManager(m_networkAccessManager);
remoteData->first = *remoteIterator; remoteData->url = *remoteIterator;
}; };
auto onQueryDone = [this, remoteData](const NetworkQuery &query, DoneWith result) { auto onQueryDone = [this, remoteData](const NetworkQuery &query, DoneWith result) {
@@ -336,43 +356,49 @@ public:
m_urlsToLoad.remove(query.reply()->url()); m_urlsToLoad.remove(query.reply()->url());
if (result == DoneWith::Success) { if (result == DoneWith::Success) {
remoteData->second = query.reply()->readAll(); remoteData->data = query.reply()->readAll();
} else { } else {
m_imageHandler.set(remoteData->first.toString(), QByteArray{}); m_imageHandler.set(remoteData->url.toString(), QByteArray{});
markContentsDirty(0, this->characterCount()); markContentsDirty(0, this->characterCount());
} }
}; };
using EntryPointer = AnimatedImageHandler::Entry::Pointer; using EntryPointer = AnimatedImageHandler::Entry::Pointer;
auto onMakeEntrySetup = [remoteData](Async<EntryPointer> &async) { auto onMakeEntrySetup = [remoteData, maxSize = m_imageHandler.maximumCacheSize()](
Async<EntryPointer> &async) {
async.setConcurrentCallData( async.setConcurrentCallData(
[](const QByteArray &data) { [](const QByteArray &data, qsizetype maxSize) {
return std::make_shared<AnimatedImageHandler::Entry>(data); return AnimatedImageHandler::makeEntry(data, maxSize);
}, },
remoteData->second); remoteData->data,
maxSize);
}; };
auto onMakeEntryDone = auto onMakeEntryDone =
[this, remoteIterator, remoteData](const Async<EntryPointer> &async) { [this, remoteIterator, remoteData](const Async<EntryPointer> &async) {
EntryPointer result = async.result(); EntryPointer result = async.result();
if (result) { if (result) {
m_imageHandler.set(remoteData->first.toString(), result); m_imageHandler.set(remoteData->url.toString(), result);
markContentsDirty(0, this->characterCount()); markContentsDirty(0, this->characterCount());
} }
}; };
auto onLocalSetup = [localIterator, basePath = m_basePath](Async<EntryPointer> &async) { auto onLocalSetup = [localIterator,
const FilePath u = basePath.resolvePath(localIterator->path()); basePath = m_basePath,
maxSize = m_imageHandler.maximumCacheSize()](
Async<EntryPointer> &async) {
const FilePath path = basePath.resolvePath(localIterator->path());
async.setConcurrentCallData( async.setConcurrentCallData(
[](QPromise<EntryPointer> &promise, const FilePath &f) { [](QPromise<EntryPointer> &promise, const FilePath &path, qsizetype maxSize) {
auto data = f.fileContents(); auto data = path.fileContents();
if (!data || promise.isCanceled()) if (!data || promise.isCanceled())
return; return;
promise.addResult(std::make_shared<AnimatedImageHandler::Entry>(*data)); promise.addResult(AnimatedImageHandler::makeEntry(*data, maxSize));
}, },
u); path,
maxSize);
}; };
auto onLocalDone = [localIterator, this](const Async<EntryPointer> &async) { auto onLocalDone = [localIterator, this](const Async<EntryPointer> &async) {