LibreOffice Module vcl (master) 1
Manager.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <graphic/Manager.hxx>
21#include <impgraph.hxx>
22#include <sal/log.hxx>
23
24#include <officecfg/Office/Common.hxx>
26
27using namespace css;
28
29namespace vcl::graphic
30{
31namespace
32{
33void setupConfigurationValuesIfPossible(sal_Int64& rMemoryLimit,
34 std::chrono::seconds& rAllowedIdleTime, bool& bSwapEnabled)
35{
37 return;
38
39 try
40 {
41 using officecfg::Office::Common::Cache;
42
43 rMemoryLimit = Cache::GraphicManager::GraphicMemoryLimit::get();
44 rAllowedIdleTime
45 = std::chrono::seconds(Cache::GraphicManager::GraphicAllowedIdleTime::get());
46 bSwapEnabled = Cache::GraphicManager::GraphicSwappingEnabled::get();
47 }
48 catch (...)
49 {
50 }
51}
52}
53
55{
56 static Manager gStaticManager;
57 return gStaticManager;
58}
59
61 : mnAllowedIdleTime(10)
62 , mbSwapEnabled(true)
63 , mbReducingGraphicMemory(false)
64 , mnMemoryLimit(300000000)
65 , mnUsedSize(0)
66 , maSwapOutTimer("graphic::Manager maSwapOutTimer")
67{
68 setupConfigurationValuesIfPossible(mnMemoryLimit, mnAllowedIdleTime, mbSwapEnabled);
69
70 if (mbSwapEnabled)
71 {
72 maSwapOutTimer.SetInvokeHandler(LINK(this, Manager, SwapOutTimerHandler));
75 }
76}
77
78void Manager::loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard, bool bDropAll)
79{
80 // make a copy of m_pImpGraphicList because if we swap out a svg, the svg
81 // filter may create more temp Graphics which are auto-added to
82 // m_pImpGraphicList invalidating a loop over m_pImpGraphicList, e.g.
83 // reexport of tdf118346-1.odg
85
86 for (ImpGraphic* pEachImpGraphic : aImpGraphicList)
87 {
88 if (mnUsedSize < sal_Int64(mnMemoryLimit * 0.7) && !bDropAll)
89 return;
90
91 if (pEachImpGraphic->isSwappedOut())
92 continue;
93
94 sal_Int64 nCurrentGraphicSize = getGraphicSizeBytes(pEachImpGraphic);
95 if (nCurrentGraphicSize > 100000 || bDropAll)
96 {
97 if (!pEachImpGraphic->mpContext)
98 {
99 auto aCurrent = std::chrono::high_resolution_clock::now();
100 auto aDeltaTime = aCurrent - pEachImpGraphic->maLastUsed;
101 auto aSeconds = std::chrono::duration_cast<std::chrono::seconds>(aDeltaTime);
102
103 if (aSeconds > mnAllowedIdleTime)
104 {
105 // unlock because svgio can call back into us
106 rGuard.unlock();
107 pEachImpGraphic->swapOut();
108 rGuard.lock();
109 }
110 }
111 }
112 }
113}
114
115void Manager::reduceGraphicMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll)
116{
117 // maMutex is locked in callers
118
119 if (!mbSwapEnabled)
120 return;
121
122 if (mnUsedSize < mnMemoryLimit && !bDropAll)
123 return;
124
125 // avoid recursive reduceGraphicMemory on reexport of tdf118346-1.odg to odg
127 return;
128
130
131 loopGraphicsAndSwapOut(rGuard, bDropAll);
132
133 sal_Int64 calculatedSize = 0;
134 for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
135 {
136 if (!pEachImpGraphic->isSwappedOut())
137 {
138 calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
139 }
140 }
141
142 if (calculatedSize != mnUsedSize)
143 {
144 assert(rGuard.owns_lock() && rGuard.mutex() == &maMutex);
145 // coverity[missing_lock: FALSE] - as above assert
146 mnUsedSize = calculatedSize;
147 }
148
150}
151
153{
154 std::unique_lock aGuard(maMutex);
155
156 reduceGraphicMemory(aGuard, true);
157}
158
159void Manager::dumpState(rtl::OStringBuffer& rState)
160{
161 std::unique_lock aGuard(maMutex);
162
163 rState.append("\nImage Manager items:\t");
164 rState.append(static_cast<sal_Int32>(m_pImpGraphicList.size()));
165 rState.append("\tsize:\t");
166 rState.append(static_cast<sal_Int64>(mnUsedSize / 1024));
167 rState.append("\tkb");
168
169 for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
170 {
171 pEachImpGraphic->dumpState(rState);
172 }
173}
174
175sal_Int64 Manager::getGraphicSizeBytes(const ImpGraphic* pImpGraphic)
176{
177 if (!pImpGraphic->isAvailable())
178 return 0;
179 return pImpGraphic->getSizeBytes();
180}
181
182IMPL_LINK(Manager, SwapOutTimerHandler, Timer*, pTimer, void)
183{
184 std::unique_lock aGuard(maMutex);
185
186 pTimer->Stop();
187 reduceGraphicMemory(aGuard);
188 pTimer->Start();
189}
190
191void Manager::registerGraphic(const std::shared_ptr<ImpGraphic>& pImpGraphic)
192{
193 std::unique_lock aGuard(maMutex);
194
195 // make some space first
197 reduceGraphicMemory(aGuard);
198
199 // Insert and update the used size (bytes)
200 assert(aGuard.owns_lock() && aGuard.mutex() == &maMutex);
201 // coverity[missing_lock: FALSE] - as above assert
202 mnUsedSize += getGraphicSizeBytes(pImpGraphic.get());
203 m_pImpGraphicList.insert(pImpGraphic.get());
204
205 // calculate size of the graphic set
206 sal_Int64 calculatedSize = 0;
207 for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
208 {
209 if (!pEachImpGraphic->isSwappedOut())
210 {
211 calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
212 }
213 }
214
215 if (calculatedSize != mnUsedSize)
216 {
217 SAL_INFO_IF(calculatedSize != mnUsedSize, "vcl.gdi",
218 "Calculated size mismatch. Variable size is '"
219 << mnUsedSize << "' but calculated size is '" << calculatedSize << "'");
220 mnUsedSize = calculatedSize;
221 }
222}
223
225{
226 std::scoped_lock aGuard(maMutex);
227
228 mnUsedSize -= getGraphicSizeBytes(pImpGraphic);
229 m_pImpGraphicList.erase(pImpGraphic);
230}
231
232std::shared_ptr<ImpGraphic> Manager::copy(std::shared_ptr<ImpGraphic> const& rImpGraphicPtr)
233{
234 auto pReturn = std::make_shared<ImpGraphic>(*rImpGraphicPtr);
235 registerGraphic(pReturn);
236 return pReturn;
237}
238
239std::shared_ptr<ImpGraphic> Manager::newInstance()
240{
241 auto pReturn = std::make_shared<ImpGraphic>();
242 registerGraphic(pReturn);
243 return pReturn;
244}
245
246std::shared_ptr<ImpGraphic> Manager::newInstance(std::shared_ptr<GfxLink> const& rGfxLink,
247 sal_Int32 nPageIndex)
248{
249 auto pReturn = std::make_shared<ImpGraphic>(rGfxLink, nPageIndex);
250 registerGraphic(pReturn);
251 return pReturn;
252}
253
254std::shared_ptr<ImpGraphic> Manager::newInstance(const BitmapEx& rBitmapEx)
255{
256 auto pReturn = std::make_shared<ImpGraphic>(rBitmapEx);
257 registerGraphic(pReturn);
258 return pReturn;
259}
260
261std::shared_ptr<ImpGraphic> Manager::newInstance(const Animation& rAnimation)
262{
263 auto pReturn = std::make_shared<ImpGraphic>(rAnimation);
264 registerGraphic(pReturn);
265 return pReturn;
266}
267
268std::shared_ptr<ImpGraphic>
269Manager::newInstance(const std::shared_ptr<VectorGraphicData>& rVectorGraphicDataPtr)
270{
271 auto pReturn = std::make_shared<ImpGraphic>(rVectorGraphicDataPtr);
272 registerGraphic(pReturn);
273 return pReturn;
274}
275
276std::shared_ptr<ImpGraphic> Manager::newInstance(const GDIMetaFile& rMetaFile)
277{
278 auto pReturn = std::make_shared<ImpGraphic>(rMetaFile);
279 registerGraphic(pReturn);
280 return pReturn;
281}
282
283std::shared_ptr<ImpGraphic> Manager::newInstance(const GraphicExternalLink& rGraphicLink)
284{
285 auto pReturn = std::make_shared<ImpGraphic>(rGraphicLink);
286 registerGraphic(pReturn);
287 return pReturn;
288}
289
290void Manager::swappedIn(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes)
291{
292 std::scoped_lock aGuard(maMutex);
293 if (pImpGraphic)
294 {
295 mnUsedSize += nSizeBytes;
296 }
297}
298
299void Manager::swappedOut(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes)
300{
301 std::scoped_lock aGuard(maMutex);
302 if (pImpGraphic)
303 {
304 mnUsedSize -= nSizeBytes;
305 }
306}
307
308void Manager::changeExisting(const ImpGraphic* pImpGraphic, sal_Int64 nOldSizeBytes)
309{
310 std::scoped_lock aGuard(maMutex);
311
312 mnUsedSize -= nOldSizeBytes;
313 mnUsedSize += getGraphicSizeBytes(pImpGraphic);
314}
315} // end vcl::graphic
316
317/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::mutex maMutex
sal_uLong getSizeBytes() const
Definition: impgraph.cxx:963
bool isAvailable() const
Definition: impgraph.cxx:514
Definition: timer.hxx:27
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:90
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
virtual void Start(bool bStartTimer=true) override
Schedules the task for execution.
Definition: timer.cxx:83
size_type erase(const Value &x)
size_type size() const
std::pair< const_iterator, bool > insert(Value &&x)
static bool IsFuzzing()
void changeExisting(const ImpGraphic *pImpGraphic, sal_Int64 nOldSize)
Definition: Manager.cxx:308
sal_Int64 mnMemoryLimit
Definition: Manager.hxx:40
o3tl::sorted_vector< ImpGraphic * > m_pImpGraphicList
Definition: Manager.hxx:36
std::shared_ptr< ImpGraphic > newInstance()
Definition: Manager.cxx:239
std::shared_ptr< ImpGraphic > copy(std::shared_ptr< ImpGraphic > const &pImpGraphic)
Definition: Manager.cxx:232
bool mbReducingGraphicMemory
Definition: Manager.hxx:39
static Manager & get()
Definition: Manager.cxx:54
void reduceGraphicMemory(std::unique_lock< std::mutex > &rGuard, bool bDropAll=false)
Definition: Manager.cxx:115
void loopGraphicsAndSwapOut(std::unique_lock< std::mutex > &rGuard, bool bDropAll)
Definition: Manager.cxx:78
void swappedOut(const ImpGraphic *pImpGraphic, sal_Int64 nSizeBytes)
Definition: Manager.cxx:299
static sal_Int64 getGraphicSizeBytes(const ImpGraphic *pImpGraphic)
Definition: Manager.cxx:175
void registerGraphic(const std::shared_ptr< ImpGraphic > &rImpGraphic)
Definition: Manager.cxx:191
void unregisterGraphic(ImpGraphic *pImpGraphic)
Definition: Manager.cxx:224
void swappedIn(const ImpGraphic *pImpGraphic, sal_Int64 nSizeBytes)
Definition: Manager.cxx:290
void dumpState(rtl::OStringBuffer &rState)
Definition: Manager.cxx:159
sal_Int64 mnUsedSize
Definition: Manager.hxx:41
std::mutex maMutex
Definition: Manager.hxx:35
std::chrono::seconds mnAllowedIdleTime
Definition: Manager.hxx:37
#define SAL_INFO_IF(condition, area, stream)
IMPL_LINK(Manager, SwapOutTimerHandler, Timer *, pTimer, void)
Definition: Manager.cxx:182