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  , mnMemoryLimit(300000000)
64  , mnUsedSize(0)
65  , maSwapOutTimer("graphic::Manager maSwapOutTimer")
66 {
67  setupConfigurationValuesIfPossible(mnMemoryLimit, mnAllowedIdleTime, mbSwapEnabled);
68 
69  if (mbSwapEnabled)
70  {
71  maSwapOutTimer.SetInvokeHandler(LINK(this, Manager, SwapOutTimerHandler));
73  maSwapOutTimer.SetDebugName("graphic::Manager maSwapOutTimer");
75  }
76 }
77 
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))
89  return;
90 
91  if (pEachImpGraphic->isSwappedOut())
92  continue;
93 
94  sal_Int64 nCurrentGraphicSize = getGraphicSizeBytes(pEachImpGraphic);
95  if (nCurrentGraphicSize > 100000)
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  pEachImpGraphic->swapOut();
105  }
106  }
107  }
108 }
109 
111 {
112  if (!mbSwapEnabled)
113  return;
114 
116  return;
117 
118  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
119 
121 
122  sal_Int64 calculatedSize = 0;
123  for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
124  {
125  if (!pEachImpGraphic->isSwappedOut())
126  {
127  calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
128  }
129  }
130 
131  if (calculatedSize != mnUsedSize)
132  {
133  mnUsedSize = calculatedSize;
134  }
135 }
136 
137 sal_Int64 Manager::getGraphicSizeBytes(const ImpGraphic* pImpGraphic)
138 {
139  if (!pImpGraphic->isAvailable())
140  return 0;
141  return pImpGraphic->getSizeBytes();
142 }
143 
144 IMPL_LINK(Manager, SwapOutTimerHandler, Timer*, pTimer, void)
145 {
146  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
147 
148  pTimer->Stop();
149  reduceGraphicMemory();
150  pTimer->Start();
151 }
152 
153 void Manager::registerGraphic(const std::shared_ptr<ImpGraphic>& pImpGraphic)
154 {
155  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
156 
157  // make some space first
160 
161  // Insert and update the used size (bytes)
162  mnUsedSize += getGraphicSizeBytes(pImpGraphic.get());
163  m_pImpGraphicList.insert(pImpGraphic.get());
164 
165  // calculate size of the graphic set
166  sal_Int64 calculatedSize = 0;
167  for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
168  {
169  if (!pEachImpGraphic->isSwappedOut())
170  {
171  calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
172  }
173  }
174 
175  if (calculatedSize != mnUsedSize)
176  {
177  SAL_INFO_IF(calculatedSize != mnUsedSize, "vcl.gdi",
178  "Calculated size mismatch. Variable size is '"
179  << mnUsedSize << "' but calculated size is '" << calculatedSize << "'");
180  mnUsedSize = calculatedSize;
181  }
182 }
183 
185 {
186  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
187 
188  mnUsedSize -= getGraphicSizeBytes(pImpGraphic);
189  m_pImpGraphicList.erase(pImpGraphic);
190 }
191 
192 std::shared_ptr<ImpGraphic> Manager::copy(std::shared_ptr<ImpGraphic> const& rImpGraphicPtr)
193 {
194  auto pReturn = std::make_shared<ImpGraphic>(*rImpGraphicPtr);
195  registerGraphic(pReturn);
196  return pReturn;
197 }
198 
199 std::shared_ptr<ImpGraphic> Manager::newInstance()
200 {
201  auto pReturn = std::make_shared<ImpGraphic>();
202  registerGraphic(pReturn);
203  return pReturn;
204 }
205 
206 std::shared_ptr<ImpGraphic> Manager::newInstance(std::shared_ptr<GfxLink> const& rGfxLink,
207  sal_Int32 nPageIndex)
208 {
209  auto pReturn = std::make_shared<ImpGraphic>(rGfxLink, nPageIndex);
210  registerGraphic(pReturn);
211  return pReturn;
212 }
213 
214 std::shared_ptr<ImpGraphic> Manager::newInstance(const BitmapEx& rBitmapEx)
215 {
216  auto pReturn = std::make_shared<ImpGraphic>(rBitmapEx);
217  registerGraphic(pReturn);
218  return pReturn;
219 }
220 
221 std::shared_ptr<ImpGraphic> Manager::newInstance(const Animation& rAnimation)
222 {
223  auto pReturn = std::make_shared<ImpGraphic>(rAnimation);
224  registerGraphic(pReturn);
225  return pReturn;
226 }
227 
228 std::shared_ptr<ImpGraphic>
229 Manager::newInstance(const std::shared_ptr<VectorGraphicData>& rVectorGraphicDataPtr)
230 {
231  auto pReturn = std::make_shared<ImpGraphic>(rVectorGraphicDataPtr);
232  registerGraphic(pReturn);
233  return pReturn;
234 }
235 
236 std::shared_ptr<ImpGraphic> Manager::newInstance(const GDIMetaFile& rMetaFile)
237 {
238  auto pReturn = std::make_shared<ImpGraphic>(rMetaFile);
239  registerGraphic(pReturn);
240  return pReturn;
241 }
242 
243 std::shared_ptr<ImpGraphic> Manager::newInstance(const GraphicExternalLink& rGraphicLink)
244 {
245  auto pReturn = std::make_shared<ImpGraphic>(rGraphicLink);
246  registerGraphic(pReturn);
247  return pReturn;
248 }
249 
250 void Manager::swappedIn(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes)
251 {
252  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
253  if (pImpGraphic)
254  {
255  mnUsedSize += nSizeBytes;
256  }
257 }
258 
259 void Manager::swappedOut(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes)
260 {
261  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
262  if (pImpGraphic)
263  {
264  mnUsedSize -= nSizeBytes;
265  }
266 }
267 
268 void Manager::changeExisting(const ImpGraphic* pImpGraphic, sal_Int64 nOldSizeBytes)
269 {
270  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
271 
272  mnUsedSize -= nOldSizeBytes;
273  mnUsedSize += getGraphicSizeBytes(pImpGraphic);
274 }
275 } // end vcl::graphic
276 
277 /* 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:137
void unregisterGraphic(ImpGraphic *pImpGraphic)
Definition: Manager.cxx:184
#define SAL_INFO_IF(condition, area, stream)
void registerGraphic(const std::shared_ptr< ImpGraphic > &rImpGraphic)
Definition: Manager.cxx:153
void reduceGraphicMemory()
Definition: Manager.cxx:110
std::shared_ptr< ImpGraphic > copy(std::shared_ptr< ImpGraphic > const &pImpGraphic)
Definition: Manager.cxx:192
::osl::Mutex maMutex
void swappedIn(const ImpGraphic *pImpGraphic, sal_Int64 nSizeBytes)
Definition: Manager.cxx:250
std::recursive_mutex maMutex
Definition: Manager.hxx:34
static bool IsFuzzing()
IMPL_LINK(Manager, SwapOutTimerHandler, Timer *, pTimer, void)
Definition: Manager.cxx:144
std::chrono::seconds mnAllowedIdleTime
Definition: Manager.hxx:36
void SetDebugName(const char *pDebugName)
Definition: task.hxx:82
sal_Int64 mnUsedSize
Definition: Manager.hxx:39
std::shared_ptr< ImpGraphic > newInstance()
Definition: Manager.cxx:199
void changeExisting(const ImpGraphic *pImpGraphic, sal_Int64 nOldSize)
Definition: Manager.cxx:268
virtual void Start() override
Activates the timer task.
Definition: timer.cxx:83
void loopGraphicsAndSwapOut()
Definition: Manager.cxx:78
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:89
sal_uLong getSizeBytes() const
Definition: impgraph.cxx:962
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
bool isAvailable() const
Definition: impgraph.cxx:510
sal_Int64 mnMemoryLimit
Definition: Manager.hxx:38
Definition: timer.hxx:26
std::pair< const_iterator, bool > insert(Value &&x)
void swappedOut(const ImpGraphic *pImpGraphic, sal_Int64 nSizeBytes)
Definition: Manager.cxx:259
size_type erase(const Value &x)