Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "cache/SlsPageCacheManager.hxx"
31 : :
32 : : #include "SlsBitmapCache.hxx"
33 : : #include "view/SlideSorterView.hxx"
34 : : #include "model/SlideSorterModel.hxx"
35 : :
36 : : #include <deque>
37 : : #include <map>
38 : : #include <boost/weak_ptr.hpp>
39 : :
40 : : namespace {
41 : :
42 : : /** Collection of data that is stored for all active preview caches.
43 : : */
44 : 680 : class CacheDescriptor
45 : : {
46 : : public:
47 : : ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument;
48 : : Size maPreviewSize;
49 : :
50 : 136 : CacheDescriptor(
51 : : ::sd::slidesorter::cache::PageCacheManager::DocumentKey pDocument,
52 : : const Size& rPreviewSize)
53 : 136 : :mpDocument(pDocument),maPreviewSize(rPreviewSize)
54 : 136 : {}
55 : : /// Test for equality with respect to all members.
56 : 0 : class Equal {public: bool operator() (
57 : : const CacheDescriptor& rDescriptor1, const CacheDescriptor& rDescriptor2) const {
58 : 0 : return rDescriptor1.mpDocument==rDescriptor2.mpDocument
59 [ # # ][ # # ]: 0 : && rDescriptor1.maPreviewSize==rDescriptor2.maPreviewSize;
60 : : } };
61 : : /// Hash function that takes all members into account.
62 : 136 : class Hash {public: size_t operator() (const CacheDescriptor& rDescriptor) const {
63 : 136 : return (size_t)rDescriptor.mpDocument.get() + rDescriptor.maPreviewSize.Width();
64 : : } };
65 : : };
66 : :
67 : :
68 : :
69 : :
70 : : /** Collection of data that is stored for the inactive, recently used
71 : : caches.
72 : : */
73 [ + - ][ + - ]: 378 : class RecentlyUsedCacheDescriptor
74 : : {
75 : : public:
76 : : ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument;
77 : : Size maPreviewSize;
78 : : ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache> mpCache;
79 : :
80 : 126 : RecentlyUsedCacheDescriptor(
81 : : ::sd::slidesorter::cache::PageCacheManager::DocumentKey pDocument,
82 : : const Size& rPreviewSize,
83 : : const ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache>& rpCache)
84 [ + - ]: 126 : :mpDocument(pDocument),maPreviewSize(rPreviewSize),mpCache(rpCache)
85 : 126 : {}
86 : : };
87 : :
88 : :
89 : :
90 : :
91 : : /** The list of recently used caches is organized as queue. When elements
92 : : are added the list is shortened to the maximally allowed number of
93 : : elements by removing the least recently used elements.
94 : : */
95 : : typedef ::std::deque<RecentlyUsedCacheDescriptor> RecentlyUsedQueue;
96 : :
97 : :
98 : :
99 : :
100 : : /** Compare the caches by preview size. Those that match the given size
101 : : come first, then, regardless of the given size, the largest ones before
102 : : the smaller ones.
103 : : */
104 : : class BestFittingCacheComparer
105 : : {
106 : : public:
107 : 126 : BestFittingCacheComparer (const Size& rPreferredSize)
108 : 126 : : maPreferredSize(rPreferredSize)
109 : 126 : {}
110 : 0 : bool operator()(const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement1,
111 : : const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement2)
112 : : {
113 [ # # ]: 0 : if (rElement1.first == maPreferredSize)
114 : 0 : return true;
115 [ # # ]: 0 : else if (rElement2.first == maPreferredSize)
116 : 0 : return false;
117 : : else
118 : 0 : return (rElement1.first.Width()*rElement1.first.Height()
119 : 0 : > rElement2.first.Width()*rElement2.first.Height());
120 : : }
121 : :
122 : : private:
123 : : Size maPreferredSize;
124 : : };
125 : :
126 : : } // end of anonymous namespace
127 : :
128 : :
129 : : namespace sd { namespace slidesorter { namespace cache {
130 : :
131 : : /** Container for the active caches.
132 : : */
133 : 130 : class PageCacheManager::PageCacheContainer
134 : : : public ::boost::unordered_map<CacheDescriptor,
135 : : ::boost::shared_ptr<PageCacheManager::Cache>,
136 : : CacheDescriptor::Hash,
137 : : CacheDescriptor::Equal>
138 : : {
139 : : public:
140 [ + - ]: 130 : PageCacheContainer (void) {}
141 : :
142 : : /** Compare entries in the cache container with respect to the cache
143 : : address only.
144 : : */
145 : 408 : class CompareWithCache { public:
146 : 136 : CompareWithCache(const ::boost::shared_ptr<PageCacheManager::Cache>& rpCache)
147 : 136 : : mpCache(rpCache) {}
148 : 136 : bool operator () (const PageCacheContainer::value_type& rValue) const
149 : 136 : { return rValue.second == mpCache; }
150 : : private:
151 : : ::boost::shared_ptr<PageCacheManager::Cache> mpCache;
152 : : };
153 : : };
154 : :
155 : :
156 : : /** The recently used caches are stored in one queue for each document.
157 : : */
158 : 130 : class PageCacheManager::RecentlyUsedPageCaches
159 : : : public ::std::map<DocumentKey,RecentlyUsedQueue>
160 : : {
161 : : public:
162 : 130 : RecentlyUsedPageCaches (void) {};
163 : : };
164 : :
165 : :
166 : :
167 : :
168 : : class PageCacheManager::Deleter
169 : : {
170 : : public:
171 [ + - ]: 130 : void operator() (PageCacheManager* pObject) { delete pObject; }
172 : : };
173 : :
174 : :
175 : :
176 : : //===== PageCacheManager ====================================================
177 : :
178 : 25 : ::boost::weak_ptr<PageCacheManager> PageCacheManager::mpInstance;
179 : :
180 : 1336 : ::boost::shared_ptr<PageCacheManager> PageCacheManager::Instance (void)
181 : : {
182 [ + - ]: 1336 : ::boost::shared_ptr<PageCacheManager> pInstance;
183 : :
184 [ + - ][ + - ]: 1336 : ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
185 : :
186 [ + - ][ + - ]: 1336 : pInstance = mpInstance.lock();
[ + - ]
187 [ + + ]: 1336 : if (pInstance.get() == NULL)
188 : : {
189 : : pInstance = ::boost::shared_ptr<PageCacheManager>(
190 : 0 : new PageCacheManager(),
191 [ + - ][ + - ]: 130 : PageCacheManager::Deleter());
[ + - ][ + - ]
[ + - ]
192 [ + - ]: 130 : mpInstance = pInstance;
193 : : }
194 : :
195 [ + - ]: 1336 : return pInstance;
196 : : }
197 : :
198 : :
199 : :
200 : :
201 : 130 : PageCacheManager::PageCacheManager (void)
202 : 0 : : mpPageCaches(new PageCacheContainer()),
203 : 0 : mpRecentlyUsedPageCaches(new RecentlyUsedPageCaches()),
204 [ + - ][ + - ]: 130 : mnMaximalRecentlyCacheCount(2)
[ + - ]
205 : : {
206 : 130 : }
207 : :
208 : :
209 : :
210 : :
211 : 130 : PageCacheManager::~PageCacheManager (void)
212 : : {
213 : 130 : }
214 : :
215 : :
216 : :
217 : :
218 : 126 : ::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetCache (
219 : : DocumentKey pDocument,
220 : : const Size& rPreviewSize)
221 : : {
222 [ + - ]: 126 : ::boost::shared_ptr<Cache> pResult;
223 : :
224 : : // Look for the cache in the list of active caches.
225 [ + - ]: 126 : CacheDescriptor aKey (pDocument, rPreviewSize);
226 [ + - ]: 126 : PageCacheContainer::iterator iCache (mpPageCaches->find(aKey));
227 [ + - ][ - + ]: 126 : if (iCache != mpPageCaches->end())
228 [ # # ][ # # ]: 0 : pResult = iCache->second;
229 : :
230 : : // Look for the cache in the list of recently used caches.
231 [ + - ]: 126 : if (pResult.get() == NULL)
232 [ + - ][ + - ]: 126 : pResult = GetRecentlyUsedCache(pDocument, rPreviewSize);
[ + - ]
233 : :
234 : : // Create the cache when no suitable one does exist.
235 [ + - ]: 126 : if (pResult.get() == NULL)
236 [ + - ][ + - ]: 126 : pResult.reset(new Cache());
[ + - ]
237 : :
238 : : // The cache may be newly created and thus empty or is old and may
239 : : // contain previews that are not up-to-date. Recycle previews from
240 : : // other caches to fill in the holes.
241 [ + - ]: 126 : Recycle(pResult, pDocument,rPreviewSize);
242 : :
243 : : // Put the new (or old) cache into the container.
244 [ + - ]: 126 : if (pResult.get() != NULL)
245 [ + - ][ + - ]: 126 : mpPageCaches->insert(PageCacheContainer::value_type(aKey, pResult));
[ + - ]
246 : :
247 [ + - ]: 126 : return pResult;
248 : : }
249 : :
250 : :
251 : :
252 : :
253 : 126 : void PageCacheManager::Recycle (
254 : : const ::boost::shared_ptr<Cache>& rpCache,
255 : : DocumentKey pDocument,
256 : : const Size& rPreviewSize)
257 : : {
258 [ + - ]: 126 : BestFittingPageCaches aCaches;
259 : :
260 : : // Add bitmap caches from active caches.
261 : 126 : PageCacheContainer::iterator iActiveCache;
262 [ + - ][ - + ]: 126 : for (iActiveCache=mpPageCaches->begin(); iActiveCache!=mpPageCaches->end(); ++iActiveCache)
[ + - ]
263 : : {
264 [ # # ][ # # ]: 0 : if (iActiveCache->first.mpDocument == pDocument)
[ # # ]
265 : : aCaches.push_back(BestFittingPageCaches::value_type(
266 [ # # ][ # # ]: 0 : iActiveCache->first.maPreviewSize, iActiveCache->second));
[ # # ][ # # ]
[ # # ]
267 : : }
268 : :
269 : : // Add bitmap caches from recently used caches.
270 [ + - ]: 126 : RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
271 [ - + ]: 126 : if (iQueue != mpRecentlyUsedPageCaches->end())
272 : : {
273 : 0 : RecentlyUsedQueue::const_iterator iRecentCache;
274 [ # # ][ # # ]: 0 : for (iRecentCache=iQueue->second.begin();iRecentCache!=iQueue->second.end();++iRecentCache)
[ # # ]
275 : : aCaches.push_back(BestFittingPageCaches::value_type(
276 [ # # ][ # # ]: 0 : iRecentCache->maPreviewSize, iRecentCache->mpCache));
[ # # ]
277 : : }
278 : :
279 [ + - ]: 126 : ::std::sort(aCaches.begin(), aCaches.end(), BestFittingCacheComparer(rPreviewSize));
280 : :
281 : 126 : BestFittingPageCaches::const_iterator iBestCache;
282 [ + - ][ + - ]: 126 : for (iBestCache=aCaches.begin(); iBestCache!=aCaches.end(); ++iBestCache)
[ - + ]
283 : : {
284 [ # # ]: 0 : rpCache->Recycle(*iBestCache->second);
285 : 126 : }
286 : 126 : }
287 : :
288 : :
289 : :
290 : :
291 : 126 : void PageCacheManager::ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache)
292 : : {
293 : : PageCacheContainer::iterator iCache (::std::find_if(
294 : 126 : mpPageCaches->begin(),
295 : 126 : mpPageCaches->end(),
296 [ + - + - : 378 : PageCacheContainer::CompareWithCache(rpCache)));
+ - ][ + - ]
[ + - ]
297 : :
298 [ + - ][ + - ]: 126 : if (iCache != mpPageCaches->end())
299 : : {
300 : : OSL_ASSERT(iCache->second == rpCache);
301 : :
302 [ + - ][ + - ]: 126 : PutRecentlyUsedCache(iCache->first.mpDocument,iCache->first.maPreviewSize,rpCache);
[ + - ]
303 : :
304 [ + - ]: 126 : mpPageCaches->erase(iCache);
305 : : }
306 : 126 : }
307 : :
308 : :
309 : :
310 : :
311 : 10 : ::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::ChangeSize (
312 : : const ::boost::shared_ptr<Cache>& rpCache,
313 : : const Size& rOldPreviewSize,
314 : : const Size& rNewPreviewSize)
315 : : {
316 : : (void)rOldPreviewSize;
317 : :
318 : 10 : ::boost::shared_ptr<Cache> pResult;
319 : :
320 [ + - ]: 10 : if (rpCache.get() != NULL)
321 : : {
322 : : // Look up the given cache in the list of active caches.
323 : : PageCacheContainer::iterator iCacheToChange (::std::find_if(
324 : 10 : mpPageCaches->begin(),
325 : 10 : mpPageCaches->end(),
326 [ + - + - : 30 : PageCacheContainer::CompareWithCache(rpCache)));
+ - ][ + - ]
[ + - ]
327 [ + - ][ + - ]: 10 : if (iCacheToChange != mpPageCaches->end())
328 : : {
329 : : OSL_ASSERT(iCacheToChange->second == rpCache);
330 : :
331 : : // Now, we can change the preview size of the existing one by
332 : : // removing the cache from the list and re-insert it with the
333 : : // updated size.
334 : : const ::sd::slidesorter::cache::PageCacheManager::DocumentKey aKey (
335 [ + - ]: 10 : iCacheToChange->first.mpDocument);
336 [ + - ]: 10 : mpPageCaches->erase(iCacheToChange);
337 : 10 : mpPageCaches->insert(PageCacheContainer::value_type(
338 : : CacheDescriptor(aKey,rNewPreviewSize),
339 [ + - ]: 20 : rpCache));
[ + - + - ]
[ + - ][ + - ]
340 : :
341 [ + - ]: 10 : pResult = rpCache;
342 : : }
343 : : else
344 : : {
345 : : OSL_ASSERT(iCacheToChange != mpPageCaches->end());
346 : : }
347 : : }
348 : :
349 : 10 : return pResult;
350 : : }
351 : :
352 : :
353 : :
354 : :
355 : 986 : bool PageCacheManager::InvalidatePreviewBitmap (
356 : : DocumentKey pDocument,
357 : : const SdrPage* pKey)
358 : : {
359 : 986 : bool bHasChanged (false);
360 : :
361 [ + - ]: 986 : if (pDocument!=NULL)
362 : : {
363 : : // Iterate over all caches that are currently in use and invalidate
364 : : // the previews in those that belong to the document.
365 : 986 : PageCacheContainer::iterator iCache;
366 [ + - ][ + + ]: 1969 : for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache)
[ + - ]
367 [ + - ][ + - ]: 983 : if (iCache->first.mpDocument == pDocument)
[ + - ]
368 [ + - ][ + - ]: 983 : bHasChanged |= iCache->second->InvalidateBitmap(pKey);
369 : :
370 : : // Invalidate the previews in the recently used caches belonging to
371 : : // the given document.
372 [ + - ]: 986 : RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
373 [ - + ]: 986 : if (iQueue != mpRecentlyUsedPageCaches->end())
374 : : {
375 : 0 : RecentlyUsedQueue::const_iterator iCache2;
376 [ # # ][ # # ]: 986 : for (iCache2=iQueue->second.begin(); iCache2!=iQueue->second.end(); ++iCache2)
[ # # ]
377 [ # # ]: 0 : bHasChanged |= iCache2->mpCache->InvalidateBitmap(pKey);
378 : : }
379 : : }
380 : :
381 : 986 : return bHasChanged;
382 : : }
383 : :
384 : :
385 : :
386 : :
387 : 94 : void PageCacheManager::InvalidateAllPreviewBitmaps (DocumentKey pDocument)
388 : : {
389 [ + - ][ + - ]: 94 : if (pDocument == NULL)
390 : 94 : return;
391 : :
392 : : // Iterate over all caches that are currently in use and invalidate the
393 : : // previews in those that belong to the document.
394 : 94 : PageCacheContainer::iterator iCache;
395 [ + - ][ + + ]: 180 : for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache)
[ + - ]
396 [ + - ][ + - ]: 86 : if (iCache->first.mpDocument == pDocument)
[ + - ]
397 [ + - ][ + - ]: 86 : iCache->second->InvalidateCache();
398 : :
399 : : // Invalidate the previews in the recently used caches belonging to the
400 : : // given document.
401 [ + - ]: 94 : RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
402 [ - + ]: 94 : if (iQueue != mpRecentlyUsedPageCaches->end())
403 : : {
404 : 0 : RecentlyUsedQueue::const_iterator iCache2;
405 [ # # ][ # # ]: 94 : for (iCache2=iQueue->second.begin(); iCache2!=iQueue->second.end(); ++iCache2)
[ # # ]
406 [ # # ]: 0 : iCache2->mpCache->InvalidateCache();
407 : : }
408 : : }
409 : :
410 : :
411 : :
412 : :
413 : 0 : void PageCacheManager::InvalidateAllCaches (void)
414 : : {
415 : : // Iterate over all caches that are currently in use and invalidate
416 : : // them.
417 : 0 : PageCacheContainer::iterator iCache;
418 [ # # ][ # # ]: 0 : for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache)
[ # # ]
419 [ # # ][ # # ]: 0 : iCache->second->InvalidateCache();
420 : :
421 : : // Remove all recently used caches, there is not much sense in storing
422 : : // invalidated and unused caches.
423 : 0 : mpRecentlyUsedPageCaches->clear();
424 : 0 : }
425 : :
426 : :
427 : :
428 : :
429 : 2 : void PageCacheManager::ReleasePreviewBitmap (const SdrPage* pPage)
430 : : {
431 : 2 : PageCacheContainer::iterator iCache;
432 [ + - ][ + + ]: 4 : for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache)
[ + - ]
433 [ + - ][ + - ]: 2 : iCache->second->ReleaseBitmap(pPage);
434 : 2 : }
435 : :
436 : :
437 : :
438 : :
439 : 126 : ::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetRecentlyUsedCache (
440 : : DocumentKey pDocument,
441 : : const Size& rPreviewSize)
442 : : {
443 [ + - ]: 126 : ::boost::shared_ptr<Cache> pCache;
444 : :
445 : : // Look for the cache in the list of recently used caches.
446 [ + - ]: 126 : RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
447 [ - + ]: 126 : if (iQueue != mpRecentlyUsedPageCaches->end())
448 : : {
449 : 0 : RecentlyUsedQueue::iterator iCache;
450 [ # # ][ # # ]: 126 : for (iCache=iQueue->second.begin(); iCache!= iQueue->second.end(); ++iCache)
[ # # ]
451 [ # # ]: 0 : if (iCache->maPreviewSize == rPreviewSize)
452 : : {
453 [ # # ]: 0 : pCache = iCache->mpCache;
454 [ # # ]: 0 : iQueue->second.erase(iCache);
455 : 0 : break;
456 : : }
457 : : }
458 : :
459 : 126 : return pCache;
460 : : }
461 : :
462 : :
463 : :
464 : :
465 : 126 : void PageCacheManager::PutRecentlyUsedCache(
466 : : DocumentKey pDocument,
467 : : const Size& rPreviewSize,
468 : : const ::boost::shared_ptr<Cache>& rpCache)
469 : : {
470 : : // Look up the list of recently used caches for the given document.
471 [ + - ]: 126 : RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
472 [ + - ]: 126 : if (iQueue == mpRecentlyUsedPageCaches->end())
473 : 126 : iQueue = mpRecentlyUsedPageCaches->insert(
474 : : RecentlyUsedPageCaches::value_type(pDocument, RecentlyUsedQueue())
475 [ + - ]: 252 : ).first;
[ + - + - ]
[ + - ]
476 : :
477 [ + - ]: 126 : if (iQueue != mpRecentlyUsedPageCaches->end())
478 : : {
479 [ + - ][ + - ]: 126 : iQueue->second.push_front(RecentlyUsedCacheDescriptor(pDocument,rPreviewSize,rpCache));
[ + - ]
480 : : // Shorten the list of recently used caches to the allowed maximal length.
481 [ - + ]: 126 : while (iQueue->second.size() > mnMaximalRecentlyCacheCount)
482 [ # # ]: 0 : iQueue->second.pop_back();
483 : : }
484 : 126 : }
485 : :
486 : :
487 : :
488 [ + - ][ + - ]: 75 : } } } // end of namespace ::sd::slidesorter::cache
489 : :
490 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|