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  if (!mbSwapEnabled)
81  return;
82 
83  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
84 
85  // make a copy of m_pImpGraphicList because if we swap out a svg, the svg
86  // filter may create more temp Graphics which are auto-added to
87  // m_pImpGraphicList invalidating a loop over m_pImpGraphicList, e.g.
88  // reexport of tdf118346-1.odg
90  for (ImpGraphic* pEachImpGraphic : aImpGraphicList)
91  {
92  if (mnUsedSize < mnMemoryLimit * 0.7)
93  return;
94 
95  sal_Int64 nCurrentGraphicSize = getGraphicSizeBytes(pEachImpGraphic);
96  if (!pEachImpGraphic->isSwappedOut() && nCurrentGraphicSize > 1000000)
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 
111 sal_Int64 Manager::getGraphicSizeBytes(const ImpGraphic* pImpGraphic)
112 {
113  if (!pImpGraphic->isAvailable())
114  return 0;
115  return pImpGraphic->ImplGetSizeBytes();
116 }
117 
118 IMPL_LINK(Manager, SwapOutTimerHandler, Timer*, pTimer, void)
119 {
120  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
121 
122  pTimer->Stop();
123  reduceGraphicMemory();
124  pTimer->Start();
125 }
126 
127 void Manager::registerGraphic(const std::shared_ptr<ImpGraphic>& pImpGraphic,
128  OUString const& /*rsContext*/)
129 {
130  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
131 
132  // make some space first
135 
136  // Insert and update the used size (bytes)
137  mnUsedSize += getGraphicSizeBytes(pImpGraphic.get());
138  m_pImpGraphicList.insert(pImpGraphic.get());
139 
140  // calculate size of the graphic set
141  sal_Int64 calculatedSize = 0;
142  for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
143  {
144  if (!pEachImpGraphic->isSwappedOut())
145  {
146  calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
147  }
148  }
149 
150  if (calculatedSize != mnUsedSize)
151  {
152  SAL_INFO_IF(calculatedSize != mnUsedSize, "vcl.gdi",
153  "Calculated size mismatch. Variable size is '"
154  << mnUsedSize << "' but calculated size is '" << calculatedSize << "'");
155  mnUsedSize = calculatedSize;
156  }
157 }
158 
160 {
161  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
162 
163  mnUsedSize -= getGraphicSizeBytes(pImpGraphic);
164  m_pImpGraphicList.erase(pImpGraphic);
165 }
166 
167 std::shared_ptr<ImpGraphic> Manager::copy(std::shared_ptr<ImpGraphic> const& rImpGraphicPtr)
168 {
169  auto pReturn = std::make_shared<ImpGraphic>(*rImpGraphicPtr);
170  registerGraphic(pReturn, "Copy");
171  return pReturn;
172 }
173 
174 std::shared_ptr<ImpGraphic> Manager::newInstance()
175 {
176  auto pReturn = std::make_shared<ImpGraphic>();
177  registerGraphic(pReturn, "Empty");
178  return pReturn;
179 }
180 
181 std::shared_ptr<ImpGraphic> Manager::newInstance(const Bitmap& rBitmap)
182 {
183  auto pReturn = std::make_shared<ImpGraphic>(rBitmap);
184  registerGraphic(pReturn, "Bitmap");
185  return pReturn;
186 }
187 
188 std::shared_ptr<ImpGraphic> Manager::newInstance(const BitmapEx& rBitmapEx)
189 {
190  auto pReturn = std::make_shared<ImpGraphic>(rBitmapEx);
191  registerGraphic(pReturn, "BitmapEx");
192  return pReturn;
193 }
194 
195 std::shared_ptr<ImpGraphic> Manager::newInstance(const Animation& rAnimation)
196 {
197  auto pReturn = std::make_shared<ImpGraphic>(rAnimation);
198  registerGraphic(pReturn, "Animation");
199  return pReturn;
200 }
201 
202 std::shared_ptr<ImpGraphic>
203 Manager::newInstance(const std::shared_ptr<VectorGraphicData>& rVectorGraphicDataPtr)
204 {
205  auto pReturn = std::make_shared<ImpGraphic>(rVectorGraphicDataPtr);
206  registerGraphic(pReturn, "VectorGraphic");
207  return pReturn;
208 }
209 
210 std::shared_ptr<ImpGraphic> Manager::newInstance(const GDIMetaFile& rMetaFile)
211 {
212  auto pReturn = std::make_shared<ImpGraphic>(rMetaFile);
213  registerGraphic(pReturn, "Metafile");
214  return pReturn;
215 }
216 
217 std::shared_ptr<ImpGraphic> Manager::newInstance(const GraphicExternalLink& rGraphicLink)
218 {
219  auto pReturn = std::make_shared<ImpGraphic>(rGraphicLink);
220  registerGraphic(pReturn, "GraphicExternalLink");
221  return pReturn;
222 }
223 
224 void Manager::swappedIn(const ImpGraphic* pImpGraphic)
225 {
226  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
227 
228  mnUsedSize += getGraphicSizeBytes(pImpGraphic);
229 }
230 
231 void Manager::swappedOut(const ImpGraphic* pImpGraphic)
232 {
233  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
234 
235  mnUsedSize -= getGraphicSizeBytes(pImpGraphic);
236 }
237 
238 void Manager::changeExisting(const ImpGraphic* pImpGraphic, sal_Int64 nOldSizeBytes)
239 {
240  std::scoped_lock<std::recursive_mutex> aGuard(maMutex);
241 
242  mnUsedSize -= nOldSizeBytes;
243  mnUsedSize += getGraphicSizeBytes(pImpGraphic);
244 }
245 } // end vcl::graphic
246 
247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
o3tl::sorted_vector< ImpGraphic * > m_pImpGraphicList
Definition: Manager.hxx:36
static sal_Int64 getGraphicSizeBytes(const ImpGraphic *pImpGraphic)
Definition: Manager.cxx:111
void unregisterGraphic(ImpGraphic *pImpGraphic)
Definition: Manager.cxx:159
#define SAL_INFO_IF(condition, area, stream)
void reduceGraphicMemory()
Definition: Manager.cxx:78
std::shared_ptr< ImpGraphic > copy(std::shared_ptr< ImpGraphic > const &pImpGraphic)
Definition: Manager.cxx:167
std::recursive_mutex maMutex
Definition: Manager.hxx:35
static bool IsFuzzing()
IMPL_LINK(Manager, SwapOutTimerHandler, Timer *, pTimer, void)
Definition: Manager.cxx:118
::osl::Mutex maMutex
std::chrono::seconds mnAllowedIdleTime
Definition: Manager.hxx:37
void SetDebugName(const char *pDebugName)
Definition: task.hxx:81
sal_Int64 mnUsedSize
Definition: Manager.hxx:40
std::shared_ptr< ImpGraphic > newInstance()
Definition: Manager.cxx:174
void changeExisting(const ImpGraphic *pImpGraphic, sal_Int64 nOldSize)
Definition: Manager.cxx:238
virtual void Start() override
Activates the timer task.
Definition: timer.cxx:83
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:89
void registerGraphic(const std::shared_ptr< ImpGraphic > &rImpGraphic, OUString const &rsContext)
Definition: Manager.cxx:127
void swappedIn(const ImpGraphic *pImpGraphic)
Definition: Manager.cxx:224
sal_uLong ImplGetSizeBytes() const
Definition: impgraph.cxx:982
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
void swappedOut(const ImpGraphic *pImpGraphic)
Definition: Manager.cxx:231
bool isAvailable() const
Definition: impgraph.cxx:535
sal_Int64 mnMemoryLimit
Definition: Manager.hxx:39
Definition: timer.hxx:26
std::pair< const_iterator, bool > insert(Value &&x)
size_type erase(const Value &x)