diff options
Diffstat (limited to 'sd/source/ui/slidesorter/cache')
23 files changed, 4464 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx new file mode 100755 index 000000000000..1bbecbef3d66 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx @@ -0,0 +1,631 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "SlsBitmapCache.hxx" +#include "SlsCacheCompactor.hxx" +#include "SlsBitmapCompressor.hxx" +#include "SlsCacheConfiguration.hxx" + +#include "taskpane/SlideSorterCacheDisplay.hxx" +#include "sdpage.hxx" +#include "drawdoc.hxx" + +// Uncomment the following define for some more OSL_TRACE messages. +#ifdef DEBUG +//#define VERBOSE +#endif + +// Define the default value for the maximal cache size that is used for +// previews that are currently not visible. The visible previews are all +// held in memory at all times. This default is used only when the +// configuration does not have a value. +static const sal_Int32 MAXIMAL_CACHE_SIZE = 4L*1024L*1024L; + +using namespace ::com::sun::star::uno; + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapCache::CacheEntry +{ +public: + CacheEntry(const ::boost::shared_ptr<BitmapEx>& rpBitmap, + sal_Int32 nLastAccessTime, bool bIsPrecious); + CacheEntry(sal_Int32 nLastAccessTime, bool bIsPrecious); + ~CacheEntry (void) {}; + inline void Recycle (const CacheEntry& rEntry); + inline sal_Int32 GetMemorySize (void) const; + void Compress (const ::boost::shared_ptr<BitmapCompressor>& rpCompressor); + inline void Decompress (void); + + bool IsUpToDate (void) const { return mbIsUpToDate; } + void SetUpToDate (bool bIsUpToDate) { mbIsUpToDate = bIsUpToDate; } + sal_Int32 GetAccessTime (void) const { return mnLastAccessTime; } + void SetAccessTime (sal_Int32 nAccessTime) { mnLastAccessTime = nAccessTime; } + ::boost::shared_ptr<BitmapEx> GetPreview (void) const { return mpPreview; } + inline void SetPreview (const ::boost::shared_ptr<BitmapEx>& rpPreview); + bool HasPreview (void) const; + bool HasReplacement (void) const { return (mpReplacement.get() != NULL); } + inline bool HasLosslessReplacement (void) const; + void Clear (void) { mpPreview.reset(); mpReplacement.reset(); mpCompressor.reset(); } + void Invalidate (void) { mpReplacement.reset(); mpCompressor.reset(); mbIsUpToDate = false; } + bool IsPrecious (void) const { return mbIsPrecious; } + void SetPrecious (bool bIsPrecious) { mbIsPrecious = bIsPrecious; } + +private: + ::boost::shared_ptr<BitmapEx> mpPreview; + ::boost::shared_ptr<BitmapReplacement> mpReplacement; + ::boost::shared_ptr<BitmapCompressor> mpCompressor; + Size maBitmapSize; + bool mbIsUpToDate; + sal_Int32 mnLastAccessTime; + // When this flag is set then the bitmap is not modified by a cache + // compactor. + bool mbIsPrecious; +}; +class CacheEntry; + +class CacheHash { +public: + size_t operator()(const BitmapCache::CacheKey& p) const + { return (size_t)p; } +}; + +class BitmapCache::CacheBitmapContainer + : public ::std::hash_map<CacheKey, CacheEntry, CacheHash> +{ +public: + CacheBitmapContainer (void) {} +}; + +namespace { + +typedef ::std::vector< + ::std::pair< ::sd::slidesorter::cache::BitmapCache::CacheKey, + ::sd::slidesorter::cache::BitmapCache::CacheEntry> + > SortableBitmapContainer; + + /** Compare elements of the bitmap cache according to their last access + time. + */ + class AccessTimeComparator + { + public: + bool operator () ( + const SortableBitmapContainer::value_type& e1, + const SortableBitmapContainer::value_type& e2) + { + return e1.second.GetAccessTime() < e2.second.GetAccessTime(); + } + }; + + +} // end of anonymous namespace + + +//===== BitmapCache ========================================================= + +BitmapCache::BitmapCache (const sal_Int32 nMaximalNormalCacheSize) + : maMutex(), + mpBitmapContainer(new CacheBitmapContainer()), + mnNormalCacheSize(0), + mnPreciousCacheSize(0), + mnCurrentAccessTime(0), + mnMaximalNormalCacheSize(MAXIMAL_CACHE_SIZE), + mpCacheCompactor(), + mbIsFull(false) +{ + if (nMaximalNormalCacheSize > 0) + mnMaximalNormalCacheSize = nMaximalNormalCacheSize; + else + { + Any aCacheSize (CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CacheSize")))); + if (aCacheSize.has<sal_Int32>()) + aCacheSize >>= mnMaximalNormalCacheSize; + } + + mpCacheCompactor = CacheCompactor::Create(*this,mnMaximalNormalCacheSize); +} + + + + +BitmapCache::~BitmapCache (void) +{ + Clear(); +} + + + + +void BitmapCache::Clear (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + mpBitmapContainer->clear(); + mnNormalCacheSize = 0; + mnPreciousCacheSize = 0; + mnCurrentAccessTime = 0; +} + + + + +bool BitmapCache::IsFull (void) const +{ + return mbIsFull; +} + + + + +sal_Int32 BitmapCache::GetSize (void) +{ + return mnNormalCacheSize; +} + + + + +bool BitmapCache::HasBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + return (iEntry != mpBitmapContainer->end() + && (iEntry->second.HasPreview() || iEntry->second.HasReplacement())); +} + + + + +bool BitmapCache::BitmapIsUpToDate (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + bool bIsUpToDate = false; + CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey)); + if (aIterator != mpBitmapContainer->end()) + bIsUpToDate = aIterator->second.IsUpToDate(); + + return bIsUpToDate; +} + + + + +::boost::shared_ptr<BitmapEx> BitmapCache::GetBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry == mpBitmapContainer->end()) + { + // Create an empty bitmap for the given key that acts as placeholder + // until we are given the real one. Mark it as not being up to date. + SetBitmap (rKey, ::boost::shared_ptr<BitmapEx>(new BitmapEx()), false); + iEntry = mpBitmapContainer->find(rKey); + iEntry->second.SetUpToDate(false); + SSCD_SET_UPTODATE(iEntry->first,false); + } + else + { + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + + // Maybe we have to decompress the preview. + if ( ! iEntry->second.HasPreview() && iEntry->second.HasReplacement()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.Decompress(); + UpdateCacheSize(iEntry->second, ADD); + } + } + return iEntry->second.GetPreview(); +} + + + + +void BitmapCache::InvalidateBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + iEntry->second.SetUpToDate(false); + SSCD_SET_UPTODATE(iEntry->first,false); + + // When there is a preview then we release the replacement. The + // preview itself is kept until a new one is created. + if (iEntry->second.HasPreview()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.Invalidate(); + SSCD_SET_UPTODATE(iEntry->first,false); + UpdateCacheSize(iEntry->second, ADD); + } + } +} + + + + +void BitmapCache::InvalidateCache (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry; + for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry) + { + iEntry->second.Invalidate(); + SSCD_SET_UPTODATE(iEntry->first,false); + } + ReCalculateTotalCacheSize(); +} + + + + +void BitmapCache::SetBitmap ( + const CacheKey& rKey, + const ::boost::shared_ptr<BitmapEx>& rpPreview, + bool bIsPrecious) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.SetPreview(rpPreview); + iEntry->second.SetUpToDate(true); + SSCD_SET_UPTODATE(iEntry->first,true); + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + } + else + { + iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( + rKey, + CacheEntry (rpPreview, mnCurrentAccessTime++, bIsPrecious)) + ).first; + } + + if (iEntry != mpBitmapContainer->end()) + UpdateCacheSize(iEntry->second, ADD); +} + + + + +void BitmapCache::SetPrecious (const CacheKey& rKey, bool bIsPrecious) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + if (iEntry->second.IsPrecious() != bIsPrecious) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.SetPrecious(bIsPrecious); + UpdateCacheSize(iEntry->second, ADD); + } + } + else if (bIsPrecious) + { + iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( + rKey, + CacheEntry ( + ::boost::shared_ptr<BitmapEx>(), + mnCurrentAccessTime++, bIsPrecious)) + ).first; + UpdateCacheSize(iEntry->second, ADD); + } +} + + + + +void BitmapCache::ReCalculateTotalCacheSize (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + mnNormalCacheSize = 0; + mnPreciousCacheSize = 0; + CacheBitmapContainer::iterator iEntry; + for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry) + { + if (iEntry->second.IsPrecious()) + mnPreciousCacheSize += iEntry->second.GetMemorySize(); + else + mnNormalCacheSize += iEntry->second.GetMemorySize(); + } + mbIsFull = (mnNormalCacheSize >= mnMaximalNormalCacheSize); + +#ifdef VERBOSE + OSL_TRACE("cache size is %d/%d", mnNormalCacheSize, mnPreciousCacheSize); +#endif +} + + + + +void BitmapCache::Recycle (const BitmapCache& rCache) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::const_iterator iOtherEntry; + for (iOtherEntry=rCache.mpBitmapContainer->begin(); + iOtherEntry!=rCache.mpBitmapContainer->end(); + ++iOtherEntry) + { + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(iOtherEntry->first)); + if (iEntry == mpBitmapContainer->end()) + { + iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( + iOtherEntry->first, + CacheEntry(mnCurrentAccessTime++, true)) + ).first; + UpdateCacheSize(iEntry->second, ADD); + } + if (iEntry != mpBitmapContainer->end()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.Recycle(iOtherEntry->second); + UpdateCacheSize(iEntry->second, ADD); + } + } +} + + + + +::std::auto_ptr<BitmapCache::CacheIndex> BitmapCache::GetCacheIndex ( + bool bIncludePrecious, + bool bIncludeNoPreview) const +{ + ::osl::MutexGuard aGuard (maMutex); + + // Create a copy of the bitmap container. + SortableBitmapContainer aSortedContainer; + aSortedContainer.reserve(mpBitmapContainer->size()); + + // Copy the relevant entries. + CacheBitmapContainer::iterator iEntry; + for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry) + { + if ( ! bIncludePrecious && iEntry->second.IsPrecious()) + continue; + + if ( ! bIncludeNoPreview && ! iEntry->second.HasPreview()) + continue; + + aSortedContainer.push_back(SortableBitmapContainer::value_type( + iEntry->first,iEntry->second)); + } + + // Sort the remaining entries. + ::std::sort(aSortedContainer.begin(), aSortedContainer.end(), AccessTimeComparator()); + + // Return a list with the keys of the sorted entries. + ::std::auto_ptr<CacheIndex> pIndex(new CacheIndex()); + SortableBitmapContainer::iterator iIndexEntry; + pIndex->reserve(aSortedContainer.size()); + for (iIndexEntry=aSortedContainer.begin(); iIndexEntry!=aSortedContainer.end(); ++iIndexEntry) + pIndex->push_back(iIndexEntry->first); + return pIndex; +} + + + + +void BitmapCache::Compress ( + const CacheKey& rKey, + const ::boost::shared_ptr<BitmapCompressor>& rpCompressor) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end() && iEntry->second.HasPreview()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.Compress(rpCompressor); + UpdateCacheSize(iEntry->second, ADD); + } +} + + + + +void BitmapCache::UpdateCacheSize (const CacheEntry& rEntry, CacheOperation eOperation) +{ + sal_Int32 nEntrySize (rEntry.GetMemorySize()); + sal_Int32& rCacheSize (rEntry.IsPrecious() ? mnPreciousCacheSize : mnNormalCacheSize); + switch (eOperation) + { + case ADD: + rCacheSize += nEntrySize; + if ( ! rEntry.IsPrecious() && mnNormalCacheSize>mnMaximalNormalCacheSize) + { + mbIsFull = true; +#ifdef VERBOSE + OSL_TRACE("cache size is %d > %d", mnNormalCacheSize,mnMaximalNormalCacheSize); +#endif + mpCacheCompactor->RequestCompaction(); + } + break; + + case REMOVE: + rCacheSize -= nEntrySize; + if (mnNormalCacheSize < mnMaximalNormalCacheSize) + mbIsFull = false; + break; + + default: + OSL_ASSERT(false); + break; + } +} + + + + +//===== CacheEntry ============================================================ + +BitmapCache::CacheEntry::CacheEntry( + sal_Int32 nLastAccessTime, + bool bIsPrecious) + : mpPreview(), + mbIsUpToDate(true), + mnLastAccessTime(nLastAccessTime), + mbIsPrecious(bIsPrecious) +{ +} + + + + +BitmapCache::CacheEntry::CacheEntry( + const ::boost::shared_ptr<BitmapEx>& rpPreview, + sal_Int32 nLastAccessTime, + bool bIsPrecious) + : mpPreview(rpPreview), + mbIsUpToDate(true), + mnLastAccessTime(nLastAccessTime), + mbIsPrecious(bIsPrecious) +{ +} + + + + +inline void BitmapCache::CacheEntry::Recycle (const CacheEntry& rEntry) +{ + if ((rEntry.HasPreview() || rEntry.HasLosslessReplacement()) + && ! (HasPreview() || HasLosslessReplacement())) + { + mpPreview = rEntry.mpPreview; + mpReplacement = rEntry.mpReplacement; + mpCompressor = rEntry.mpCompressor; + mnLastAccessTime = rEntry.mnLastAccessTime; + mbIsUpToDate = rEntry.mbIsUpToDate; + } +} + + + + +inline sal_Int32 BitmapCache::CacheEntry::GetMemorySize (void) const +{ + sal_Int32 nSize (0); + if (mpPreview.get() != NULL) + nSize += mpPreview->GetSizeBytes(); + if (mpReplacement.get() != NULL) + nSize += mpReplacement->GetMemorySize(); + return nSize; +} + + + + +void BitmapCache::CacheEntry::Compress (const ::boost::shared_ptr<BitmapCompressor>& rpCompressor) +{ + if (mpPreview.get() != NULL) + { + if (mpReplacement.get() == NULL) + { + mpReplacement = rpCompressor->Compress(mpPreview); + +#ifdef VERBOSE + sal_uInt32 nOldSize (mpPreview->GetSizeBytes()); + sal_uInt32 nNewSize (mpReplacement.get()!=NULL ? mpReplacement->GetMemorySize() : 0); + if (nOldSize == 0) + nOldSize = 1; + sal_Int32 nRatio (100L * nNewSize / nOldSize); + OSL_TRACE("compressing bitmap for %x from %d to %d bytes (%d%%)", + this, + nOldSize, + nNewSize, + nRatio); +#endif + + mpCompressor = rpCompressor; + } + + mpPreview.reset(); + } +} + + + + +inline void BitmapCache::CacheEntry::Decompress (void) +{ + if (mpReplacement.get()!=NULL && mpCompressor.get()!=NULL && mpPreview.get()==NULL) + { + mpPreview = mpCompressor->Decompress(*mpReplacement); + if ( ! mpCompressor->IsLossless()) + mbIsUpToDate = false; + } +} + + + +inline void BitmapCache::CacheEntry::SetPreview (const ::boost::shared_ptr<BitmapEx>& rpPreview) +{ + mpPreview = rpPreview; + mpReplacement.reset(); + mpCompressor.reset(); +} + + + + +bool BitmapCache::CacheEntry::HasPreview (void) const +{ + if (mpPreview.get() != NULL) + return mpPreview->GetSizePixel().Width()>0 && mpPreview->GetSizePixel().Height()>0; + else + return false; +} + + + + +inline bool BitmapCache::CacheEntry::HasLosslessReplacement (void) const +{ + return mpReplacement.get()!=NULL + && mpCompressor.get()!=NULL + && mpCompressor->IsLossless(); +} + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx new file mode 100755 index 000000000000..2c33e042342f --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx @@ -0,0 +1,211 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_BITMAP_CACHE_HXX +#define SD_SLIDESORTER_BITMAP_CACHE_HXX + +class SdrPage; + +#include <vcl/bitmapex.hxx> +#include <osl/mutex.hxx> +#include <memory> +#include <boost/shared_ptr.hpp> +#include <hash_map> + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapReplacement; +class CacheCompactor; +class BitmapCompressor; + +/** This low level cache is the actual bitmap container. It supports a + precious flag for every preview bitmap and keeps track of total sizes + for all previews with as well as those without the flag. The precious + flag is used by compaction algorithms to determine which previews may be + compressed or even discarded and which have to remain in their original + form. The precious flag is usually set for the visible previews. +*/ +class BitmapCache +{ +public: + /** The key for looking up preview bitmaps is a pointer to an SdrPage + object. The prior use of PageObjectViewObjectContact objects (which + ultimatly use them) turned out to be less suitable because their + life time is shorter then that of the page objects. Frequent + destruction and re-creation of the preview bitmaps was the result. + */ + typedef const SdrPage* CacheKey; + class CacheEntry; + class CacheBitmapContainer; + typedef ::std::vector<CacheKey> CacheIndex; + + /** Create a new cache for bitmap objects. + @param nMaximalNormalCacheSize + When a size larger then zero is given then that size is used. + Otherwise the default value from the configuration is used. + When that does not exist either then a internal default value is + used. + */ + BitmapCache (const sal_Int32 nMaximalNormalCacheSize = 0); + + /** The destructor clears the cache and relases all bitmaps still in it. + */ + ~BitmapCache (void); + + /** Remove all preview bitmaps from the cache. After this call the + cache is empty. + */ + void Clear (void); + + /** Return <TRUE/> when the cache is full, i.e. the cache compactor had + to be run. + */ + bool IsFull (void) const; + + /** Return the memory size that is occupied by all non-precious bitmaps + in the cache. + */ + sal_Int32 GetSize (void); + + /** Return <TRUE/> when a preview bitmap exists for the given key. + */ + bool HasBitmap (const CacheKey& rKey); + + /** Return <TRUE/> when a preview bitmap exists for the given key and + when it is up-to-date. + */ + bool BitmapIsUpToDate (const CacheKey& rKey); + + /** Return the preview bitmap for the given contact object. + */ + ::boost::shared_ptr<BitmapEx> GetBitmap (const CacheKey& rKey); + + /** Mark the specified preview bitmap as not being up-to-date anymore. + */ + void InvalidateBitmap (const CacheKey& rKey); + + /** Mark all preview bitmaps as not being up-to-date anymore. + */ + void InvalidateCache (void); + + /** Add or replace a bitmap for the given key. + */ + void SetBitmap ( + const CacheKey& rKey, + const ::boost::shared_ptr<BitmapEx>& rpPreview, + bool bIsPrecious); + + /** Mark the specified preview bitmap as precious, i.e. that it must not + be compressed or otherwise removed from the cache. + */ + void SetPrecious (const CacheKey& rKey, bool bIsPrecious); + + /** Calculate the cache size. This should rarely be necessary because + the cache size is tracked with each modification of preview + bitmaps. + */ + void ReCalculateTotalCacheSize (void); + + /** Use the previews in the given cache to initialize missing previews. + */ + void Recycle (const BitmapCache& rCache); + + /** Return a list of sorted cache keys that represent an index into (a + part of) the cache. The entries of the index are sorted according + to last access times with the least recently access time first. + @param bIncludePrecious + When this flag is <TRUE/> entries with the precious flag set are + included in the index. When the flag is <FALSE/> these entries + are ommited. + @param bIncludeNoPreview + When this flag is <TRUE/> entries with that have no preview + bitmaps are included in the index. When the flag is <FALSE/> these entries + are ommited. + */ + ::std::auto_ptr<CacheIndex> GetCacheIndex ( + bool bIncludePrecious, + bool bIncludeNoPreview) const; + + /** Compress the specified preview bitmap with the given bitmap + compressor. A reference to the compressor is stored for later + decompression. + */ + void Compress ( + const CacheKey& rKey, + const ::boost::shared_ptr<BitmapCompressor>& rpCompressor); + +private: + mutable ::osl::Mutex maMutex; + + ::std::auto_ptr<CacheBitmapContainer> mpBitmapContainer; + + /** Total size of bytes that are occupied by bitmaps in the cache for + whom the slides are currently not inside the visible area. + */ + sal_Int32 mnNormalCacheSize; + + /** Total size of bytes that are occupied by bitmaps in the cache for + whom the slides are currently visible. + */ + sal_Int32 mnPreciousCacheSize; + + /** At the moment the access time is not an actual time or date value + but a counter that is increased with every access. It thus defines + the same ordering as a true time. + */ + sal_Int32 mnCurrentAccessTime; + + /** The maximal cache size for the off-screen preview bitmaps. When + mnNormalCacheSize grows larger than this value then the + mpCacheCompactor member is used to reduce the cache size. + */ + sal_Int32 mnMaximalNormalCacheSize; + + /** The cache compactor is used to reduce the number of bytes used by + off-screen preview bitmaps. + */ + ::std::auto_ptr<CacheCompactor> mpCacheCompactor; + + /** This flag stores if the cache is or recently was full, i.e. the + cache compactor has or had to be run in order to reduce the cache + size to the allowed value. + */ + bool mbIsFull; + + /** Update mnNormalCacheSize or mnPreciousCacheSize according to the + precious flag of the specified preview bitmap and the specified + operation. + */ + enum CacheOperation { ADD, REMOVE }; + void UpdateCacheSize (const CacheEntry& rKey, CacheOperation eOperation); +}; + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx new file mode 100644 index 000000000000..86fc72885414 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx @@ -0,0 +1,273 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "SlsBitmapCompressor.hxx" + +#include <tools/stream.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/pngread.hxx> +#include <vcl/pngwrite.hxx> + +namespace sd { namespace slidesorter { namespace cache { + + +//===== NoBitmapCompression =================================================== + +/** This dummy replacement simply stores a shared pointer to the original + preview bitmap. +*/ +class NoBitmapCompression::DummyReplacement + : public BitmapReplacement +{ +public: + ::boost::shared_ptr<BitmapEx> mpPreview; + Size maOriginalSize; + + DummyReplacement (const ::boost::shared_ptr<BitmapEx>& rpPreview) : mpPreview(rpPreview) + { + } + + virtual ~DummyReplacement(); + + virtual sal_Int32 GetMemorySize (void) const; +}; + +NoBitmapCompression::DummyReplacement::~DummyReplacement() +{ +} + +sal_Int32 NoBitmapCompression::DummyReplacement::GetMemorySize (void) const +{ + return mpPreview->GetSizeBytes(); +} + +::boost::shared_ptr<BitmapReplacement> NoBitmapCompression::Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const +{ + return ::boost::shared_ptr<BitmapReplacement>(new DummyReplacement(rpBitmap)); +} + +::boost::shared_ptr<BitmapEx> NoBitmapCompression::Decompress ( + const BitmapReplacement& rBitmapData) const +{ + return dynamic_cast<const DummyReplacement&>(rBitmapData).mpPreview; +} + + + + +bool NoBitmapCompression::IsLossless (void) const +{ + return true; +} + + + + +//===== CompressionByDeletion ================================================= + +::boost::shared_ptr<BitmapReplacement> CompressionByDeletion::Compress ( + const ::boost::shared_ptr<BitmapEx>& ) const +{ + return ::boost::shared_ptr<BitmapReplacement>(); +} + + + + +::boost::shared_ptr<BitmapEx> CompressionByDeletion::Decompress ( + const BitmapReplacement& ) const +{ + // Return a NULL pointer. This will eventually lead to a request for + // the creation of a new one. + return ::boost::shared_ptr<BitmapEx>(); +} + + + + +bool CompressionByDeletion::IsLossless (void) const +{ + return false; +} + + + + +//===== ResolutionReduction =================================================== + +/** Store a scaled down bitmap together with the original size. +*/ +class ResolutionReduction::ResolutionReducedReplacement : public BitmapReplacement +{ +public: + ::boost::shared_ptr<BitmapEx> mpPreview; + Size maOriginalSize; + + virtual ~ResolutionReducedReplacement(); + + virtual sal_Int32 GetMemorySize (void) const; +}; + +ResolutionReduction::ResolutionReducedReplacement::~ResolutionReducedReplacement() +{ +} + +sal_Int32 ResolutionReduction::ResolutionReducedReplacement::GetMemorySize (void) const +{ + if (mpPreview.get() != NULL) + return mpPreview->GetSizeBytes(); + else + return 0; +} + +::boost::shared_ptr<BitmapReplacement> ResolutionReduction::Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const +{ + ResolutionReducedReplacement* pResult = new ResolutionReducedReplacement(); + pResult->mpPreview.reset(new BitmapEx(*rpBitmap)); + Size aSize (rpBitmap->GetSizePixel()); + pResult->maOriginalSize = aSize; + if (aSize.Width()>0 && aSize.Width()<mnWidth) + { + int nHeight = aSize.Height() * mnWidth / aSize.Width() ; + pResult->mpPreview->Scale(Size(mnWidth,nHeight)); + } + + return ::boost::shared_ptr<BitmapReplacement>(pResult); +} + + + + +::boost::shared_ptr<BitmapEx> ResolutionReduction::Decompress ( + const BitmapReplacement& rBitmapData) const +{ + ::boost::shared_ptr<BitmapEx> pResult; + + const ResolutionReducedReplacement* pData ( + dynamic_cast<const ResolutionReducedReplacement*>(&rBitmapData)); + + if (pData->mpPreview.get() != NULL) + { + pResult.reset(new BitmapEx(*pData->mpPreview)); + if (pData->maOriginalSize.Width() > mnWidth) + pResult->Scale(pData->maOriginalSize); + } + + return pResult; +} + + + + +bool ResolutionReduction::IsLossless (void) const +{ + return false; +} + + + + +//===== PNGCompression ======================================================== + + +class PngCompression::PngReplacement : public BitmapReplacement +{ +public: + void* mpData; + sal_Int32 mnDataSize; + Size maImageSize; + PngReplacement (void) + : mpData(NULL), + mnDataSize(0), + maImageSize(0,0) + {} + virtual ~PngReplacement (void) + { + delete [] (char*)mpData; + } + virtual sal_Int32 GetMemorySize (void) const + { + return mnDataSize; + } +}; + + + + +::boost::shared_ptr<BitmapReplacement> PngCompression::Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const +{ + ::vcl::PNGWriter aWriter (*rpBitmap); + SvMemoryStream aStream (32768, 32768); + aWriter.Write(aStream); + + PngReplacement* pResult = new PngReplacement(); + pResult->maImageSize = rpBitmap->GetSizePixel(); + pResult->mnDataSize = aStream.Tell(); + pResult->mpData = new char[pResult->mnDataSize]; + memcpy(pResult->mpData, aStream.GetData(), pResult->mnDataSize); + + return ::boost::shared_ptr<BitmapReplacement>(pResult); +} + + + + +::boost::shared_ptr<BitmapEx> PngCompression::Decompress ( + const BitmapReplacement& rBitmapData) const +{ + BitmapEx* pResult = NULL; + const PngReplacement* pData (dynamic_cast<const PngReplacement*>(&rBitmapData)); + if (pData != NULL) + { + SvMemoryStream aStream (pData->mpData, pData->mnDataSize, STREAM_READ); + ::vcl::PNGReader aReader (aStream); + pResult = new BitmapEx(aReader.Read()); + } + +// sal_Int32 nRatio ((100L * (ULONG)pResult->GetSizeBytes()) / (ULONG)pData->mnDataSize); + + return ::boost::shared_ptr<BitmapEx>(pResult); +} + + + + +bool PngCompression::IsLossless (void) const +{ + return true; +} + + + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx new file mode 100644 index 000000000000..cd564ddddcfd --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx @@ -0,0 +1,160 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_BITMAP_COMPRESSOR_HXX +#define SD_SLIDESORTER_BITMAP_COMPRESSOR_HXX + +#include <sal/types.h> +#include <tools/gen.hxx> +#include <boost/shared_ptr.hpp> + +class BitmapEx; + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapReplacement; + + +/** This interface class provides the minimal method set for classes that + implement the compression and decompression of preview bitmaps. +*/ +class BitmapCompressor +{ +public: + /** Compress the given bitmap into a replacement format that is specific + to the compressor class. + */ + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const = 0; + + /** Decompress the given replacement data into a preview bitmap. + Depending on the compression technique the returned bitmap may + differ from the original bitmap given to the Compress() method. It + may even of the wrong size or empty or the NULL pointer. It is the + task of the caller to create a new preview bitmap if the returned + one is not as desired. + */ + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData)const=0; + + /** Return whether the compression and decompression is lossless. This + value is used by the caller of Decompress() to decide whether to use + the returned bitmap as is or if a new preview has to be created. + */ + virtual bool IsLossless (void) const = 0; +}; + + + +/** Interface for preview bitmap replacements. Each bitmap + compressor/decompressor has to provide an implementation that is + suitable to store the compressed bitmaps. +*/ +class BitmapReplacement +{ +public: + virtual sal_Int32 GetMemorySize (void) const { return 0; } +}; + + + + +/** This is one trivial bitmap compressor. It stores bitmaps unmodified + instead of compressing them. + This compressor is lossless. +*/ +class NoBitmapCompression + : public BitmapCompressor +{ + class DummyReplacement; +public: + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + + + +/** This is another trivial bitmap compressor. Instead of compressing a + bitmap, it throws the bitmap away. Its Decompress() method returns a + NULL pointer. The caller has to create a new preview bitmap instead. + This compressor clearly is not lossless. +*/ +class CompressionByDeletion + : public BitmapCompressor +{ +public: + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + + + +/** Compress a preview bitmap by reducing its resolution. While the aspect + ratio is maintained the horizontal resolution is scaled down to 100 + pixels. + This compressor is not lossless. +*/ +class ResolutionReduction + : public BitmapCompressor +{ + class ResolutionReducedReplacement; + static const sal_Int32 mnWidth = 100; +public: + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + /** Scale the replacement bitmap up to the original size. + */ + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + + + +/** Compress preview bitmaps using the PNG format. + This compressor is lossless. +*/ +class PngCompression + : public BitmapCompressor +{ + class PngReplacement; +public: + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx new file mode 100644 index 000000000000..5ad30ef43c1f --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx @@ -0,0 +1,81 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsBitmapFactory.hxx" + +#include "PreviewRenderer.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "sdpage.hxx" +#include "Window.hxx" +#include <svx/svdtypes.hxx> +#include <svx/svdpage.hxx> +#include <vcl/bitmapex.hxx> + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +class PageObjectViewObjectContact; +} } } + +namespace sd { namespace slidesorter { namespace cache { + +BitmapFactory::BitmapFactory (void) + : maRenderer(NULL,false) +{ +} + + + + +BitmapFactory::~BitmapFactory (void) +{ +} + + + + +::boost::shared_ptr<BitmapEx> BitmapFactory::CreateBitmap ( + const SdPage& rPage, + const Size& rPixelSize) +{ + Image aPreview (maRenderer.RenderPage ( + &rPage, + rPixelSize, + String())); + + return ::boost::shared_ptr<BitmapEx>(new BitmapEx(aPreview.GetBitmapEx())); +} + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx new file mode 100644 index 000000000000..87cd1f268f80 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx @@ -0,0 +1,65 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_PREVIEW_BITMAP_FACTORY_HXX +#define SD_SLIDESORTER_PREVIEW_BITMAP_FACTORY_HXX + +#include "PreviewRenderer.hxx" +#include <boost/shared_ptr.hpp> + +class BitmapEx; +class SdPage; +class Size; + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + +namespace sd { namespace slidesorter { namespace cache { + +/** This factory class creates preview bitmaps for page objects. It is + merely an adapter for the PreviewRenderer. +*/ +class BitmapFactory +{ +public: + BitmapFactory (void); + ~BitmapFactory (void); + + ::boost::shared_ptr<BitmapEx> CreateBitmap ( + const SdPage& rPage, + const Size& rPixelSize); + +private: + PreviewRenderer maRenderer; +}; + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx new file mode 100644 index 000000000000..520ce4ce2cf8 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx @@ -0,0 +1,236 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "SlsCacheCompactor.hxx" + +#include "SlsBitmapCompressor.hxx" +#include "SlsBitmapCache.hxx" +#include "SlsCacheCompactor.hxx" +#include "SlsCacheConfiguration.hxx" + +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <set> + +using namespace ::com::sun::star::uno; + +// Uncomment the definition of VERBOSE to get some more OSL_TRACE messages. +#ifdef DEBUG +//#define VERBOSE +#endif + +namespace { + +/** This is a trivial implementation of the CacheCompactor interface class. + It ignores calls to RequestCompaction() and thus will never decrease the + total size of off-screen preview bitmaps. +*/ +class NoCacheCompaction + : public ::sd::slidesorter::cache::CacheCompactor +{ +public: + NoCacheCompaction ( + ::sd::slidesorter::cache::BitmapCache& rCache, + sal_Int32 nMaximalCacheSize) + : CacheCompactor(rCache, nMaximalCacheSize) + {} + + virtual void RequestCompaction (void) { /* Ignored */ }; + +protected: + virtual void Run (void) { /* Do nothing */ }; +}; + + + + +/** This implementation of the CacheCompactor interface class uses one of + several bitmap compression algorithms to reduce the number of the bytes + of the off-screen previews in the bitmap cache. See the documentation + of CacheCompactor::Create() for more details on configuration properties + that control the choice of compression algorithm. +*/ +class CacheCompactionByCompression + : public ::sd::slidesorter::cache::CacheCompactor +{ +public: + CacheCompactionByCompression ( + ::sd::slidesorter::cache::BitmapCache& rCache, + sal_Int32 nMaximalCacheSize, + const ::boost::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor>& rpCompressor); + +protected: + virtual void Run (void); + +private: + ::boost::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor> mpCompressor; +}; + + +} // end of anonymous namespace + +namespace sd { namespace slidesorter { namespace cache { + + +::std::auto_ptr<CacheCompactor> CacheCompactor::Create ( + BitmapCache& rCache, + sal_Int32 nMaximalCacheSize) +{ + static const ::rtl::OUString sNone (RTL_CONSTASCII_USTRINGPARAM("None")); + static const ::rtl::OUString sCompress (RTL_CONSTASCII_USTRINGPARAM("Compress")); + static const ::rtl::OUString sErase (RTL_CONSTASCII_USTRINGPARAM("Erase")); + static const ::rtl::OUString sResolution (RTL_CONSTASCII_USTRINGPARAM("ResolutionReduction")); + static const ::rtl::OUString sPNGCompression (RTL_CONSTASCII_USTRINGPARAM("PNGCompression")); + + ::boost::shared_ptr<BitmapCompressor> pCompressor; + ::rtl::OUString sCompressionPolicy(sPNGCompression); + Any aCompressionPolicy (CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CompressionPolicy")))); + if (aCompressionPolicy.has<rtl::OUString>()) + aCompressionPolicy >>= sCompressionPolicy; + if (sCompressionPolicy == sNone) + pCompressor.reset(new NoBitmapCompression()); + else if (sCompressionPolicy == sErase) + pCompressor.reset(new CompressionByDeletion()); + else if (sCompressionPolicy == sResolution) + pCompressor.reset(new ResolutionReduction()); + else + pCompressor.reset(new PngCompression()); + + ::std::auto_ptr<CacheCompactor> pCompactor (NULL); + ::rtl::OUString sCompactionPolicy(sCompress); + Any aCompactionPolicy (CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CompactionPolicy")))); + if (aCompactionPolicy.has<rtl::OUString>()) + aCompactionPolicy >>= sCompactionPolicy; + if (sCompactionPolicy == sNone) + pCompactor.reset(new NoCacheCompaction(rCache,nMaximalCacheSize)); + else + pCompactor.reset(new CacheCompactionByCompression(rCache,nMaximalCacheSize,pCompressor)); + + return pCompactor; +} + + + + +void CacheCompactor::RequestCompaction (void) +{ + if ( ! mbIsCompactionRunning && ! maCompactionTimer.IsActive()) + maCompactionTimer.Start(); +} + + + + +CacheCompactor::CacheCompactor( + BitmapCache& rCache, + sal_Int32 nMaximalCacheSize) + : mrCache(rCache), + mnMaximalCacheSize(nMaximalCacheSize), + mbIsCompactionRunning(false) +{ + maCompactionTimer.SetTimeout(100 /*ms*/); + maCompactionTimer.SetTimeoutHdl(LINK(this,CacheCompactor,CompactionCallback)); + +} + + + + +IMPL_LINK(CacheCompactor, CompactionCallback, Timer*, EMPTYARG) +{ + mbIsCompactionRunning = true; + + try + { + Run(); + } + catch(::com::sun::star::uno::RuntimeException e) { } + catch(::com::sun::star::uno::Exception e) { } + + mbIsCompactionRunning = false; + return 1; +} + + + + +} } } // end of namespace ::sd::slidesorter::cache + + + + +namespace { + +//===== CacheCompactionByCompression ========================================== + +CacheCompactionByCompression::CacheCompactionByCompression ( + ::sd::slidesorter::cache::BitmapCache& rCache, + sal_Int32 nMaximalCacheSize, + const ::boost::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor>& rpCompressor) + : CacheCompactor(rCache,nMaximalCacheSize), + mpCompressor(rpCompressor) +{ +} + + + + +void CacheCompactionByCompression::Run (void) +{ + if (mrCache.GetSize() > mnMaximalCacheSize) + { +#ifdef VERBOSE + OSL_TRACE ("bitmap cache uses to much space: %d > %d", + mrCache.GetSize(), mnMaximalCacheSize); +#endif + + ::std::auto_ptr< ::sd::slidesorter::cache::BitmapCache::CacheIndex> pIndex ( + mrCache.GetCacheIndex(false,false)); + ::sd::slidesorter::cache::BitmapCache::CacheIndex::iterator iIndex; + for (iIndex=pIndex->begin(); iIndex!=pIndex->end(); ++iIndex) + { + if (*iIndex == NULL) + continue; + + mrCache.Compress(*iIndex, mpCompressor); + if (mrCache.GetSize() < mnMaximalCacheSize) + break; + } + mrCache.ReCalculateTotalCacheSize(); +#ifdef VERBOSE + OSL_TRACE (" there are now %d bytes occupied", mrCache.GetSize()); +#endif + } +} + + +} // end of anonymous namespace diff --git a/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx new file mode 100644 index 000000000000..84e450dcfbc9 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_CACHE_COMPACTOR_HXX +#define SD_SLIDESORTER_CACHE_COMPACTOR_HXX + +#include <sal/types.h> +#include <vcl/timer.hxx> +#include <memory> + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapCache; +class BitmapCompressor; + +/** This is an interface class whose implementations are created via the + Create() factory method. +*/ +class CacheCompactor +{ +public: + virtual ~CacheCompactor (void) {}; + + /** Create a new instance of the CacheCompactor interface class. The + type of compaction algorithm used depends on values from the + configuration: the SlideSorter/PreviewCache/CompactionPolicy + property of the Impress.xcs file currently supports the values + "None" and "Compress". With the later the CompressionPolicy + property is evaluated which implementation of the BitmapCompress + interface class to use as bitmap compressor. + @param rCache + The bitmap cache on which to operate. + @param nMaximalCacheSize + The total number of bytes the off-screen bitmaps in the cache + may have. When the Run() method is (indirectly) called the + compactor tries to reduce that summed size of off-screen bitmaps + under this number. However, it is not guaranteed that this + works in all cases. + */ + static ::std::auto_ptr<CacheCompactor> Create ( + BitmapCache& rCache, + sal_Int32 nMaximalCacheSize); + + /** Request a compaction of the off-screen previews in the bitmap + cache. This calls via a timer the Run() method. + */ + virtual void RequestCompaction (void); + +protected: + BitmapCache& mrCache; + sal_Int32 mnMaximalCacheSize; + + CacheCompactor( + BitmapCache& rCache, + sal_Int32 nMaximalCacheSize); + + /** This method actually tries to reduce the total number of bytes used + by the off-screen preview bitmaps. + */ + virtual void Run (void) = 0; + +private: + /** This timer is used to collect calles to RequestCompaction() and + eventually call Run(). + */ + Timer maCompactionTimer; + bool mbIsCompactionRunning; + DECL_LINK(CompactionCallback, Timer*); +}; + + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx new file mode 100644 index 000000000000..942a3e762acb --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx @@ -0,0 +1,181 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "SlsCacheConfiguration.hxx" +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> + +#include <comphelper/processfactory.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#ifndef _COM_SUN_STAR_CONTAINER_PROPERTYVALUE_HPP_ +#include <com/sun/star/beans/PropertyValue.hpp> +#endif + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd { namespace slidesorter { namespace cache { + +::boost::shared_ptr<CacheConfiguration> CacheConfiguration::mpInstance; +::boost::weak_ptr<CacheConfiguration> CacheConfiguration::mpWeakInstance; +Timer CacheConfiguration::maReleaseTimer; + + + +::boost::shared_ptr<CacheConfiguration> CacheConfiguration::Instance (void) +{ + ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); + if (mpInstance.get() == NULL) + { + // Maybe somebody else kept a previously created instance alive. + if ( ! mpWeakInstance.expired()) + mpInstance = ::boost::shared_ptr<CacheConfiguration>(mpWeakInstance); + if (mpInstance.get() == NULL) + { + // We have to create a new instance. + mpInstance.reset(new CacheConfiguration()); + mpWeakInstance = mpInstance; + // Prepare to release this instance in the near future. + maReleaseTimer.SetTimeoutHdl( + LINK(mpInstance.get(),CacheConfiguration,TimerCallback)); + maReleaseTimer.SetTimeout(5000 /* 5s */); + maReleaseTimer.Start(); + } + } + return mpInstance; +} + + + + +CacheConfiguration::CacheConfiguration (void) +{ + // Get the cache size from configuration. + const ::rtl::OUString sConfigurationProviderServiceName( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.configuration.ConfigurationProvider")); + const ::rtl::OUString sPathToImpressConfigurationRoot( + RTL_CONSTASCII_USTRINGPARAM("/org.openoffice.Office.Impress/")); + const ::rtl::OUString sPathToNode( + RTL_CONSTASCII_USTRINGPARAM( + "MultiPaneGUI/SlideSorter/PreviewCache")); + + try + { + do + { + // Obtain access to the configuration. + Reference<lang::XMultiServiceFactory> xProvider ( + ::comphelper::getProcessServiceFactory()->createInstance( + sConfigurationProviderServiceName), + UNO_QUERY); + if ( ! xProvider.is()) + break; + + // Obtain access to Impress configuration. + Sequence<Any> aCreationArguments(3); + aCreationArguments[0] = makeAny(beans::PropertyValue( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("nodepath")), + 0, + makeAny(sPathToImpressConfigurationRoot), + beans::PropertyState_DIRECT_VALUE)); + aCreationArguments[1] = makeAny(beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("depth")), + 0, + makeAny((sal_Int32)-1), + beans::PropertyState_DIRECT_VALUE)); + aCreationArguments[2] = makeAny(beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("lazywrite")), + 0, + makeAny(true), + beans::PropertyState_DIRECT_VALUE)); + ::rtl::OUString sAccessService (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.configuration.ConfigurationAccess"))); + Reference<XInterface> xRoot (xProvider->createInstanceWithArguments( + sAccessService, aCreationArguments)); + if ( ! xRoot.is()) + break; + Reference<container::XHierarchicalNameAccess> xHierarchy (xRoot, UNO_QUERY); + if ( ! xHierarchy.is()) + break; + + // Get the node for the slide sorter preview cache. + mxCacheNode = Reference<container::XNameAccess>( + xHierarchy->getByHierarchicalName(sPathToNode), + UNO_QUERY); + } + while (false); + } + catch (RuntimeException aException) + { + (void)aException; + } + catch (Exception aException) + { + (void)aException; + } +} + + + + +Any CacheConfiguration::GetValue (const ::rtl::OUString& rName) +{ + Any aResult; + + if (mxCacheNode != NULL) + { + try + { + aResult = mxCacheNode->getByName(rName); + } + catch (Exception aException) + { + (void)aException; + } + } + + return aResult; +} + + + + +IMPL_LINK(CacheConfiguration,TimerCallback, Timer*,EMPTYARG) +{ + // Release out reference to the instance. + mpInstance.reset(); + return 0; +} + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx new file mode 100644 index 000000000000..034480298006 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_CACHE_CONFIGURATION_HXX +#define SD_SLIDESORTER_CACHE_CONFIGURATION_HXX + +#include <com/sun/star/uno/Any.hxx> +#include <vcl/timer.hxx> +#include <com/sun/star/container/XNameAccess.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> + +namespace sd { namespace slidesorter { namespace cache { + +/** A very simple and easy-to-use access to configuration entries regarding + the slide sorter cache. +*/ +class CacheConfiguration +{ +public: + /** Return an instance to this class. The reference is released after 5 + seconds. Subsequent calls to this function will create a new + instance. + */ + static ::boost::shared_ptr<CacheConfiguration> Instance (void); + + /** Look up the specified value in + MultiPaneGUI/SlideSorter/PreviewCache. When the specified value + does not exist then an empty Any is returned. + */ + ::com::sun::star::uno::Any GetValue (const ::rtl::OUString& rName); + +private: + static ::boost::shared_ptr<CacheConfiguration> mpInstance; + /** When a caller holds a reference after we have released ours we use + this weak pointer to avoid creating a new instance. + */ + static ::boost::weak_ptr<CacheConfiguration> mpWeakInstance; + static Timer maReleaseTimer; + ::com::sun::star::uno::Reference< + ::com::sun::star::container::XNameAccess> mxCacheNode; + + CacheConfiguration (void); + + DECL_LINK(TimerCallback, Timer*); +}; + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx new file mode 100755 index 000000000000..780a429df29e --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx @@ -0,0 +1,310 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsGenericPageCache.hxx" + +#include "SlsQueueProcessor.hxx" +#include "SlsRequestPriorityClass.hxx" +#include "SlsRequestFactory.hxx" +#include "cache/SlsPageCacheManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "controller/SlideSorterController.hxx" + +namespace sd { namespace slidesorter { namespace cache { + +GenericPageCache::GenericPageCache ( + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext) + : mpBitmapCache(), + maRequestQueue(rpCacheContext), + mpQueueProcessor(), + mpCacheContext(rpCacheContext), + maPreviewSize(rPreviewSize) +{ +} + + + + +GenericPageCache::~GenericPageCache (void) +{ + OSL_TRACE("terminating queue processor %p", mpQueueProcessor.get()); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Stop(); + maRequestQueue.Clear(); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Terminate(); + mpQueueProcessor.reset(); + OSL_TRACE("queue processor stopped and terminated"); + + if (mpBitmapCache.get() != NULL) + PageCacheManager::Instance()->ReleaseCache(mpBitmapCache); + mpBitmapCache.reset(); +} + + + + +void GenericPageCache::ProvideCacheAndProcessor (void) +{ + if (mpBitmapCache.get() == NULL) + mpBitmapCache = PageCacheManager::Instance()->GetCache( + mpCacheContext->GetModel(), + maPreviewSize); + + if (mpQueueProcessor.get() == NULL) + mpQueueProcessor.reset(new QueueProcessor( + maRequestQueue, + mpBitmapCache, + maPreviewSize, + mpCacheContext)); +} + + + + +void GenericPageCache::ChangePreviewSize (const Size& rPreviewSize) +{ + if (rPreviewSize != maPreviewSize) + { + if (mpBitmapCache.get() != NULL) + { + mpBitmapCache = PageCacheManager::Instance()->ChangeSize( + mpBitmapCache, maPreviewSize, rPreviewSize); + if (mpQueueProcessor.get() != NULL) + { + mpQueueProcessor->SetPreviewSize(rPreviewSize); + mpQueueProcessor->SetBitmapCache(mpBitmapCache); + } + } + maPreviewSize = rPreviewSize; + } +} + + + + +BitmapEx GenericPageCache::GetPreviewBitmap ( + CacheKey aKey, + const Size& rSize) +{ + OSL_ASSERT(aKey != NULL); + + BitmapEx aPreview; + bool bMayBeUpToDate = true; + ProvideCacheAndProcessor(); + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + if (mpBitmapCache->HasBitmap(pPage)) + { + ::boost::shared_ptr<BitmapEx> pPreview(mpBitmapCache->GetBitmap(pPage)); + OSL_ASSERT(pPreview.get() != NULL); + aPreview = *pPreview; + Size aBitmapSize (aPreview.GetSizePixel()); + if (aBitmapSize != rSize) + { + // The bitmap has the wrong size. + DBG_ASSERT (rSize.Width() < 1000, + "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. " + "This may indicate an error."); + + // Scale the bitmap to the desired size when that is possible, + // i.e. the bitmap is not empty. + if (aBitmapSize.Width()>0 && aBitmapSize.Height()>0) + aPreview.Scale (rSize, BMP_SCALE_FAST); + } + bMayBeUpToDate = true; + } + else + bMayBeUpToDate = false; + + // Request the creation of a correctly sized preview bitmap. We do this + // even when the size of the bitmap in the cache is correct because its + // content may be not up-to-date anymore. + RequestPreviewBitmap(aKey, rSize, bMayBeUpToDate); + + return aPreview; +} + + + + +void GenericPageCache::RequestPreviewBitmap ( + CacheKey aKey, + const Size& rSize, + bool bMayBeUpToDate) +{ + OSL_ASSERT(aKey != NULL); + + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + + ProvideCacheAndProcessor(); + + // Determine if the available bitmap is up to date. + bool bIsUpToDate = false; + if (bMayBeUpToDate) + bIsUpToDate = mpBitmapCache->BitmapIsUpToDate (pPage); + if (bIsUpToDate) + { + ::boost::shared_ptr<BitmapEx> pPreview (mpBitmapCache->GetBitmap(pPage)); + if (pPreview.get()==NULL || pPreview->GetSizePixel()!=rSize) + bIsUpToDate = false; + } + + if ( ! bIsUpToDate) + { + // No, the bitmap is not up-to-date. Request a new one. + RequestPriorityClass ePriorityClass (NOT_VISIBLE); + if (mpCacheContext->IsVisible(aKey)) + { + if (mpBitmapCache->HasBitmap(pPage)) + ePriorityClass = VISIBLE_OUTDATED_PREVIEW; + else + ePriorityClass = VISIBLE_NO_PREVIEW; + } + maRequestQueue.AddRequest(aKey, ePriorityClass); + mpQueueProcessor->Start(ePriorityClass); + } +} + + + + +void GenericPageCache::ReleasePreviewBitmap (CacheKey aKey) +{ + if (mpBitmapCache.get() != NULL) + { + // Suspend the queue processing temporarily to avoid the reinsertion + // of the request that is to be deleted. + mpQueueProcessor->Stop(); + + maRequestQueue.RemoveRequest(aKey); + mpQueueProcessor->RemoveRequest(aKey); + + // Resume the queue processing. + if ( ! maRequestQueue.IsEmpty()) + { + try + { + mpQueueProcessor->Start(maRequestQueue.GetFrontPriorityClass()); + } + catch (::com::sun::star::uno::RuntimeException) + { + } + } + } + + // We do not relase the preview bitmap that is associated with the page + // of the given request data because this method is called when the + // request data, typically a view-object-contact object, is destroyed. + // The page object usually lives longer than that and thus the preview + // bitmap may be used later on. +} + + + + +void GenericPageCache::InvalidateCache (bool bUpdateCache) +{ + if (mpBitmapCache.get() != NULL) + { + // When the cache is being invalidated then it makes no sense to + // continue creating preview bitmaps. However, this may be + // re-started below. + mpQueueProcessor->Stop(); + maRequestQueue.Clear(); + + // Mark the previews in the cache as not being up-to-date anymore. + // Depending on the given bUpdateCache flag we start to create new + // preview bitmaps. + mpBitmapCache->InvalidateCache(); + if (bUpdateCache) + RequestFactory()(maRequestQueue, mpCacheContext); + } +} + + + + +void GenericPageCache::SetPreciousFlag (CacheKey aKey, bool bIsPrecious) +{ + ProvideCacheAndProcessor(); + + // Change the request priority class according to the new precious flag. + if (bIsPrecious) + { + if (mpBitmapCache->HasBitmap(mpCacheContext->GetPage(aKey))) + maRequestQueue.ChangeClass(aKey,VISIBLE_OUTDATED_PREVIEW); + else + maRequestQueue.ChangeClass(aKey,VISIBLE_NO_PREVIEW); + } + else + { + if (mpBitmapCache->IsFull()) + { + // When the bitmap cache is full then requests for slides that + // are not visible are removed. + maRequestQueue.RemoveRequest(aKey); + } + else + maRequestQueue.ChangeClass(aKey,NOT_VISIBLE); + } + + mpBitmapCache->SetPrecious(mpCacheContext->GetPage(aKey), bIsPrecious); +} + + + + +void GenericPageCache::Pause (void) +{ + ProvideCacheAndProcessor(); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Pause(); +} + + + + +void GenericPageCache::Resume (void) +{ + ProvideCacheAndProcessor(); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Resume(); +} + + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx new file mode 100755 index 000000000000..89fc657004e8 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx @@ -0,0 +1,146 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_GENERIC_PAGE_CACHE_HXX +#define SD_SLIDESORTER_GENERIC_PAGE_CACHE_HXX + +#include "SlideSorter.hxx" +#include "SlsRequestQueue.hxx" +#include "SlsQueueProcessor.hxx" +#include <boost/function.hpp> +#include <boost/scoped_ptr.hpp> + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapCache; +class QueueProcessor; + +/** This basically is the implementation class for the PageCache class. +*/ +class GenericPageCache +{ +public: + /** The page chache is created with references both to the SlideSorter. + This allows access to both view and model and the cache can so fill + itself with requests for all or just the visible pages. + */ + GenericPageCache ( + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext); + + ~GenericPageCache (void); + + /** Change the size of the preview bitmaps. This may be caused by a + resize of the slide sorter window or a change of the number of + columns. + */ + void ChangePreviewSize (const Size& rPreviewSize); + + /** Request a preview bitmap for the specified page object in the + specified size. The returned bitmap may be preview of the preview, + i.e. either a scaled (up or down) version of a previous preview (of + the wrong size) or an empty bitmap. In this case a request for the + generation of a new preview is created and inserted into the request + queue. When the preview is available the page shape will be told to + paint itself again. When it then calls this method again if + receives the correctly sized preview bitmap. + @param rRequestData + This data is used to determine the preview. + @param rSize + The size of the requested preview bitmap. + @return + Returns a bitmap that is either empty, contains a scaled (up or + down) version or is the requested bitmap. + */ + BitmapEx GetPreviewBitmap ( + CacheKey aKey, + const Size& rSize); + + /** When the requested preview bitmap does not yet exist or is not + up-to-date then the rendering of one is scheduled. Otherwise this + method does nothing. + @param rRequestData + This data is used to determine the preview. + @param rSize + The size of the requested preview bitmap in pixel coordinates. + @param bMayBeUpToDate + This flag helps the method to determine whether an existing + preview that matches the request is up to date. If the caller + know that it is not then by passing <FALSE/> he tells us that we + do not have to check the up-to-date flag a second time. If + unsure pass <TRUE/>. + */ + void RequestPreviewBitmap ( + CacheKey aKey, + const Size& rSize, + bool bMayBeUpToDate = true); + + /** Call this method when a view-object-contact object is being deleted + and does not need (a) its current bitmap in the cache and (b) a + requested a new bitmap. + */ + void ReleasePreviewBitmap (CacheKey aKey); + + /** Call this method when all preview bitmaps have to be generated anew. + This is the case when the size of the page objects on the screen has + changed or when the model has changed. + */ + void InvalidateCache (bool bUpdateCache); + + /** With the precious flag you can control whether a bitmap can be + removed from the cache or reduced in size to make room for other + bitmaps or is so precious that it will not be touched. A typical + use is to set the precious flag for the visible pages. + */ + void SetPreciousFlag (CacheKey aKey, bool bIsPrecious); + + void Pause (void); + void Resume (void); + +private: + ::boost::shared_ptr<BitmapCache> mpBitmapCache; + + RequestQueue maRequestQueue; + + ::boost::scoped_ptr<QueueProcessor> mpQueueProcessor; + + SharedCacheContext mpCacheContext; + + /** The current size of preview bitmaps. + */ + Size maPreviewSize; + + /** Both bitmap cache and queue processor are created on demand by this + method. + */ + void ProvideCacheAndProcessor (void); +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx new file mode 100755 index 000000000000..714e1f008329 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsGenericPageCache.hxx" +#include "SlsRequestFactory.hxx" +#include "cache/SlsPageCache.hxx" +#include "model/SlideSorterModel.hxx" +#include <boost/bind.hpp> +#include <boost/bind/protect.hpp> + +using namespace ::com::sun::star; + + +namespace sd { namespace slidesorter { namespace cache { + + +//===== PageCache ============================================================= + +PageCache::PageCache ( + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext) + : mpImplementation( + new GenericPageCache( + rPreviewSize, + rpCacheContext)) +{ +} + + + + +PageCache::~PageCache (void) +{ +} + + + + +void PageCache::ChangeSize(const Size& rPreviewSize) +{ + mpImplementation->ChangePreviewSize(rPreviewSize); +} + + + + +BitmapEx PageCache::GetPreviewBitmap ( + CacheKey aKey, + const Size& rSize) +{ + return mpImplementation->GetPreviewBitmap(aKey, rSize); +} + + + + +void PageCache::ReleasePreviewBitmap ( + CacheKey aKey) +{ + mpImplementation->ReleasePreviewBitmap(aKey); +} + + + + +void PageCache::InvalidateCache (bool bUpdateCache) +{ + mpImplementation->InvalidateCache(bUpdateCache); +} + + + + +void PageCache::SetPreciousFlag ( + CacheKey aKey, + bool bIsPrecious) +{ + mpImplementation->SetPreciousFlag(aKey, bIsPrecious); +} + + + + +void PageCache::Pause (void) +{ + mpImplementation->Pause(); +} + + + + +void PageCache::Resume (void) +{ + mpImplementation->Resume(); +} + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx new file mode 100644 index 000000000000..3c8a15892e7c --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx @@ -0,0 +1,446 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "cache/SlsPageCacheManager.hxx" + +#include "SlsBitmapCache.hxx" +#include "view/SlideSorterView.hxx" +#include "model/SlideSorterModel.hxx" + +#include <deque> +#include <map> +#include <boost/weak_ptr.hpp> + +namespace { + +/** Collection of data that is stored for all active preview caches. +*/ +class CacheDescriptor +{ +public: + ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument; + Size maPreviewSize; + + CacheDescriptor( + ::sd::slidesorter::cache::PageCacheManager::DocumentKey pDocument, + const Size& rPreviewSize) + :mpDocument(pDocument),maPreviewSize(rPreviewSize) + {} + /// Test for equality with respect to all members. + class Equal {public: bool operator() ( + const CacheDescriptor& rDescriptor1, const CacheDescriptor& rDescriptor2) const { + return rDescriptor1.mpDocument==rDescriptor2.mpDocument + && rDescriptor1.maPreviewSize==rDescriptor2.maPreviewSize; + } }; + /// Hash function that takes all members into account. + class Hash {public: size_t operator() (const CacheDescriptor& rDescriptor) const { + return (size_t)rDescriptor.mpDocument.get() + rDescriptor.maPreviewSize.Width(); + } }; +}; + + + + +/** Collection of data that is stored for the inactive, recently used + caches. +*/ +class RecentlyUsedCacheDescriptor +{ +public: + ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument; + Size maPreviewSize; + ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache> mpCache; + + RecentlyUsedCacheDescriptor( + ::sd::slidesorter::cache::PageCacheManager::DocumentKey pDocument, + const Size& rPreviewSize, + const ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache>& rpCache) + :mpDocument(pDocument),maPreviewSize(rPreviewSize),mpCache(rpCache) + {} +}; + + + + +/** The list of recently used caches is organized as queue. When elements + are added the list is shortened to the maximally allowed number of + elements by removing the least recently used elements. +*/ +typedef ::std::deque<RecentlyUsedCacheDescriptor> RecentlyUsedQueue; + + + + +/** Compare the caches by preview size. Those that match the given size + come first, then, regardless of the given size, the largest ones before + the smaller ones. +*/ +class BestFittingCacheComparer +{ +public: + BestFittingCacheComparer (const Size& rPreferredSize) + : maPreferredSize(rPreferredSize) + {} + bool operator()(const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement1, + const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement2) + { + if (rElement1.first == maPreferredSize) + return true; + else if (rElement2.first == maPreferredSize) + return false; + else + return (rElement1.first.Width()*rElement1.first.Height() + > rElement2.first.Width()*rElement2.first.Height()); + } + +private: + Size maPreferredSize; +}; + +} // end of anonymous namespace + + +namespace sd { namespace slidesorter { namespace cache { + +/** Container for the active caches. +*/ +class PageCacheManager::PageCacheContainer + : public ::std::hash_map<CacheDescriptor, + ::boost::shared_ptr<PageCacheManager::Cache>, + CacheDescriptor::Hash, + CacheDescriptor::Equal> +{ +public: + PageCacheContainer (void) {} + + /** Compare entries in the cache container with respect to the cache + address only. + */ + class CompareWithCache { public: + CompareWithCache(const ::boost::shared_ptr<PageCacheManager::Cache>& rpCache) + : mpCache(rpCache) {} + bool operator () (const PageCacheContainer::value_type& rValue) + { return rValue.second == mpCache; } + private: + ::boost::shared_ptr<PageCacheManager::Cache> mpCache; + }; +}; + + +/** The recently used caches are stored in one queue for each document. +*/ +class PageCacheManager::RecentlyUsedPageCaches + : public ::std::map<DocumentKey,RecentlyUsedQueue> +{ +public: + RecentlyUsedPageCaches (void) {}; +}; + + + + +class PageCacheManager::Deleter +{ +public: + void operator() (PageCacheManager* pObject) { delete pObject; } +}; + + + +//===== PageCacheManager ==================================================== + +::boost::weak_ptr<PageCacheManager> PageCacheManager::mpInstance; + +::boost::shared_ptr<PageCacheManager> PageCacheManager::Instance (void) +{ + ::boost::shared_ptr<PageCacheManager> pInstance; + + ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); + + pInstance = mpInstance.lock(); + if (pInstance.get() == NULL) + { + pInstance = ::boost::shared_ptr<PageCacheManager>( + new PageCacheManager(), + PageCacheManager::Deleter()); + mpInstance = pInstance; + } + + return pInstance; +} + + + + +PageCacheManager::PageCacheManager (void) + : mpPageCaches(new PageCacheContainer()), + mpRecentlyUsedPageCaches(new RecentlyUsedPageCaches()), + mnMaximalRecentlyCacheCount(2) +{ +} + + + + +PageCacheManager::~PageCacheManager (void) +{ +} + + + + +::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetCache ( + DocumentKey pDocument, + const Size& rPreviewSize) +{ + ::boost::shared_ptr<Cache> pResult; + + // Look for the cache in the list of active caches. + CacheDescriptor aKey (pDocument, rPreviewSize); + PageCacheContainer::iterator iCache (mpPageCaches->find(aKey)); + if (iCache != mpPageCaches->end()) + pResult = iCache->second; + + // Look for the cache in the list of recently used caches. + if (pResult.get() == NULL) + pResult = GetRecentlyUsedCache(pDocument, rPreviewSize); + + // Create the cache when no suitable one does exist. + if (pResult.get() == NULL) + pResult.reset(new Cache()); + + // The cache may be newly created and thus empty or is old and may + // contain previews that are not up-to-date. Recycle previews from + // other caches to fill in the holes. + Recycle(pResult, pDocument,rPreviewSize); + + // Put the new (or old) cache into the container. + if (pResult.get() != NULL) + mpPageCaches->insert(PageCacheContainer::value_type(aKey, pResult)); + + return pResult; +} + + + + +void PageCacheManager::Recycle ( + const ::boost::shared_ptr<Cache>& rpCache, + DocumentKey pDocument, + const Size& rPreviewSize) +{ + BestFittingPageCaches aCaches; + + // Add bitmap caches from active caches. + PageCacheContainer::iterator iActiveCache; + for (iActiveCache=mpPageCaches->begin(); iActiveCache!=mpPageCaches->end(); ++iActiveCache) + { + if (iActiveCache->first.mpDocument == pDocument) + aCaches.push_back(BestFittingPageCaches::value_type( + iActiveCache->first.maPreviewSize, iActiveCache->second)); + } + + // Add bitmap caches from recently used caches. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + RecentlyUsedQueue::const_iterator iRecentCache; + for (iRecentCache=iQueue->second.begin();iRecentCache!=iQueue->second.end();++iRecentCache) + aCaches.push_back(BestFittingPageCaches::value_type( + iRecentCache->maPreviewSize, iRecentCache->mpCache)); + } + + ::std::sort(aCaches.begin(), aCaches.end(), BestFittingCacheComparer(rPreviewSize)); + + BestFittingPageCaches::const_iterator iBestCache; + for (iBestCache=aCaches.begin(); iBestCache!=aCaches.end(); ++iBestCache) + { + rpCache->Recycle(*iBestCache->second); + } +} + + + + +void PageCacheManager::ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache) +{ + PageCacheContainer::iterator iCache (::std::find_if( + mpPageCaches->begin(), + mpPageCaches->end(), + PageCacheContainer::CompareWithCache(rpCache))); + + if (iCache != mpPageCaches->end()) + { + OSL_ASSERT(iCache->second == rpCache); + + PutRecentlyUsedCache(iCache->first.mpDocument,iCache->first.maPreviewSize,rpCache); + + mpPageCaches->erase(iCache); + } +} + + + + +::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::ChangeSize ( + const ::boost::shared_ptr<Cache>& rpCache, + const Size& rOldPreviewSize, + const Size& rNewPreviewSize) +{ + (void)rOldPreviewSize; + + ::boost::shared_ptr<Cache> pResult; + + if (rpCache.get() != NULL) + { + // Look up the given cache in the list of active caches. + PageCacheContainer::iterator iCacheToChange (::std::find_if( + mpPageCaches->begin(), + mpPageCaches->end(), + PageCacheContainer::CompareWithCache(rpCache))); + OSL_ASSERT(iCacheToChange != mpPageCaches->end()); + if (iCacheToChange != mpPageCaches->end()) + { + OSL_ASSERT(iCacheToChange->second == rpCache); + + // Now, we can change the preview size of the existing one by + // removing the cache from the list and re-insert it with the + // updated size. + const ::sd::slidesorter::cache::PageCacheManager::DocumentKey aKey ( + iCacheToChange->first.mpDocument); + mpPageCaches->erase(iCacheToChange); + mpPageCaches->insert(PageCacheContainer::value_type( + CacheDescriptor(aKey,rNewPreviewSize), + rpCache)); + + pResult = rpCache; + } + } + + return pResult; +} + + + + +void PageCacheManager::InvalidatePreviewBitmap ( + DocumentKey pDocument, + const SdrPage* pKey) +{ + if (pDocument!=NULL) + { + // Iterate over all caches that are currently in use and invalidate + // the previews in those that belong to the document. + PageCacheContainer::iterator iCache; + for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache) + if (iCache->first.mpDocument == pDocument) + iCache->second->InvalidateBitmap(pKey); + + // Invalidate the previews in the recently used caches belonging to + // the given document. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + RecentlyUsedQueue::const_iterator iCache2; + for (iCache2=iQueue->second.begin(); iCache2!=iQueue->second.end(); ++iCache2) + iCache2->mpCache->InvalidateBitmap(pKey); + } + } +} + + + + +void PageCacheManager::InvalidateAllCaches (void) +{ + // Iterate over all caches that are currently in use and invalidate + // them. + PageCacheContainer::iterator iCache; + for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache) + iCache->second->InvalidateCache(); + + // Remove all recently used caches, there is not much sense in storing + // invalidated and unused caches. + mpRecentlyUsedPageCaches->clear(); +} + + + + +::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetRecentlyUsedCache ( + DocumentKey pDocument, + const Size& rPreviewSize) +{ + ::boost::shared_ptr<Cache> pCache; + + // Look for the cache in the list of recently used caches. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + RecentlyUsedQueue::iterator iCache; + for (iCache=iQueue->second.begin(); iCache!= iQueue->second.end(); ++iCache) + if (iCache->maPreviewSize == rPreviewSize) + { + pCache = iCache->mpCache; + iQueue->second.erase(iCache); + break; + } + } + + return pCache; +} + + + + +void PageCacheManager::PutRecentlyUsedCache( + DocumentKey pDocument, + const Size& rPreviewSize, + const ::boost::shared_ptr<Cache>& rpCache) +{ + // Look up the list of recently used caches for the given document. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue == mpRecentlyUsedPageCaches->end()) + iQueue = mpRecentlyUsedPageCaches->insert( + RecentlyUsedPageCaches::value_type(pDocument, RecentlyUsedQueue()) + ).first; + + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + iQueue->second.push_front(RecentlyUsedCacheDescriptor(pDocument,rPreviewSize,rpCache)); + // Shorten the list of recently used caches to the allowed maximal length. + while (iQueue->second.size() > mnMaximalRecentlyCacheCount) + iQueue->second.pop_back(); + } +} + + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx new file mode 100755 index 000000000000..bec9c7fa369d --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx @@ -0,0 +1,254 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsQueueProcessor.hxx" +#include "SlsCacheConfiguration.hxx" +#include "SlsRequestQueue.hxx" + +namespace sd { namespace slidesorter { namespace cache { + + +//===== QueueProcessor ====================================================== + +QueueProcessor::QueueProcessor ( + RequestQueue& rQueue, + const ::boost::shared_ptr<BitmapCache>& rpCache, + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext) + : maMutex(), + maTimer(), + mnTimeBetweenHighPriorityRequests (10/*ms*/), + mnTimeBetweenLowPriorityRequests (100/*ms*/), + mnTimeBetweenRequestsWhenNotIdle (1000/*ms*/), + maPreviewSize(rPreviewSize), + mpCacheContext(rpCacheContext), + mrQueue(rQueue), + mpCache(rpCache), + maBitmapFactory(), + mbIsPaused(false) +{ + // Look into the configuration if there for overriding values. + ::com::sun::star::uno::Any aTimeBetweenReqeusts; + aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenHighPriorityRequests"))); + if (aTimeBetweenReqeusts.has<sal_Int32>()) + aTimeBetweenReqeusts >>= mnTimeBetweenHighPriorityRequests; + + aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenLowPriorityRequests"))); + if (aTimeBetweenReqeusts.has<sal_Int32>()) + aTimeBetweenReqeusts >>= mnTimeBetweenLowPriorityRequests; + + aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenRequestsDuringShow"))); + if (aTimeBetweenReqeusts.has<sal_Int32>()) + aTimeBetweenReqeusts >>= mnTimeBetweenRequestsWhenNotIdle; + + maTimer.SetTimeoutHdl (LINK(this,QueueProcessor,ProcessRequestHdl)); + maTimer.SetTimeout (mnTimeBetweenHighPriorityRequests); +} + + + + + +QueueProcessor::~QueueProcessor (void) +{ +} + + + + +void QueueProcessor::Start (int nPriorityClass) +{ + if (mbIsPaused) + return; + if ( ! maTimer.IsActive()) + { + if (nPriorityClass == 0) + maTimer.SetTimeout (mnTimeBetweenHighPriorityRequests); + else + maTimer.SetTimeout (mnTimeBetweenLowPriorityRequests); + maTimer.Start(); + } +} + + + + +void QueueProcessor::Stop (void) +{ + if (maTimer.IsActive()) + maTimer.Stop(); +} + + + + +void QueueProcessor::Pause (void) +{ + mbIsPaused = true; +} + + + + +void QueueProcessor::Resume (void) +{ + mbIsPaused = false; + if ( ! mrQueue.IsEmpty()) + Start(mrQueue.GetFrontPriorityClass()); +} + + + + +void QueueProcessor::Terminate (void) +{ +} + + + + +void QueueProcessor::SetPreviewSize (const Size& rPreviewSize) +{ + maPreviewSize = rPreviewSize; +} + + + + +IMPL_LINK(QueueProcessor, ProcessRequestHdl, Timer*, EMPTYARG) +{ + ProcessRequests(); + return 1; +} + + + + +void QueueProcessor::ProcessRequests (void) +{ + OSL_ASSERT(mpCacheContext.get()!=NULL); + + // Never process more than one request at a time in order to prevent the + // lock up of the edit view. + if ( ! mrQueue.IsEmpty() + && ! mbIsPaused + && mpCacheContext->IsIdle()) + { + CacheKey aKey = NULL; + RequestPriorityClass ePriorityClass (NOT_VISIBLE); + { + ::osl::MutexGuard aGuard (mrQueue.GetMutex()); + + if ( ! mrQueue.IsEmpty()) + { + // Get the request with the highest priority from the queue. + ePriorityClass = mrQueue.GetFrontPriorityClass(); + aKey = mrQueue.GetFront(); + mrQueue.PopFront(); + } + } + + if (aKey != NULL) + ProcessOneRequest(aKey, ePriorityClass); + } + + // Schedule the processing of the next element(s). + { + ::osl::MutexGuard aGuard (mrQueue.GetMutex()); + if ( ! mrQueue.IsEmpty()) + Start(mrQueue.GetFrontPriorityClass()); + } +} + + + + +void QueueProcessor::ProcessOneRequest ( + CacheKey aKey, + const RequestPriorityClass ePriorityClass) +{ + try + { + ::osl::MutexGuard aGuard (maMutex); + + // Create a new preview bitmap and store it in the cache. + if (mpCache.get() != NULL + && mpCacheContext.get() != NULL) + { + const SdPage* pSdPage = dynamic_cast<const SdPage*>(mpCacheContext->GetPage(aKey)); + if (pSdPage != NULL) + { + const ::boost::shared_ptr<BitmapEx> pPreview ( + maBitmapFactory.CreateBitmap(*pSdPage, maPreviewSize)); + mpCache->SetBitmap ( + pSdPage, + pPreview, + ePriorityClass!=NOT_VISIBLE); + + // Initiate a repaint of the new preview. + mpCacheContext->NotifyPreviewCreation(aKey, pPreview); + } + } + } + catch (::com::sun::star::uno::RuntimeException aException) + { + (void) aException; + OSL_ASSERT("RuntimeException caught in QueueProcessor"); + } + catch (::com::sun::star::uno::Exception aException) + { + (void) aException; + OSL_ASSERT("Exception caught in QueueProcessor"); + } +} + + + + +void QueueProcessor::RemoveRequest (CacheKey aKey) +{ + (void)aKey; + // See the method declaration above for an explanation why this makes sense. + ::osl::MutexGuard aGuard (maMutex); +} + + + + +void QueueProcessor::SetBitmapCache ( + const ::boost::shared_ptr<BitmapCache>& rpCache) +{ + mpCache = rpCache; +} + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx new file mode 100644 index 000000000000..e42ad092d0e2 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_QUEUE_PROCESSOR_HXX +#define SD_SLIDESORTER_QUEUE_PROCESSOR_HXX + +#include "cache/SlsPageCache.hxx" +#include "SlsRequestPriorityClass.hxx" +#include "SlsBitmapFactory.hxx" +#include "view/SlsPageObject.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "tools/IdleDetection.hxx" +#include "SlsBitmapCache.hxx" +#include "sdpage.hxx" +#include "Window.hxx" + +#include <svx/svdpagv.hxx> +#include <vcl/svapp.hxx> +#include <vcl/timer.hxx> +#include <boost/function.hpp> + + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + + + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapCache; +class RequestQueue; + + + +/** This queue processor is timer based, i.e. when an entry is added to the + queue and the processor is started with Start() in the base class a + timer is started that eventually calls ProcessRequest(). This is + repeated until the queue is empty or Stop() is called. +*/ +class QueueProcessor +{ +public: + typedef ::boost::function<bool()> IdleDetectionCallback; + QueueProcessor ( + RequestQueue& rQueue, + const ::boost::shared_ptr<BitmapCache>& rpCache, + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext); + virtual ~QueueProcessor(); + + /** Start the processor. This implementation is timer based and waits + an defined amount of time that depends on the given argument before + the next entry in the queue is processed. + @param nPriorityClass + A priority class of 0 tells the processor that a high priority + request is waiting in the queue. The time to wait is thus + shorter then that for a low priority request (denoted by a value + of 1.) When the timer is already running it is not modified. + */ + void Start (int nPriorityClass = 0); + void Stop (void); + void Pause (void); + void Resume (void); + + void Terminate (void); + + void SetPreviewSize (const Size& rSize); + + /** As we can not really terminate the rendering of a preview bitmap for + a request in midair this method acts more like a semaphor. It + returns only when it is save for the caller to delete the request. + For this to work it is important to remove the request from the + queue before calling this method. + */ + void RemoveRequest (CacheKey aKey); + + /** Use this method when the page cache is (maybe) using a different + BitmapCache. This is usually necessary after calling + PageCacheManager::ChangeSize(). + */ + void SetBitmapCache (const ::boost::shared_ptr<BitmapCache>& rpCache); + +private: + /** This mutex is used to guard the queue processor. Be carefull not to + mix its use with that of the solar mutex. + */ + ::osl::Mutex maMutex; + + Timer maTimer; + DECL_LINK(ProcessRequestHdl, Timer*); + sal_uInt32 mnTimeBetweenHighPriorityRequests; + sal_uInt32 mnTimeBetweenLowPriorityRequests; + sal_uInt32 mnTimeBetweenRequestsWhenNotIdle; + Size maPreviewSize; + SharedCacheContext mpCacheContext; + RequestQueue& mrQueue; + ::boost::shared_ptr<BitmapCache> mpCache; + BitmapFactory maBitmapFactory; + bool mbIsPaused; + + void ProcessRequests (void); + void ProcessOneRequest ( + CacheKey aKey, + const RequestPriorityClass ePriorityClass); +}; + + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx new file mode 100644 index 000000000000..08ca63284ea6 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx @@ -0,0 +1,365 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_QUEUE_PROCESSOR_THREAD_HXX +#define SD_SLIDESORTER_QUEUE_PROCESSOR_THREAD_HXX + +#include "view/SlsPageObjectViewObjectContact.hxx" +#include <vcl/svapp.hxx> +#include <osl/thread.hxx> + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + + +namespace sd { namespace slidesorter { namespace cache { + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +class QueueProcessorThread + : public ::osl::Thread +{ +public: + QueueProcessorThread ( + view::SlideSorterView& rView, + Queue& rQueue, + BitmapCache& rCache); + ~QueueProcessorThread (void); + + /** Start the execution of a suspended thread. A thread is suspended + after Stop() is called or when the queue on which it operates is + empty. Calling Start() on a running thread is OK. + */ + void Start (void); + + /** Stop the thread by suspending it. To re-start its execution call + Start(). + */ + void Stop (void); + + /** As we can not really terminate the rendering of a preview bitmap for + a request in midair this method acts more like a semaphor. It + returns only when it is save for the caller to delete the request. + For this to work it is important to remove the request from the + queue before calling this method. + */ + void RemoveRequest (RequestData& rRequest); + + /** Terminate the execution of the thread. When the thread is detached + it deletes itself. Otherwise the caller of this method may call + delete after this method returnes. + */ + void SAL_CALL Terminate (void); + +protected: + /** This virutal method is called (among others?) from the + inherited create method and acts as the main function of this + thread. + */ + virtual void SAL_CALL run (void); + + /** Called after the thread is terminated via the terminate + method. Used to kill the thread by calling delete on this. + */ + virtual void SAL_CALL onTerminated (void); + +private: + /** Flag that indicates wether the onTerminated method has been already + called. If so then a subsequent call to detach deletes the thread. + */ + volatile bool mbIsTerminated; + + volatile bool mbCanBeJoined; + + /** This mutex is used to guard the queue processor. Be carefull not to + mix its use with that of the solar mutex. + */ + ::osl::Mutex maMutex; + + view::SlideSorterView& mrView; + Queue& mrQueue; + BitmapCache& mrCache; + + void ProcessQueueEntry (void); +}; + + + + +//===== QueueProcessorThread ================================================ + +template <class Queue, class Request, class Cache, class Factory> + QueueProcessorThread<Queue, Request, Cache, Factory> + ::QueueProcessorThread ( + view::SlideSorterView& rView, + Queue& rQueue, + Cache& rCache) + : mbIsTerminated (false), + mbCanBeJoined (false), + mrView (rView), + mrQueue (rQueue), + mrCache (rCache) +{ + OSL_TRACE("QueueProcessorThread::constructor %p", this); + create(); +} + + + + +template <class Queue, class Request, class Cache, class Factory> + QueueProcessorThread<Queue, Request, Cache, Factory> + ::~QueueProcessorThread (void) +{ + OSL_TRACE("QueueProcessorThread::destructor %p", this); +} + + + + +template <class Queue, class Request, class Cache, class Factory> +void SAL_CALL QueueProcessorThread<Queue, Request, Cache, Factory>::run (void) +{ + OSL_TRACE("QueueProcessorThread::run(): running thread %p", this); + while ( ! mbIsTerminated) + { + OSL_TRACE("QueueProcessorThread::run(): still running thread %p: %d", this, mbIsTerminated?1:0); + if (mrQueue.IsEmpty()) + { + // Sleep while the queue is empty. + OSL_TRACE("QueueProcessorThread::run(): suspending thread %p", this); + suspend(); + OSL_TRACE("QueueProcessorThread::run(): running again thread %p", this); + } + + else if (GetpApp()->AnyInput()) + { + yield(); + // When there is input waiting to be processed we wait a short + // time and try again. + TimeValue aTimeToWait; + aTimeToWait.Seconds = 0; + aTimeToWait.Nanosec = 50*1000*1000; + OSL_TRACE("QueueProcessorThread::run(): input pending: waiting %d nanoseconds", + aTimeToWait.Nanosec); + wait (aTimeToWait); + } + + else + { + OSL_TRACE ("QueueProcessorThread::run(): Processing Query"); + ProcessQueueEntry(); + yield (); + } + } + OSL_TRACE("QueueProcessorThread::run(): exiting run %p", this); +} + + + + +template <class Queue, class Request, class Cache, class Factory> +void QueueProcessorThread<Queue, Request, Cache, Factory> + ::ProcessQueueEntry (void) +{ + Request* pRequest = NULL; + int nPriorityClass; + bool bRequestIsValid = false; + + do + { + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry(): testing for mbIsTerminated %p", this); + { + ::osl::MutexGuard aGuard (maMutex); + if (mbIsTerminated) + break; + if (mrQueue.IsEmpty()) + break; + } + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():acquiring mutex for bitmap creation %p", this); + ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); + ::osl::MutexGuard aGuard (maMutex); + if (mbIsTerminated) + break; + + if (mrQueue.IsEmpty()) + break; + + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry(): have mutexes %p", this); + + // Get the requeuest with the highest priority from the queue. + nPriorityClass = mrQueue.GetFrontPriorityClass(); + pRequest = &mrQueue.GetFront(); + mrQueue.PopFront(); + bRequestIsValid = true; + + + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():using request %p for creating bitmap", pRequest); + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():processing request for page %d with priority class ", + pRequest->GetPage()->GetPageNum(), nPriorityClass); + try + { + // Create a new preview bitmap and store it in the cache. + if (mbIsTerminated) + break; + BitmapEx aBitmap (Factory::CreateBitmap (*pRequest, mrView)); + if (mbIsTerminated) + break; + mrCache.SetBitmap ( + pRequest->GetPage(), + aBitmap, + nPriorityClass==0); + } + catch (...) + { + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry(): caught exception; %p", this); + // We are rendering a preview and can do without if need + // be. So keep going if something happens that should + // not happen. + } + } + while (false); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::Start (void) +{ + OSL_TRACE ("QueueProcessorThread::Start %p", this); + resume (); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::Stop (void) +{ + OSL_TRACE ("QueueProcessorThread::Stop %p", this); + suspend(); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::RemoveRequest (RequestData& rRequest) +{ + OSL_TRACE ("QueueProcessorThread::RemoveRequest %p", this); + // Do nothing else then wait for the mutex to be released. + ::osl::MutexGuard aGuard (mrQueue.GetMutex()); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::Terminate (void) +{ + // ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); + OSL_TRACE("QueueProcessorThread::Terminate(): terminating thread %p", this); + ::osl::Thread::terminate (); + { + ::osl::MutexGuard aGuard (maMutex); + OSL_TRACE("QueueProcessorThread::Terminate(): starting to join %p, %d", this, mbIsTerminated?1:0); + mbIsTerminated = true; + } + Start(); +} + + + + +/** This callback method is called when the run() method terminates. +*/ +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void SAL_CALL QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::onTerminated (void) +{ + ::osl::MutexGuard aGuard (maMutex); + mbCanBeJoined = true; + /* + OSL_TRACE("QueueProcessorThread::Terminate():join %p, %d", this, mbIsTerminated?1:0); + while (true) + { + { + ::osl::MutexGuard aGuard (maMutex); + if (mbCanBeJoined) + break; + } + Start(); + TimeValue aTimeToWait; + aTimeToWait.Seconds = 0; + aTimeToWait.Nanosec = 50*1000*1000; + OSL_TRACE("QueueProcessorThread::Terminate(): waiting for join"); + wait (aTimeToWait); + } + if (mbCanBeJoined) + join(); + else + OSL_TRACE("Can not join"); + OSL_TRACE("QueueProcessorThread::Terminate():terminated thread %p :%d", + this, mbIsTerminated?1:0); + */ +} + + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx new file mode 100644 index 000000000000..8030558759f3 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsRequestFactory.hxx" + +#include "SlsGenericPageCache.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include <svx/svdpagv.hxx> +#include <svx/sdrpagewindow.hxx> +#include <svx/sdr/contact/viewcontact.hxx> + + +namespace sd { namespace slidesorter { namespace cache { + +void RequestFactory::operator()( + RequestQueue& rRequestQueue, + const SharedCacheContext& rpCacheContext) +{ + ::boost::shared_ptr<std::vector<CacheKey> > aKeys; + + // Add the requests for the visible pages. + aKeys = rpCacheContext->GetEntryList(true); + if (aKeys.get() != NULL) + { + std::vector<CacheKey>::const_iterator iKey; + std::vector<CacheKey>::const_iterator iEnd (aKeys->end()); + for (iKey=aKeys->begin(); iKey!=iEnd; ++iKey) + rRequestQueue.AddRequest(*iKey, VISIBLE_NO_PREVIEW); + } + + // Add the requests for the non-visible pages. + aKeys = rpCacheContext->GetEntryList(false); + if (aKeys.get() != NULL) + { + std::vector<CacheKey>::const_iterator iKey; + std::vector<CacheKey>::const_iterator iEnd (aKeys->end()); + for (iKey=aKeys->begin(); iKey!=iEnd; ++iKey) + rRequestQueue.AddRequest(*iKey, NOT_VISIBLE); + } +} + + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx new file mode 100644 index 000000000000..d2872c2ad7bf --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_REQUEST_FACTORY_HXX +#define SD_SLIDESORTER_REQUEST_FACTORY_HXX + +#include "cache/SlsCacheContext.hxx" + +namespace sd { namespace slidesorter { namespace cache { + +class RequestQueue; + +class RequestFactory +{ +public: + void operator() ( + RequestQueue& rRequestQueue, + const SharedCacheContext& rpCacheContext); +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx b/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx new file mode 100644 index 000000000000..ebf6284a8f8b --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_CACHE_REQUEST_PRIORITY_CLASS_HXX +#define SD_SLIDESORTER_CACHE_REQUEST_PRIORITY_CLASS_HXX + +namespace sd { namespace slidesorter { namespace cache { + + +/** Each request for a preview creation has a priority. This enum defines + the available priorities. The special values MIN__CLASS and MAX__CLASS + are/can be used for validation and have to be kept up-to-date. +*/ +enum RequestPriorityClass +{ + MIN__CLASS = 0, + + // The slide is visible. A preview does not yet exist. + VISIBLE_NO_PREVIEW = MIN__CLASS, + // The slide is visible. A preview exists but is not up-to-date anymore. + VISIBLE_OUTDATED_PREVIEW, + // The slide is not visible. + NOT_VISIBLE, + + MAX__CLASS = NOT_VISIBLE +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx new file mode 100644 index 000000000000..ccd590131343 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx @@ -0,0 +1,291 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsRequestQueue.hxx" + +#include <set> + + +#undef VERBOSE +//#define VERBOSE + +namespace sd { namespace slidesorter { namespace cache { + +/** This class extends the actual request data with additional information + that is used by the priority queues. +*/ +class Request +{ +public: + Request ( + CacheKey aKey, sal_Int32 nPriority, RequestPriorityClass eClass) + : maKey(aKey), mnPriorityInClass(nPriority), meClass(eClass) + {} + /** Sort requests according to priority classes and then to priorities. + */ + class Comparator { public: + bool operator() (const Request& rRequest1, const Request& rRequest2) + { + if (rRequest1.meClass == rRequest2.meClass) + return (rRequest1.mnPriorityInClass > rRequest2.mnPriorityInClass); + else + return (rRequest1.meClass < rRequest2.meClass); + } + }; + /** Request data is compared arbitrarily by their addresses in memory. + This just establishes an order so that the STL containers are happy. + The order is not semantically interpreted. + */ + class DataComparator { public: + DataComparator (const Request&rRequest):maKey(rRequest.maKey){} + DataComparator (const CacheKey aKey):maKey(aKey){} + bool operator() (const Request& rRequest) { return maKey == rRequest.maKey; } + private: const CacheKey maKey; + }; + + CacheKey maKey; + sal_Int32 mnPriorityInClass; + RequestPriorityClass meClass; +}; + + +class RequestQueue::Container + : public ::std::set< + Request, + Request::Comparator> +{ +}; + + + + +//===== GenericRequestQueue ================================================= + + +RequestQueue::RequestQueue (const SharedCacheContext& rpCacheContext) + : maMutex(), + mpRequestQueue(new Container()), + mpCacheContext(rpCacheContext), + mnMinimumPriority(0), + mnMaximumPriority(1) +{ +} + + + + +RequestQueue::~RequestQueue (void) +{ +} + + + + +void RequestQueue::AddRequest ( + CacheKey aKey, + RequestPriorityClass eRequestClass, + bool /*bInsertWithHighestPriority*/) +{ + ::osl::MutexGuard aGuard (maMutex); + + OSL_ASSERT(eRequestClass>=MIN__CLASS && eRequestClass<=MAX__CLASS); + + // If the request is already a member of the queue then remove it so + // that the following insertion will use the new prioritization. +#ifdef VERBOSE + bool bRemoved = +#endif + RemoveRequest(aKey); + + // The priority of the request inside its priority class is defined by + // the page number. This ensures a strict top-to-bottom, left-to-right + // order. + sal_Int32 nPriority (mpCacheContext->GetPriority(aKey)); + Request aRequest (aKey, nPriority, eRequestClass); + mpRequestQueue->insert(aRequest); + + SSCD_SET_REQUEST_CLASS(rRequestData.GetPage(),eRequestClass); + +#ifdef VERBOSE + OSL_TRACE("%s request for page %d with priority class %d", + bRemoved?"replaced":"added", + (rRequestData.GetPage()->GetPageNum()-1)/2, + eRequestClass); +#endif +} + + + + +bool RequestQueue::RemoveRequest ( + CacheKey aKey) +{ + bool bRequestWasRemoved (false); + ::osl::MutexGuard aGuard (maMutex); + + while(true) + { + Container::const_iterator aRequestIterator = ::std::find_if ( + mpRequestQueue->begin(), + mpRequestQueue->end(), + Request::DataComparator(aKey)); + if (aRequestIterator != mpRequestQueue->end()) + { + if (aRequestIterator->mnPriorityInClass == mnMinimumPriority+1) + mnMinimumPriority++; + else if (aRequestIterator->mnPriorityInClass == mnMaximumPriority-1) + mnMaximumPriority--; + mpRequestQueue->erase(aRequestIterator); + bRequestWasRemoved = true; + + if (bRequestWasRemoved) + { + SSCD_SET_STATUS(rRequest.GetPage(),NONE); + } + } + else + break; + } + + return bRequestWasRemoved; +} + + + + +void RequestQueue::ChangeClass ( + CacheKey aKey, + RequestPriorityClass eNewRequestClass) +{ + ::osl::MutexGuard aGuard (maMutex); + + OSL_ASSERT(eNewRequestClass>=MIN__CLASS && eNewRequestClass<=MAX__CLASS); + + Container::const_iterator iRequest ( + ::std::find_if ( + mpRequestQueue->begin(), + mpRequestQueue->end(), + Request::DataComparator(aKey))); + if (iRequest!=mpRequestQueue->end() && iRequest->meClass!=eNewRequestClass) + { + AddRequest(aKey, eNewRequestClass, true); + SSCD_SET_REQUEST_CLASS(rRequestData.GetPage(),eNewRequestClass); + } +} + + + + +CacheKey RequestQueue::GetFront (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + if (mpRequestQueue->empty()) + throw ::com::sun::star::uno::RuntimeException( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "RequestQueue::GetFront(): queue is empty")), + NULL); + + return mpRequestQueue->begin()->maKey; +} + + + + +RequestPriorityClass RequestQueue::GetFrontPriorityClass (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + if (mpRequestQueue->empty()) + throw ::com::sun::star::uno::RuntimeException( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "RequestQueue::GetFrontPriorityClass(): queue is empty")), + NULL); + + return mpRequestQueue->begin()->meClass; +} + + + + +void RequestQueue::PopFront (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + if ( ! mpRequestQueue->empty()) + { + SSCD_SET_STATUS(maRequestQueue.begin()->mpData->GetPage(),NONE); + + mpRequestQueue->erase(mpRequestQueue->begin()); + + // Reset the priority counter if possible. + if (mpRequestQueue->empty()) + { + mnMinimumPriority = 0; + mnMaximumPriority = 1; + } + } +} + + + + +bool RequestQueue::IsEmpty (void) +{ + ::osl::MutexGuard aGuard (maMutex); + return mpRequestQueue->empty(); +} + + + + +void RequestQueue::Clear (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + mpRequestQueue->clear(); + mnMinimumPriority = 0; + mnMaximumPriority = 1; +} + + + + +::osl::Mutex& RequestQueue::GetMutex (void) +{ + return maMutex; +} + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx new file mode 100644 index 000000000000..f59ec702ac01 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx @@ -0,0 +1,133 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_REQUEST_QUEUE_HXX +#define SD_SLIDESORTER_REQUEST_QUEUE_HXX + +#include "SlsRequestPriorityClass.hxx" +#include "cache/SlsCacheContext.hxx" +#include "taskpane/SlideSorterCacheDisplay.hxx" +#include <drawdoc.hxx> +#include "osl/mutex.hxx" + + +namespace sd { namespace slidesorter { namespace cache { + +class RequestData; + +/** The request queue stores requests that are described by the RequestData + sorted according to priority class and then priority. +*/ +class RequestQueue +{ +public: + RequestQueue (const SharedCacheContext& rpCacheContext); + ~RequestQueue (void); + + /** Insert a request with highest or lowest priority in its priority + class. When the request is already present then it is first + removed. This effect is then a re-prioritization. + @param rRequestData + The request. + @param eRequestClass + The priority class in which to insert the request with highest + or lowest priority. + @param bInsertWithHighestPriority + When this flag is <TRUE/> the request is inserted with highes + priority in its class. When <FALSE/> the request is inserted + with lowest priority. + */ + void AddRequest ( + CacheKey aKey, + RequestPriorityClass eRequestClass, + bool bInsertWithHighestPriority = false); + + /** Remove the specified request from the queue. + @param rRequestData + It is OK when the specified request is not a member of the + queue. + @return + Returns <TRUE/> when the request has been successfully been + removed from the queue. Otherwise, e.g. because the request was + not a member of the queue, <FALSE/> is returned. + */ + bool RemoveRequest (CacheKey aKey); + + /** Change the priority class of the specified request. + */ + void ChangeClass ( + CacheKey aKey, + RequestPriorityClass eNewRequestClass); + + /** Get the request with the highest priority int the highest priority class. + */ + CacheKey GetFront (void); + + // For debugging. + RequestPriorityClass GetFrontPriorityClass (void); + + /** Really a synonym for RemoveRequest(GetFront()); + */ + void PopFront (void); + + /** Returns <TRUE/> when there is no element in the queue. + */ + bool IsEmpty (void); + + /** Remove all requests from the queue. This resets the minimum and + maximum priorities to their default values. + */ + void Clear (void); + + /** Return the mutex that guards the access to the priority queue. + */ + ::osl::Mutex& GetMutex (void); + +private: + ::osl::Mutex maMutex; + class Container; + ::boost::scoped_ptr<Container> mpRequestQueue; + SharedCacheContext mpCacheContext; + + /** A lower bound of the lowest priority of all elements in the queues. + The start value is 0. It is assigned and then decreased every time + when an element is inserted or marked as the request with lowest + priority. + */ + int mnMinimumPriority; + /** An upper bound of the highest priority of all elements in the queues. + The start value is 1. It is assigned and then increased every time + when an element is inserted or marked as the request with highest + priority. + */ + int mnMaximumPriority; +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/makefile.mk b/sd/source/ui/slidesorter/cache/makefile.mk new file mode 100755 index 000000000000..58862a28645a --- /dev/null +++ b/sd/source/ui/slidesorter/cache/makefile.mk @@ -0,0 +1,64 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slscache +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/SlsBitmapCache.obj \ + $(SLO)$/SlsBitmapCompressor.obj \ + $(SLO)$/SlsBitmapFactory.obj \ + $(SLO)$/SlsCacheCompactor.obj \ + $(SLO)$/SlsCacheConfiguration.obj \ + $(SLO)$/SlsGenericPageCache.obj \ + $(SLO)$/SlsPageCache.obj \ + $(SLO)$/SlsPageCacheManager.obj \ + $(SLO)$/SlsQueueProcessor.obj \ + $(SLO)$/SlsRequestFactory.obj \ + $(SLO)$/SlsRequestQueue.obj + + +EXCEPTIONSFILES= + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + |