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: SlsBitmapCache.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 "SlsBitmapCache.hxx"
35 #include "SlsCacheCompactor.hxx"
36 #include "SlsBitmapCompressor.hxx"
37 #include "SlsCacheConfiguration.hxx"
39 #include "taskpane/SlideSorterCacheDisplay.hxx"
41 #include "drawdoc.hxx"
43 // Uncomment the following define for some more OSL_TRACE messages.
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
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
; }
85 ::boost::shared_ptr
<BitmapEx
> mpPreview
;
86 ::boost::shared_ptr
<BitmapReplacement
> mpReplacement
;
87 ::boost::shared_ptr
<BitmapCompressor
> mpCompressor
;
90 sal_Int32 mnLastAccessTime
;
91 // When this flag is set then the bitmap is not modified by a cache
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
>
107 CacheBitmapContainer (void) {}
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
120 class AccessTimeComparator
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
)
139 mpBitmapContainer(new CacheBitmapContainer()),
140 mnNormalCacheSize(0),
141 mnPreciousCacheSize(0),
142 mnCurrentAccessTime(0),
143 mnMaximalNormalCacheSize(MAXIMAL_CACHE_SIZE
),
147 if (nMaximalNormalCacheSize
> 0)
148 mnMaximalNormalCacheSize
= nMaximalNormalCacheSize
;
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)
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
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();
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);
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
,
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
++);
341 iEntry
= mpBitmapContainer
->insert(CacheBitmapContainer::value_type (
343 CacheEntry (rpPreview
, mnCurrentAccessTime
++, bIsPrecious
))
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();
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 (
387 ::boost::shared_ptr
<BitmapEx
>(),
388 mnCurrentAccessTime
++, bIsPrecious
))
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();
409 mnNormalCacheSize
+= iEntry
->second
.GetMemorySize();
411 mbIsFull
= (mnNormalCacheSize
>= mnMaximalNormalCacheSize
);
414 OSL_TRACE("cache size is %d/%d", mnNormalCacheSize
, mnPreciousCacheSize
);
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();
430 CacheBitmapContainer::iterator
iEntry (mpBitmapContainer
->find(iOtherEntry
->first
));
431 if (iEntry
== mpBitmapContainer
->end())
433 iEntry
= mpBitmapContainer
->insert(CacheBitmapContainer::value_type (
435 CacheEntry(mnCurrentAccessTime
++, true))
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())
468 if ( ! bIncludeNoPreview
&& ! iEntry
->second
.HasPreview())
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
);
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
);
515 rCacheSize
+= nEntrySize
;
516 if ( ! rEntry
.IsPrecious() && mnNormalCacheSize
>mnMaximalNormalCacheSize
)
520 OSL_TRACE("cache size is %d > %d", mnNormalCacheSize
,mnMaximalNormalCacheSize
);
522 mpCacheCompactor
->RequestCompaction();
527 rCacheSize
-= nEntrySize
;
528 if (mnNormalCacheSize
< mnMaximalNormalCacheSize
)
541 //===== CacheEntry ============================================================
543 BitmapCache::CacheEntry::CacheEntry(
544 sal_Int32 nLastAccessTime
,
548 mnLastAccessTime(nLastAccessTime
),
549 mbIsPrecious(bIsPrecious
)
556 BitmapCache::CacheEntry::CacheEntry(
557 const ::boost::shared_ptr
<BitmapEx
>& rpPreview
,
558 sal_Int32 nLastAccessTime
,
560 : mpPreview(rpPreview
),
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
589 if (mpPreview
.get() != NULL
)
590 nSize
+= mpPreview
->GetSizeBytes();
591 if (mpReplacement
.get() != NULL
)
592 nSize
+= mpReplacement
->GetMemorySize();
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
);
608 sal_uInt32
nOldSize (mpPreview
->GetSizeBytes());
609 sal_uInt32
nNewSize (mpReplacement
.get()!=NULL
? mpReplacement
->GetMemorySize() : 0);
612 sal_Int32
nRatio (100L * nNewSize
/ nOldSize
);
613 OSL_TRACE("compressing bitmap for %x from %d to %d bytes (%d%%)",
620 mpCompressor
= rpCompressor
;
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;
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