merge the formfield patch from ooo-build
[ooovba.git] / sd / source / ui / slidesorter / cache / SlsBitmapCache.cxx
blob179f6fcd0fd8b12cfe8c95bd52adc7b0a88885bd
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SlsBitmapCache.cxx,v $
10 * $Revision: 1.10 $
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 "SlsBitmapCache.hxx"
35 #include "SlsCacheCompactor.hxx"
36 #include "SlsBitmapCompressor.hxx"
37 #include "SlsCacheConfiguration.hxx"
39 #include "taskpane/SlideSorterCacheDisplay.hxx"
40 #include "sdpage.hxx"
41 #include "drawdoc.hxx"
43 // Uncomment the following define for some more OSL_TRACE messages.
44 #ifdef DEBUG
45 //#define VERBOSE
46 #endif
48 // Define the default value for the maximal cache size that is used for
49 // previews that are currently not visible. The visible previews are all
50 // held in memory at all times. This default is used only when the
51 // configuration does not have a value.
52 static const sal_Int32 MAXIMAL_CACHE_SIZE = 4L*1024L*1024L;
54 using namespace ::com::sun::star::uno;
56 namespace sd { namespace slidesorter { namespace cache {
58 class BitmapCache::CacheEntry
60 public:
61 CacheEntry(const ::boost::shared_ptr<BitmapEx>& rpBitmap,
62 sal_Int32 nLastAccessTime, bool bIsPrecious);
63 CacheEntry(sal_Int32 nLastAccessTime, bool bIsPrecious);
64 ~CacheEntry (void) {};
65 inline void Recycle (const CacheEntry& rEntry);
66 inline sal_Int32 GetMemorySize (void) const;
67 void Compress (const ::boost::shared_ptr<BitmapCompressor>& rpCompressor);
68 inline void Decompress (void);
70 bool IsUpToDate (void) const { return mbIsUpToDate; }
71 void SetUpToDate (bool bIsUpToDate) { mbIsUpToDate = bIsUpToDate; }
72 sal_Int32 GetAccessTime (void) const { return mnLastAccessTime; }
73 void SetAccessTime (sal_Int32 nAccessTime) { mnLastAccessTime = nAccessTime; }
74 ::boost::shared_ptr<BitmapEx> GetPreview (void) const { return mpPreview; }
75 inline void SetPreview (const ::boost::shared_ptr<BitmapEx>& rpPreview);
76 bool HasPreview (void) const;
77 bool HasReplacement (void) const { return (mpReplacement.get() != NULL); }
78 inline bool HasLosslessReplacement (void) const;
79 void Clear (void) { mpPreview.reset(); mpReplacement.reset(); mpCompressor.reset(); }
80 void Invalidate (void) { mpReplacement.reset(); mpCompressor.reset(); mbIsUpToDate = false; }
81 bool IsPrecious (void) const { return mbIsPrecious; }
82 void SetPrecious (bool bIsPrecious) { mbIsPrecious = bIsPrecious; }
84 private:
85 ::boost::shared_ptr<BitmapEx> mpPreview;
86 ::boost::shared_ptr<BitmapReplacement> mpReplacement;
87 ::boost::shared_ptr<BitmapCompressor> mpCompressor;
88 Size maBitmapSize;
89 bool mbIsUpToDate;
90 sal_Int32 mnLastAccessTime;
91 // When this flag is set then the bitmap is not modified by a cache
92 // compactor.
93 bool mbIsPrecious;
95 class CacheEntry;
97 class CacheHash {
98 public:
99 size_t operator()(const BitmapCache::CacheKey& p) const
100 { return (size_t)p; }
103 class BitmapCache::CacheBitmapContainer
104 : public ::std::hash_map<CacheKey, CacheEntry, CacheHash>
106 public:
107 CacheBitmapContainer (void) {}
110 namespace {
112 typedef ::std::vector<
113 ::std::pair< ::sd::slidesorter::cache::BitmapCache::CacheKey,
114 ::sd::slidesorter::cache::BitmapCache::CacheEntry>
115 > SortableBitmapContainer;
117 /** Compare elements of the bitmap cache according to their last access
118 time.
120 class AccessTimeComparator
122 public:
123 bool operator () (
124 const SortableBitmapContainer::value_type& e1,
125 const SortableBitmapContainer::value_type& e2)
127 return e1.second.GetAccessTime() < e2.second.GetAccessTime();
132 } // end of anonymous namespace
135 //===== BitmapCache =========================================================
137 BitmapCache::BitmapCache (const sal_Int32 nMaximalNormalCacheSize)
138 : maMutex(),
139 mpBitmapContainer(new CacheBitmapContainer()),
140 mnNormalCacheSize(0),
141 mnPreciousCacheSize(0),
142 mnCurrentAccessTime(0),
143 mnMaximalNormalCacheSize(MAXIMAL_CACHE_SIZE),
144 mpCacheCompactor(),
145 mbIsFull(false)
147 if (nMaximalNormalCacheSize > 0)
148 mnMaximalNormalCacheSize = nMaximalNormalCacheSize;
149 else
151 Any aCacheSize (CacheConfiguration::Instance()->GetValue(
152 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CacheSize"))));
153 if (aCacheSize.has<sal_Int32>())
154 aCacheSize >>= mnMaximalNormalCacheSize;
157 mpCacheCompactor = CacheCompactor::Create(*this,mnMaximalNormalCacheSize);
163 BitmapCache::~BitmapCache (void)
165 Clear();
171 void BitmapCache::Clear (void)
173 ::osl::MutexGuard aGuard (maMutex);
175 mpBitmapContainer->clear();
176 mnNormalCacheSize = 0;
177 mnPreciousCacheSize = 0;
178 mnCurrentAccessTime = 0;
184 bool BitmapCache::IsEmpty (void) const
186 return mpBitmapContainer->empty();
192 bool BitmapCache::IsFull (void) const
194 return mbIsFull;
200 sal_Int32 BitmapCache::GetSize (void)
202 return mnNormalCacheSize;
208 bool BitmapCache::HasBitmap (const CacheKey& rKey)
210 ::osl::MutexGuard aGuard (maMutex);
212 CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
213 return (iEntry != mpBitmapContainer->end()
214 && (iEntry->second.HasPreview() || iEntry->second.HasReplacement()));
220 bool BitmapCache::BitmapIsUpToDate (const CacheKey& rKey)
222 ::osl::MutexGuard aGuard (maMutex);
224 bool bIsUpToDate = false;
225 CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey));
226 if (aIterator != mpBitmapContainer->end())
227 bIsUpToDate = aIterator->second.IsUpToDate();
229 return bIsUpToDate;
235 ::boost::shared_ptr<BitmapEx> BitmapCache::GetBitmap (const CacheKey& rKey)
237 ::osl::MutexGuard aGuard (maMutex);
239 CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
240 if (iEntry == mpBitmapContainer->end())
242 // Create an empty bitmap for the given key that acts as placeholder
243 // until we are given the real one. Mark it as not being up to date.
244 SetBitmap (rKey, ::boost::shared_ptr<BitmapEx>(new BitmapEx()), false);
245 iEntry = mpBitmapContainer->find(rKey);
246 iEntry->second.SetUpToDate(false);
247 SSCD_SET_UPTODATE(iEntry->first,false);
249 else
251 iEntry->second.SetAccessTime(mnCurrentAccessTime++);
253 // Maybe we have to decompress the preview.
254 if ( ! iEntry->second.HasPreview() && iEntry->second.HasReplacement())
256 UpdateCacheSize(iEntry->second, REMOVE);
257 iEntry->second.Decompress();
258 UpdateCacheSize(iEntry->second, ADD);
261 return iEntry->second.GetPreview();
267 void BitmapCache::ReleaseBitmap (const CacheKey& rKey)
269 ::osl::MutexGuard aGuard (maMutex);
271 CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey));
272 if (aIterator != mpBitmapContainer->end())
274 UpdateCacheSize(aIterator->second, REMOVE);
275 mpBitmapContainer->erase(aIterator);
282 void BitmapCache::InvalidateBitmap (const CacheKey& rKey)
284 ::osl::MutexGuard aGuard (maMutex);
286 CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
287 if (iEntry != mpBitmapContainer->end())
289 iEntry->second.SetUpToDate(false);
290 SSCD_SET_UPTODATE(iEntry->first,false);
292 // When there is a preview then we release the replacement. The
293 // preview itself is kept until a new one is created.
294 if (iEntry->second.HasPreview())
296 UpdateCacheSize(iEntry->second, REMOVE);
297 iEntry->second.Invalidate();
298 SSCD_SET_UPTODATE(iEntry->first,false);
299 UpdateCacheSize(iEntry->second, ADD);
307 void BitmapCache::InvalidateCache (void)
309 ::osl::MutexGuard aGuard (maMutex);
311 CacheBitmapContainer::iterator iEntry;
312 for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry)
314 iEntry->second.Invalidate();
315 SSCD_SET_UPTODATE(iEntry->first,false);
317 ReCalculateTotalCacheSize();
323 void BitmapCache::SetBitmap (
324 const CacheKey& rKey,
325 const ::boost::shared_ptr<BitmapEx>& rpPreview,
326 bool bIsPrecious)
328 ::osl::MutexGuard aGuard (maMutex);
330 CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
331 if (iEntry != mpBitmapContainer->end())
333 UpdateCacheSize(iEntry->second, REMOVE);
334 iEntry->second.SetPreview(rpPreview);
335 iEntry->second.SetUpToDate(true);
336 SSCD_SET_UPTODATE(iEntry->first,true);
337 iEntry->second.SetAccessTime(mnCurrentAccessTime++);
339 else
341 iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type (
342 rKey,
343 CacheEntry (rpPreview, mnCurrentAccessTime++, bIsPrecious))
344 ).first;
347 if (iEntry != mpBitmapContainer->end())
348 UpdateCacheSize(iEntry->second, ADD);
354 bool BitmapCache::IsPrecious (const CacheKey& rKey)
356 ::osl::MutexGuard aGuard (maMutex);
358 CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey));
359 if (aIterator != mpBitmapContainer->end())
360 return aIterator->second.IsPrecious();
361 else
362 return false;
368 void BitmapCache::SetPrecious (const CacheKey& rKey, bool bIsPrecious)
370 ::osl::MutexGuard aGuard (maMutex);
372 CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
373 if (iEntry != mpBitmapContainer->end())
375 if (iEntry->second.IsPrecious() != bIsPrecious)
377 UpdateCacheSize(iEntry->second, REMOVE);
378 iEntry->second.SetPrecious(bIsPrecious);
379 UpdateCacheSize(iEntry->second, ADD);
382 else if (bIsPrecious)
384 iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type (
385 rKey,
386 CacheEntry (
387 ::boost::shared_ptr<BitmapEx>(),
388 mnCurrentAccessTime++, bIsPrecious))
389 ).first;
390 UpdateCacheSize(iEntry->second, ADD);
397 void BitmapCache::ReCalculateTotalCacheSize (void)
399 ::osl::MutexGuard aGuard (maMutex);
401 mnNormalCacheSize = 0;
402 mnPreciousCacheSize = 0;
403 CacheBitmapContainer::iterator iEntry;
404 for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry)
406 if (iEntry->second.IsPrecious())
407 mnPreciousCacheSize += iEntry->second.GetMemorySize();
408 else
409 mnNormalCacheSize += iEntry->second.GetMemorySize();
411 mbIsFull = (mnNormalCacheSize >= mnMaximalNormalCacheSize);
413 #ifdef VERBOSE
414 OSL_TRACE("cache size is %d/%d", mnNormalCacheSize, mnPreciousCacheSize);
415 #endif
421 void BitmapCache::Recycle (const BitmapCache& rCache)
423 ::osl::MutexGuard aGuard (maMutex);
425 CacheBitmapContainer::const_iterator iOtherEntry;
426 for (iOtherEntry=rCache.mpBitmapContainer->begin();
427 iOtherEntry!=rCache.mpBitmapContainer->end();
428 ++iOtherEntry)
430 CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(iOtherEntry->first));
431 if (iEntry == mpBitmapContainer->end())
433 iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type (
434 iOtherEntry->first,
435 CacheEntry(mnCurrentAccessTime++, true))
436 ).first;
437 UpdateCacheSize(iEntry->second, ADD);
439 if (iEntry != mpBitmapContainer->end())
441 UpdateCacheSize(iEntry->second, REMOVE);
442 iEntry->second.Recycle(iOtherEntry->second);
443 UpdateCacheSize(iEntry->second, ADD);
451 ::std::auto_ptr<BitmapCache::CacheIndex> BitmapCache::GetCacheIndex (
452 bool bIncludePrecious,
453 bool bIncludeNoPreview) const
455 ::osl::MutexGuard aGuard (maMutex);
457 // Create a copy of the bitmap container.
458 SortableBitmapContainer aSortedContainer;
459 aSortedContainer.reserve(mpBitmapContainer->size());
461 // Copy the relevant entries.
462 CacheBitmapContainer::iterator iEntry;
463 for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry)
465 if ( ! bIncludePrecious && iEntry->second.IsPrecious())
466 continue;
468 if ( ! bIncludeNoPreview && ! iEntry->second.HasPreview())
469 continue;
471 aSortedContainer.push_back(SortableBitmapContainer::value_type(
472 iEntry->first,iEntry->second));
475 // Sort the remaining entries.
476 ::std::sort(aSortedContainer.begin(), aSortedContainer.end(), AccessTimeComparator());
478 // Return a list with the keys of the sorted entries.
479 ::std::auto_ptr<CacheIndex> pIndex(new CacheIndex());
480 SortableBitmapContainer::iterator iIndexEntry;
481 pIndex->reserve(aSortedContainer.size());
482 for (iIndexEntry=aSortedContainer.begin(); iIndexEntry!=aSortedContainer.end(); ++iIndexEntry)
483 pIndex->push_back(iIndexEntry->first);
484 return pIndex;
490 void BitmapCache::Compress (
491 const CacheKey& rKey,
492 const ::boost::shared_ptr<BitmapCompressor>& rpCompressor)
494 ::osl::MutexGuard aGuard (maMutex);
496 CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey));
497 if (iEntry != mpBitmapContainer->end() && iEntry->second.HasPreview())
499 UpdateCacheSize(iEntry->second, REMOVE);
500 iEntry->second.Compress(rpCompressor);
501 UpdateCacheSize(iEntry->second, ADD);
508 void BitmapCache::UpdateCacheSize (const CacheEntry& rEntry, CacheOperation eOperation)
510 sal_Int32 nEntrySize (rEntry.GetMemorySize());
511 sal_Int32& rCacheSize (rEntry.IsPrecious() ? mnPreciousCacheSize : mnNormalCacheSize);
512 switch (eOperation)
514 case ADD:
515 rCacheSize += nEntrySize;
516 if ( ! rEntry.IsPrecious() && mnNormalCacheSize>mnMaximalNormalCacheSize)
518 mbIsFull = true;
519 #ifdef VERBOSE
520 OSL_TRACE("cache size is %d > %d", mnNormalCacheSize,mnMaximalNormalCacheSize);
521 #endif
522 mpCacheCompactor->RequestCompaction();
524 break;
526 case REMOVE:
527 rCacheSize -= nEntrySize;
528 if (mnNormalCacheSize < mnMaximalNormalCacheSize)
529 mbIsFull = false;
530 break;
532 default:
533 OSL_ASSERT(false);
534 break;
541 //===== CacheEntry ============================================================
543 BitmapCache::CacheEntry::CacheEntry(
544 sal_Int32 nLastAccessTime,
545 bool bIsPrecious)
546 : mpPreview(),
547 mbIsUpToDate(true),
548 mnLastAccessTime(nLastAccessTime),
549 mbIsPrecious(bIsPrecious)
556 BitmapCache::CacheEntry::CacheEntry(
557 const ::boost::shared_ptr<BitmapEx>& rpPreview,
558 sal_Int32 nLastAccessTime,
559 bool bIsPrecious)
560 : mpPreview(rpPreview),
561 mbIsUpToDate(true),
562 mnLastAccessTime(nLastAccessTime),
563 mbIsPrecious(bIsPrecious)
570 inline void BitmapCache::CacheEntry::Recycle (const CacheEntry& rEntry)
572 if ((rEntry.HasPreview() || rEntry.HasLosslessReplacement())
573 && ! (HasPreview() || HasLosslessReplacement()))
575 mpPreview = rEntry.mpPreview;
576 mpReplacement = rEntry.mpReplacement;
577 mpCompressor = rEntry.mpCompressor;
578 mnLastAccessTime = rEntry.mnLastAccessTime;
579 mbIsUpToDate = rEntry.mbIsUpToDate;
586 inline sal_Int32 BitmapCache::CacheEntry::GetMemorySize (void) const
588 sal_Int32 nSize (0);
589 if (mpPreview.get() != NULL)
590 nSize += mpPreview->GetSizeBytes();
591 if (mpReplacement.get() != NULL)
592 nSize += mpReplacement->GetMemorySize();
593 return nSize;
599 void BitmapCache::CacheEntry::Compress (const ::boost::shared_ptr<BitmapCompressor>& rpCompressor)
601 if (mpPreview.get() != NULL)
603 if (mpReplacement.get() == NULL)
605 mpReplacement = rpCompressor->Compress(mpPreview);
607 #ifdef VERBOSE
608 sal_uInt32 nOldSize (mpPreview->GetSizeBytes());
609 sal_uInt32 nNewSize (mpReplacement.get()!=NULL ? mpReplacement->GetMemorySize() : 0);
610 if (nOldSize == 0)
611 nOldSize = 1;
612 sal_Int32 nRatio (100L * nNewSize / nOldSize);
613 OSL_TRACE("compressing bitmap for %x from %d to %d bytes (%d%%)",
614 this,
615 nOldSize,
616 nNewSize,
617 nRatio);
618 #endif
620 mpCompressor = rpCompressor;
623 mpPreview.reset();
630 inline void BitmapCache::CacheEntry::Decompress (void)
632 if (mpReplacement.get()!=NULL && mpCompressor.get()!=NULL && mpPreview.get()==NULL)
634 mpPreview = mpCompressor->Decompress(*mpReplacement);
635 if ( ! mpCompressor->IsLossless())
636 mbIsUpToDate = false;
642 inline void BitmapCache::CacheEntry::SetPreview (const ::boost::shared_ptr<BitmapEx>& rpPreview)
644 mpPreview = rpPreview;
645 mpReplacement.reset();
646 mpCompressor.reset();
652 bool BitmapCache::CacheEntry::HasPreview (void) const
654 if (mpPreview.get() != NULL)
655 return mpPreview->GetSizePixel().Width()>0 && mpPreview->GetSizePixel().Height()>0;
656 else
657 return false;
663 inline bool BitmapCache::CacheEntry::HasLosslessReplacement (void) const
665 return mpReplacement.get()!=NULL
666 && mpCompressor.get()!=NULL
667 && mpCompressor->IsLossless();
671 } } } // end of namespace ::sd::slidesorter::cache