summaryrefslogtreecommitdiff
path: root/vcl/source/graphic
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2023-04-03 09:34:54 +0100
committerMichael Meeks <michael.meeks@collabora.com>2023-05-05 18:47:03 +0200
commit0f2581204a70038ed7ca78089a9bd96d158e02c0 (patch)
tree7708448554efc524a2cf88d184e762fb22deb803 /vcl/source/graphic
parentd1999f23caf47a36786182adbe071619fd60f999 (diff)
BinaryDataContainer swap out implementation.
We can easily accumulate a large number of in-memory graphic objects, and swapping these as well as the un-compressed images can become important. For now we swap out the container when the image is swapped out, however it seems unlikely it will ever need to be swapped in again. Despite the shared pImpl, we retained the reference counting on the underling vector to keep this immutable while we hand out a MemoryStream reference to it. Change-Id: Ib7ca45afb8499460b1852461f7c11afca3f3cdfa Signed-off-by: Michael Meeks <michael.meeks@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151359 Tested-by: Jenkins
Diffstat (limited to 'vcl/source/graphic')
-rw-r--r--vcl/source/graphic/BinaryDataContainer.cxx117
1 files changed, 103 insertions, 14 deletions
diff --git a/vcl/source/graphic/BinaryDataContainer.cxx b/vcl/source/graphic/BinaryDataContainer.cxx
index b35195b7d27e..f395497f9449 100644
--- a/vcl/source/graphic/BinaryDataContainer.cxx
+++ b/vcl/source/graphic/BinaryDataContainer.cxx
@@ -10,21 +10,76 @@
#include <vcl/BinaryDataContainer.hxx>
#include <o3tl/hash_combine.hxx>
+#include <unotools/tempfile.hxx>
+#include <comphelper/lok.hxx>
+#include <sal/log.hxx>
+
+struct BinaryDataContainer::Impl
+{
+ // temp file to store the data out of RAM if necessary
+ std::unique_ptr<utl::TempFileNamed> mpFile;
+ // the binary data
+ std::shared_ptr<std::vector<sal_uInt8>> mpData;
+
+ Impl(SvStream& stream, size_t size) { readData(stream, size); }
+
+ /// Populate mpData from the stream
+ void readData(SvStream& stream, size_t size)
+ {
+ auto pData = std::make_shared<std::vector<sal_uInt8>>(size);
+ if (stream.ReadBytes(pData->data(), pData->size()) == size)
+ mpData = std::move(pData);
+ }
+
+ /// ensure the data is in-RAM
+ void ensureSwappedIn()
+ {
+ if (mpData || !mpFile)
+ return;
+
+ auto pStream = mpFile->GetStream(StreamMode::READ);
+ pStream->Seek(0);
+ readData(*pStream, pStream->remainingSize());
+
+ // Horrifying data loss ...
+ SAL_WARN_IF(pStream->GetError(), "vcl",
+ "Inconsistent system - failed to swap image back in");
+ SAL_DEBUG("Swap in: " << pStream->GetError());
+ }
+
+ void swapOut()
+ {
+ if (mpFile)
+ {
+ // we already have it swapped out.
+ mpData.reset();
+ return;
+ }
+
+ if (!mpData || mpData->empty())
+ return;
+
+ mpFile.reset(new utl::TempFileNamed());
+ auto pStream = mpFile->GetStream(StreamMode::READWRITE);
+
+ pStream->WriteBytes(mpData->data(), mpData->size());
+
+ mpData.reset();
+ }
+};
BinaryDataContainer::BinaryDataContainer(SvStream& stream, size_t size)
+ : mpImpl(new Impl(stream, size))
{
- auto pBuffer = std::make_shared<std::vector<sal_uInt8>>(size);
- if (stream.ReadBytes(pBuffer->data(), pBuffer->size()) == size)
- mpData = std::move(pBuffer);
}
size_t BinaryDataContainer::calculateHash() const
{
size_t nSeed = 0;
- if (mpData)
+ if (mpImpl && mpImpl->mpData && !mpImpl->mpData->empty())
{
o3tl::hash_combine(nSeed, getSize());
- for (sal_uInt8 const& rByte : *mpData)
+ for (sal_uInt8 const& rByte : *mpImpl->mpData)
o3tl::hash_combine(nSeed, rByte);
}
return nSeed;
@@ -34,10 +89,11 @@ css::uno::Sequence<sal_Int8> BinaryDataContainer::getCopyAsByteSequence() const
{
if (isEmpty())
return css::uno::Sequence<sal_Int8>();
+ assert(mpImpl);
css::uno::Sequence<sal_Int8> aData(getSize());
- std::copy(mpData->cbegin(), mpData->cend(), aData.getArray());
+ std::copy(mpImpl->mpData->cbegin(), mpImpl->mpData->cend(), aData.getArray());
return aData;
}
@@ -53,10 +109,9 @@ class ReferencedMemoryStream : public SvMemoryStream
std::shared_ptr<std::vector<sal_uInt8>> mpData;
public:
- ReferencedMemoryStream(const std::shared_ptr<std::vector<sal_uInt8>>& rData)
- : SvMemoryStream(rData ? rData->data() : nullptr, rData ? rData->size() : 0,
- StreamMode::READ)
- , mpData(rData)
+ ReferencedMemoryStream(const std::shared_ptr<std::vector<sal_uInt8>>& pData)
+ : SvMemoryStream(pData->data(), pData->size(), StreamMode::READ)
+ , mpData(pData)
{
}
};
@@ -64,18 +119,52 @@ public:
std::shared_ptr<SvStream> BinaryDataContainer::getAsStream()
{
- return std::make_shared<ReferencedMemoryStream>(mpData);
+ ensureSwappedIn(); // TODO: transfer in streamed chunks
+ return std::make_shared<ReferencedMemoryStream>(mpImpl->mpData);
}
std::size_t BinaryDataContainer::writeToStream(SvStream& rStream) const
{
+ ensureSwappedIn(); // TODO: transfer in streamed chunks
return rStream.WriteBytes(getData(), getSize());
}
-size_t BinaryDataContainer::getSize() const { return mpData ? mpData->size() : 0; }
+size_t BinaryDataContainer::getSize() const
+{
+ ensureSwappedIn();
+ return mpImpl && mpImpl->mpData ? mpImpl->mpData->size() : 0;
+}
+
+size_t BinaryDataContainer::getSizeBytes() const
+{
+ return mpImpl && mpImpl->mpData ? mpImpl->mpData->size() : 0;
+}
+
+bool BinaryDataContainer::isEmpty() const
+{
+ ensureSwappedIn();
+ return !mpImpl || !mpImpl->mpData || mpImpl->mpData->empty();
+}
+
+const sal_uInt8* BinaryDataContainer::getData() const
+{
+ ensureSwappedIn();
+ return mpImpl && mpImpl->mpData ? mpImpl->mpData->data() : nullptr;
+}
-bool BinaryDataContainer::isEmpty() const { return !mpData || mpData->empty(); }
+void BinaryDataContainer::ensureSwappedIn() const
+{
+ if (mpImpl)
+ mpImpl->ensureSwappedIn();
+}
+
+void BinaryDataContainer::swapOut() const
+{
+ // Only bother reducing memory footprint in kit mode - for mobile/online etc.
+ if (!mpImpl || !comphelper::LibreOfficeKit::isActive())
+ return;
-const sal_uInt8* BinaryDataContainer::getData() const { return mpData ? mpData->data() : nullptr; }
+ mpImpl->swapOut();
+}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */