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>
25 #include <unotools/configmgr.hxx>
26 
27 using namespace css;
28 
29 namespace vcl::graphic
30 {
31 namespace
32 {
33 void 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 
54 Manager& Manager::get()
55 {
56  static Manager gStaticManager;
57  return gStaticManager;
58 }
59 
60 Manager::Manager()
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));
74  maSwapOutTimer.SetDebugName("graphic::Manager maSwapOutTimer");
76  }
77 }
78 
80 {
81  // make a copy of m_pImpGraphicList because if we swap out a svg, the svg
82  // filter may create more temp Graphics which are auto-added to
83  // m_pImpGraphicList invalidating a loop over m_pImpGraphicList, e.g.
84  // reexport of tdf118346-1.odg
86 
87  for (ImpGraphic* pEachImpGraphic : aImpGraphicList)
88  {
89  if (mnUsedSize < sal_Int64(mnMemoryLimit * 0.7))
90  return;
91 
92  if (pEachImpGraphic->isSwappedOut())
93  continue;
94 
95  sal_Int64 nCurrentGraphicSize = getGraphicSizeBytes(pEachImpGraphic);
96  if (nCurrentGraphicSize > 100000)
97  {
98  if (!pEachImpGraphic->mpContext)
99  {
100  auto aCurrent = std::chrono::high_resolution_clock::now();
101  auto aDeltaTime = aCurrent - pEachImpGraphic->maLastUsed;
102  auto aSeconds = std::chrono::duration_cast<std::chrono::seconds>(aDeltaTime);
103 
104  if (aSeconds > mnAllowedIdleTime)
105  pEachImpGraphic->swapOut();
106  }
107  }
108  }
109 }
110 
112 {
113  if (!mbSwapEnabled)
114  return;
115 
117  return;
118 
119  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
120 
121  // avoid recursive reduceGraphicMemory on reexport of tdf118346-1.odg to odg
123  return;
125 
127 
128  sal_Int64 calculatedSize = 0;
129  for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
130  {
131  if (!pEachImpGraphic->isSwappedOut())
132  {
133  calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
134  }
135  }
136 
137  if (calculatedSize != mnUsedSize)
138  {
139  mnUsedSize = calculatedSize;
140  }
141 
142  mbReducingGraphicMemory = false;
143 }
144 
145 sal_Int64 Manager::getGraphicSizeBytes(const ImpGraphic* pImpGraphic)
146 {
147  if (!pImpGraphic->isAvailable())
148  return 0;
149  return pImpGraphic->getSizeBytes();
150 }
151 
152 IMPL_LINK(Manager, SwapOutTimerHandler, Timer*, pTimer, void)
153 {
154  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
155 
156  pTimer->Stop();
157  reduceGraphicMemory();
158  pTimer->Start();
159 }
160 
161 void Manager::registerGraphic(const std::shared_ptr<ImpGraphic>& pImpGraphic)
162 {
163  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
164 
165  // make some space first
168 
169  // Insert and update the used size (bytes)
170  mnUsedSize += getGraphicSizeBytes(pImpGraphic.get());
171  m_pImpGraphicList.insert(pImpGraphic.get());
172 
173  // calculate size of the graphic set
174  sal_Int64 calculatedSize = 0;
175  for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
176  {
177  if (!pEachImpGraphic->isSwappedOut())
178  {
179  calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
180  }
181  }
182 
183  if (calculatedSize != mnUsedSize)
184  {
185  SAL_INFO_IF(calculatedSize != mnUsedSize, "vcl.gdi",
186  "Calculated size mismatch. Variable size is '"
187  << mnUsedSize << "' but calculated size is '" << calculatedSize << "'");
188  mnUsedSize = calculatedSize;
189  }
190 }
191 
193 {
194  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
195 
196  mnUsedSize -= getGraphicSizeBytes(pImpGraphic);
197  m_pImpGraphicList.erase(pImpGraphic);
198 }
199 
200 std::shared_ptr<ImpGraphic> Manager::copy(std::shared_ptr<ImpGraphic> const& rImpGraphicPtr)
201 {
202  auto pReturn = std::make_shared<ImpGraphic>(*rImpGraphicPtr);
203  registerGraphic(pReturn);
204  return pReturn;
205 }
206 
207 std::shared_ptr<ImpGraphic> Manager::newInstance()
208 {
209  auto pReturn = std::make_shared<ImpGraphic>();
210  registerGraphic(pReturn);
211  return pReturn;
212 }
213 
214 std::shared_ptr<ImpGraphic> Manager::newInstance(std::shared_ptr<GfxLink> const& rGfxLink,
215  sal_Int32 nPageIndex)
216 {
217  auto pReturn = std::make_shared<ImpGraphic>(rGfxLink, nPageIndex);
218  registerGraphic(pReturn);
219  return pReturn;
220 }
221 
222 std::shared_ptr<ImpGraphic> Manager::newInstance(const BitmapEx& rBitmapEx)
223 {
224  auto pReturn = std::make_shared<ImpGraphic>(rBitmapEx);
225  registerGraphic(pReturn);
226  return pReturn;
227 }
228 
229 std::shared_ptr<ImpGraphic> Manager::newInstance(const Animation& rAnimation)
230 {
231  auto pReturn = std::make_shared<ImpGraphic>(rAnimation);
232  registerGraphic(pReturn);
233  return pReturn;
234 }
235 
236 std::shared_ptr<ImpGraphic>
237 Manager::newInstance(const std::shared_ptr<VectorGraphicData>& rVectorGraphicDataPtr)
238 {
239  auto pReturn = std::make_shared<ImpGraphic>(rVectorGraphicDataPtr);
240  registerGraphic(pReturn);
241  return pReturn;
242 }
243 
244 std::shared_ptr<ImpGraphic> Manager::newInstance(const GDIMetaFile& rMetaFile)
245 {
246  auto pReturn = std::make_shared<ImpGraphic>(rMetaFile);
247  registerGraphic(pReturn);
248  return pReturn;
249 }
250 
251 std::shared_ptr<ImpGraphic> Manager::newInstance(const GraphicExternalLink& rGraphicLink)
252 {
253  auto pReturn = std::make_shared<ImpGraphic>(rGraphicLink);
254  registerGraphic(pReturn);
255  return pReturn;
256 }
257 
258 void Manager::swappedIn(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes)
259 {
260  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
261  if (pImpGraphic)
262  {
263  mnUsedSize += nSizeBytes;
264  }
265 }
266 
267 void Manager::swappedOut(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes)
268 {
269  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
270  if (pImpGraphic)
271  {
272  mnUsedSize -= nSizeBytes;
273  }
274 }
275 
276 void Manager::changeExisting(const ImpGraphic* pImpGraphic, sal_Int64 nOldSizeBytes)
277 {
278  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
279 
280  mnUsedSize -= nOldSizeBytes;
281  mnUsedSize += getGraphicSizeBytes(pImpGraphic);
282 }
283 } // end vcl::graphic
284 
285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
o3tl::sorted_vector< ImpGraphic * > m_pImpGraphicList
Definition: Manager.hxx:35
static sal_Int64 getGraphicSizeBytes(const ImpGraphic *pImpGraphic)
Definition: Manager.cxx:145
void unregisterGraphic(ImpGraphic *pImpGraphic)
Definition: Manager.cxx:192
#define SAL_INFO_IF(condition, area, stream)
std::mutex maMutex
void registerGraphic(const std::shared_ptr< ImpGraphic > &rImpGraphic)
Definition: Manager.cxx:161
void reduceGraphicMemory()
Definition: Manager.cxx:111
std::shared_ptr< ImpGraphic > copy(std::shared_ptr< ImpGraphic > const &pImpGraphic)
Definition: Manager.cxx:200
bool mbReducingGraphicMemory
Definition: Manager.hxx:38
void swappedIn(const ImpGraphic *pImpGraphic, sal_Int64 nSizeBytes)
Definition: Manager.cxx:258
std::recursive_mutex maMutex
Definition: Manager.hxx:34
static bool IsFuzzing()
IMPL_LINK(Manager, SwapOutTimerHandler, Timer *, pTimer, void)
Definition: Manager.cxx:152
std::chrono::seconds mnAllowedIdleTime
Definition: Manager.hxx:36
void SetDebugName(const char *pDebugName)
Definition: task.hxx:82
sal_Int64 mnUsedSize
Definition: Manager.hxx:40
std::shared_ptr< ImpGraphic > newInstance()
Definition: Manager.cxx:207
virtual void Start(bool bStartTimer=true) override
Schedules the task for execution.
Definition: timer.cxx:83
void changeExisting(const ImpGraphic *pImpGraphic, sal_Int64 nOldSize)
Definition: Manager.cxx:276
void loopGraphicsAndSwapOut()
Definition: Manager.cxx:79
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:90
sal_uLong getSizeBytes() const
Definition: impgraph.cxx:964
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
bool isAvailable() const
Definition: impgraph.cxx:512
sal_Int64 mnMemoryLimit
Definition: Manager.hxx:39
Definition: timer.hxx:26
std::pair< const_iterator, bool > insert(Value &&x)
void swappedOut(const ImpGraphic *pImpGraphic, sal_Int64 nSizeBytes)
Definition: Manager.cxx:267
size_type erase(const Value &x)