1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SlsPageCacheManager.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sd.hxx"
34 #include "cache/SlsPageCacheManager.hxx"
36 #include "SlsBitmapCache.hxx"
37 #include "view/SlideSorterView.hxx"
38 #include "model/SlideSorterModel.hxx"
42 #include <boost/weak_ptr.hpp>
46 /** Collection of data that is stored for all active preview caches.
51 ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument
;
55 ::sd::slidesorter::cache::PageCacheManager::DocumentKey pDocument
,
56 const Size
& rPreviewSize
)
57 :mpDocument(pDocument
),maPreviewSize(rPreviewSize
)
59 /// Test for equality with respect to all members.
60 class Equal
{public: bool operator() (
61 const CacheDescriptor
& rDescriptor1
, const CacheDescriptor
& rDescriptor2
) const {
62 return rDescriptor1
.mpDocument
==rDescriptor2
.mpDocument
63 && rDescriptor1
.maPreviewSize
==rDescriptor2
.maPreviewSize
;
65 /// Hash function that takes all members into account.
66 class Hash
{public: size_t operator() (const CacheDescriptor
& rDescriptor
) const {
67 return (size_t)rDescriptor
.mpDocument
.get() + rDescriptor
.maPreviewSize
.Width();
74 /** Collection of data that is stored for the inactive, recently used
77 class RecentlyUsedCacheDescriptor
80 ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument
;
82 ::boost::shared_ptr
< ::sd::slidesorter::cache::PageCacheManager::Cache
> mpCache
;
84 RecentlyUsedCacheDescriptor(
85 ::sd::slidesorter::cache::PageCacheManager::DocumentKey pDocument
,
86 const Size
& rPreviewSize
,
87 const ::boost::shared_ptr
< ::sd::slidesorter::cache::PageCacheManager::Cache
>& rpCache
)
88 :mpDocument(pDocument
),maPreviewSize(rPreviewSize
),mpCache(rpCache
)
95 /** The list of recently used caches is organized as queue. When elements
96 are added the list is shortened to the maximally allowed number of
97 elements by removing the least recently used elements.
99 typedef ::std::deque
<RecentlyUsedCacheDescriptor
> RecentlyUsedQueue
;
104 /** Compare the caches by preview size. Those that match the given size
105 come first, then, regardless of the given size, the largest ones before
108 class BestFittingCacheComparer
111 BestFittingCacheComparer (const Size
& rPreferredSize
)
112 : maPreferredSize(rPreferredSize
)
114 bool operator()(const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type
& rElement1
,
115 const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type
& rElement2
)
117 if (rElement1
.first
== maPreferredSize
)
119 else if (rElement2
.first
== maPreferredSize
)
122 return (rElement1
.first
.Width()*rElement1
.first
.Height()
123 > rElement2
.first
.Width()*rElement2
.first
.Height());
127 Size maPreferredSize
;
130 } // end of anonymous namespace
133 namespace sd
{ namespace slidesorter
{ namespace cache
{
135 /** Container for the active caches.
137 class PageCacheManager::PageCacheContainer
138 : public ::std::hash_map
<CacheDescriptor
,
139 ::boost::shared_ptr
<PageCacheManager::Cache
>,
140 CacheDescriptor::Hash
,
141 CacheDescriptor::Equal
>
144 PageCacheContainer (void) {}
146 /** Compare entries in the cache container with respect to the cache
149 class CompareWithCache
{ public:
150 CompareWithCache(const ::boost::shared_ptr
<PageCacheManager::Cache
>& rpCache
)
151 : mpCache(rpCache
) {}
152 bool operator () (const PageCacheContainer::value_type
& rValue
)
153 { return rValue
.second
== mpCache
; }
155 ::boost::shared_ptr
<PageCacheManager::Cache
> mpCache
;
160 /** The recently used caches are stored in one queue for each document.
162 class PageCacheManager::RecentlyUsedPageCaches
163 : public ::std::map
<DocumentKey
,RecentlyUsedQueue
>
166 RecentlyUsedPageCaches (void) {};
172 class PageCacheManager::Deleter
175 void operator() (PageCacheManager
* pObject
) { delete pObject
; }
180 //===== PageCacheManager ====================================================
182 ::boost::weak_ptr
<PageCacheManager
> PageCacheManager::mpInstance
;
184 ::boost::shared_ptr
<PageCacheManager
> PageCacheManager::Instance (void)
186 ::boost::shared_ptr
<PageCacheManager
> pInstance
;
188 ::osl::MutexGuard
aGuard (::osl::Mutex::getGlobalMutex());
190 pInstance
= mpInstance
.lock();
191 if (pInstance
.get() == NULL
)
193 pInstance
= ::boost::shared_ptr
<PageCacheManager
>(
194 new PageCacheManager(),
195 PageCacheManager::Deleter());
196 mpInstance
= pInstance
;
205 PageCacheManager::PageCacheManager (void)
206 : mpPageCaches(new PageCacheContainer()),
207 mpRecentlyUsedPageCaches(new RecentlyUsedPageCaches()),
208 mnMaximalRecentlyCacheCount(2)
215 PageCacheManager::~PageCacheManager (void)
222 ::boost::shared_ptr
<PageCacheManager::Cache
> PageCacheManager::GetCache (
223 DocumentKey pDocument
,
224 const Size
& rPreviewSize
)
226 ::boost::shared_ptr
<Cache
> pResult
;
228 // Look for the cache in the list of active caches.
229 CacheDescriptor
aKey (pDocument
, rPreviewSize
);
230 PageCacheContainer::iterator
iCache (mpPageCaches
->find(aKey
));
231 if (iCache
!= mpPageCaches
->end())
232 pResult
= iCache
->second
;
234 // Look for the cache in the list of recently used caches.
235 if (pResult
.get() == NULL
)
236 pResult
= GetRecentlyUsedCache(pDocument
, rPreviewSize
);
238 // Create the cache when no suitable one does exist.
239 if (pResult
.get() == NULL
)
240 pResult
.reset(new Cache());
242 // The cache may be newly created and thus empty or is old and may
243 // contain previews that are not up-to-date. Recycle previews from
244 // other caches to fill in the holes.
245 Recycle(pResult
, pDocument
,rPreviewSize
);
247 // Put the new (or old) cache into the container.
248 if (pResult
.get() != NULL
)
249 mpPageCaches
->insert(PageCacheContainer::value_type(aKey
, pResult
));
257 void PageCacheManager::Recycle (
258 const ::boost::shared_ptr
<Cache
>& rpCache
,
259 DocumentKey pDocument
,
260 const Size
& rPreviewSize
)
262 BestFittingPageCaches aCaches
;
264 // Add bitmap caches from active caches.
265 PageCacheContainer::iterator iActiveCache
;
266 for (iActiveCache
=mpPageCaches
->begin(); iActiveCache
!=mpPageCaches
->end(); ++iActiveCache
)
268 if (iActiveCache
->first
.mpDocument
== pDocument
)
269 aCaches
.push_back(BestFittingPageCaches::value_type(
270 iActiveCache
->first
.maPreviewSize
, iActiveCache
->second
));
273 // Add bitmap caches from recently used caches.
274 RecentlyUsedPageCaches::iterator
iQueue (mpRecentlyUsedPageCaches
->find(pDocument
));
275 if (iQueue
!= mpRecentlyUsedPageCaches
->end())
277 RecentlyUsedQueue::const_iterator iRecentCache
;
278 for (iRecentCache
=iQueue
->second
.begin();iRecentCache
!=iQueue
->second
.end();++iRecentCache
)
279 aCaches
.push_back(BestFittingPageCaches::value_type(
280 iRecentCache
->maPreviewSize
, iRecentCache
->mpCache
));
283 ::std::sort(aCaches
.begin(), aCaches
.end(), BestFittingCacheComparer(rPreviewSize
));
285 BestFittingPageCaches::const_iterator iBestCache
;
286 for (iBestCache
=aCaches
.begin(); iBestCache
!=aCaches
.end(); ++iBestCache
)
288 rpCache
->Recycle(*iBestCache
->second
);
295 void PageCacheManager::ReleaseCache (const ::boost::shared_ptr
<Cache
>& rpCache
)
297 PageCacheContainer::iterator
iCache (::std::find_if(
298 mpPageCaches
->begin(),
300 PageCacheContainer::CompareWithCache(rpCache
)));
302 if (iCache
!= mpPageCaches
->end())
304 OSL_ASSERT(iCache
->second
== rpCache
);
306 PutRecentlyUsedCache(iCache
->first
.mpDocument
,iCache
->first
.maPreviewSize
,rpCache
);
308 mpPageCaches
->erase(iCache
);
315 ::boost::shared_ptr
<PageCacheManager::Cache
> PageCacheManager::ChangeSize (
316 const ::boost::shared_ptr
<Cache
>& rpCache
,
317 const Size
& rOldPreviewSize
,
318 const Size
& rNewPreviewSize
)
320 (void)rOldPreviewSize
;
322 ::boost::shared_ptr
<Cache
> pResult
;
324 if (rpCache
.get() != NULL
)
326 // Look up the given cache in the list of active caches.
327 PageCacheContainer::iterator
iCacheToChange (::std::find_if(
328 mpPageCaches
->begin(),
330 PageCacheContainer::CompareWithCache(rpCache
)));
331 OSL_ASSERT(iCacheToChange
!= mpPageCaches
->end());
332 if (iCacheToChange
!= mpPageCaches
->end())
334 OSL_ASSERT(iCacheToChange
->second
== rpCache
);
336 // Now, we can change the preview size of the existing one by
337 // removing the cache from the list and re-insert it with the
339 const ::sd::slidesorter::cache::PageCacheManager::DocumentKey
aKey (
340 iCacheToChange
->first
.mpDocument
);
341 mpPageCaches
->erase(iCacheToChange
);
342 mpPageCaches
->insert(PageCacheContainer::value_type(
343 CacheDescriptor(aKey
,rNewPreviewSize
),
356 void PageCacheManager::InvalidatePreviewBitmap (
357 DocumentKey pDocument
,
362 // Iterate over all caches that are currently in use and invalidate
363 // the previews in those that belong to the document.
364 PageCacheContainer::iterator iCache
;
365 for (iCache
=mpPageCaches
->begin(); iCache
!=mpPageCaches
->end(); ++iCache
)
366 if (iCache
->first
.mpDocument
== pDocument
)
367 iCache
->second
->InvalidateBitmap(pKey
);
369 // Invalidate the previews in the recently used caches belonging to
370 // the given document.
371 RecentlyUsedPageCaches::iterator
iQueue (mpRecentlyUsedPageCaches
->find(pDocument
));
372 if (iQueue
!= mpRecentlyUsedPageCaches
->end())
374 RecentlyUsedQueue::const_iterator iCache2
;
375 for (iCache2
=iQueue
->second
.begin(); iCache2
!=iQueue
->second
.end(); ++iCache2
)
376 iCache2
->mpCache
->InvalidateBitmap(pKey
);
384 void PageCacheManager::InvalidateAllCaches (void)
386 // Iterate over all caches that are currently in use and invalidate
388 PageCacheContainer::iterator iCache
;
389 for (iCache
=mpPageCaches
->begin(); iCache
!=mpPageCaches
->end(); ++iCache
)
390 iCache
->second
->InvalidateCache();
392 // Remove all recently used caches, there is not much sense in storing
393 // invalidated and unused caches.
394 mpRecentlyUsedPageCaches
->clear();
400 ::boost::shared_ptr
<PageCacheManager::Cache
> PageCacheManager::GetRecentlyUsedCache (
401 DocumentKey pDocument
,
402 const Size
& rPreviewSize
)
404 ::boost::shared_ptr
<Cache
> pCache
;
406 // Look for the cache in the list of recently used caches.
407 RecentlyUsedPageCaches::iterator
iQueue (mpRecentlyUsedPageCaches
->find(pDocument
));
408 if (iQueue
!= mpRecentlyUsedPageCaches
->end())
410 RecentlyUsedQueue::iterator iCache
;
411 for (iCache
=iQueue
->second
.begin(); iCache
!= iQueue
->second
.end(); ++iCache
)
412 if (iCache
->maPreviewSize
== rPreviewSize
)
414 pCache
= iCache
->mpCache
;
415 iQueue
->second
.erase(iCache
);
426 void PageCacheManager::PutRecentlyUsedCache(
427 DocumentKey pDocument
,
428 const Size
& rPreviewSize
,
429 const ::boost::shared_ptr
<Cache
>& rpCache
)
431 // Look up the list of recently used caches for the given document.
432 RecentlyUsedPageCaches::iterator
iQueue (mpRecentlyUsedPageCaches
->find(pDocument
));
433 if (iQueue
== mpRecentlyUsedPageCaches
->end())
434 iQueue
= mpRecentlyUsedPageCaches
->insert(
435 RecentlyUsedPageCaches::value_type(pDocument
, RecentlyUsedQueue())
438 if (iQueue
!= mpRecentlyUsedPageCaches
->end())
440 iQueue
->second
.push_front(RecentlyUsedCacheDescriptor(pDocument
,rPreviewSize
,rpCache
));
441 // Shorten the list of recently used caches to the allowed maximal length.
442 while (iQueue
->second
.size() > mnMaximalRecentlyCacheCount
)
443 iQueue
->second
.pop_back();
449 } } } // end of namespace ::sd::slidesorter::cache