1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_sd.hxx"
29 
30 #include "SlsGenericPageCache.hxx"
31 
32 #include "SlsQueueProcessor.hxx"
33 #include "SlsRequestPriorityClass.hxx"
34 #include "SlsRequestFactory.hxx"
35 #include "cache/SlsPageCacheManager.hxx"
36 #include "model/SlideSorterModel.hxx"
37 #include "model/SlsPageDescriptor.hxx"
38 #include "controller/SlideSorterController.hxx"
39 
40 
41 namespace sd { namespace slidesorter { namespace cache {
42 
43 GenericPageCache::GenericPageCache (
44     const Size& rPreviewSize,
45     const bool bDoSuperSampling,
46     const SharedCacheContext& rpCacheContext)
47     : mpBitmapCache(),
48       maRequestQueue(rpCacheContext),
49       mpQueueProcessor(),
50       mpCacheContext(rpCacheContext),
51       maPreviewSize(rPreviewSize),
52       mbDoSuperSampling(bDoSuperSampling)
53 {
54     // A large size may indicate an error of the caller.  After all we
55     // are creating previews.
56         DBG_ASSERT (maPreviewSize.Width()<1000 && maPreviewSize.Height()<1000,
57         "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. "
58         "This may indicate an error.");
59 }
60 
61 
62 
63 
64 GenericPageCache::~GenericPageCache (void)
65 {
66     if (mpQueueProcessor.get() != NULL)
67         mpQueueProcessor->Stop();
68     maRequestQueue.Clear();
69     if (mpQueueProcessor.get() != NULL)
70         mpQueueProcessor->Terminate();
71     mpQueueProcessor.reset();
72 
73     if (mpBitmapCache.get() != NULL)
74         PageCacheManager::Instance()->ReleaseCache(mpBitmapCache);
75     mpBitmapCache.reset();
76 }
77 
78 
79 
80 
81 void GenericPageCache::ProvideCacheAndProcessor (void)
82 {
83     if (mpBitmapCache.get() == NULL)
84         mpBitmapCache = PageCacheManager::Instance()->GetCache(
85             mpCacheContext->GetModel(),
86             maPreviewSize);
87 
88     if (mpQueueProcessor.get() == NULL)
89         mpQueueProcessor.reset(new QueueProcessor(
90             maRequestQueue,
91             mpBitmapCache,
92             maPreviewSize,
93             mbDoSuperSampling,
94             mpCacheContext));
95 }
96 
97 
98 
99 
100 void GenericPageCache::ChangePreviewSize (
101     const Size& rPreviewSize,
102     const bool bDoSuperSampling)
103 {
104     if (rPreviewSize!=maPreviewSize || bDoSuperSampling!=mbDoSuperSampling)
105     {
106         // A large size may indicate an error of the caller.  After all we
107         // are creating previews.
108         DBG_ASSERT (maPreviewSize.Width()<1000 && maPreviewSize.Height()<1000,
109             "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. "
110             "This may indicate an error.");
111 
112         if (mpBitmapCache.get() != NULL)
113         {
114             mpBitmapCache = PageCacheManager::Instance()->ChangeSize(
115                 mpBitmapCache, maPreviewSize, rPreviewSize);
116             if (mpQueueProcessor.get() != NULL)
117             {
118                 mpQueueProcessor->SetPreviewSize(rPreviewSize, bDoSuperSampling);
119                 mpQueueProcessor->SetBitmapCache(mpBitmapCache);
120             }
121         }
122         maPreviewSize = rPreviewSize;
123         mbDoSuperSampling = bDoSuperSampling;
124     }
125 }
126 
127 
128 
129 
130 Bitmap GenericPageCache::GetPreviewBitmap (
131     const CacheKey aKey,
132     const bool bResize)
133 {
134     OSL_ASSERT(aKey != NULL);
135 
136     Bitmap aPreview;
137     bool bMayBeUpToDate = true;
138     ProvideCacheAndProcessor();
139     const SdrPage* pPage = mpCacheContext->GetPage(aKey);
140     if (mpBitmapCache->HasBitmap(pPage))
141     {
142         aPreview = mpBitmapCache->GetBitmap(pPage);
143         const Size aBitmapSize (aPreview.GetSizePixel());
144         if (aBitmapSize != maPreviewSize)
145         {
146             // Scale the bitmap to the desired size when that is possible,
147             // i.e. the bitmap is not empty.
148             if (bResize && aBitmapSize.Width()>0 && aBitmapSize.Height()>0)
149             {
150                 aPreview.Scale(maPreviewSize, BMP_SCALE_FAST);
151             }
152             bMayBeUpToDate = false;
153         }
154         else
155             bMayBeUpToDate = true;
156     }
157     else
158         bMayBeUpToDate = false;
159 
160     // Request the creation of a correctly sized preview bitmap.  We do this
161     // even when the size of the bitmap in the cache is correct because its
162     // content may be not up-to-date anymore.
163     RequestPreviewBitmap(aKey, bMayBeUpToDate);
164 
165     return aPreview;
166 }
167 
168 
169 
170 
171 Bitmap GenericPageCache::GetMarkedPreviewBitmap (
172     const CacheKey aKey,
173     const bool bResize)
174 {
175     OSL_ASSERT(aKey != NULL);
176 
177     ProvideCacheAndProcessor();
178     const SdrPage* pPage = mpCacheContext->GetPage(aKey);
179     Bitmap aMarkedPreview (mpBitmapCache->GetMarkedBitmap(pPage));
180     const Size aBitmapSize (aMarkedPreview.GetSizePixel());
181     if (bResize && aBitmapSize != maPreviewSize)
182     {
183         // Scale the bitmap to the desired size when that is possible,
184         // i.e. the bitmap is not empty.
185         if (aBitmapSize.Width()>0 && aBitmapSize.Height()>0)
186         {
187             aMarkedPreview.Scale(maPreviewSize, BMP_SCALE_FAST);
188         }
189     }
190 
191     return aMarkedPreview;
192 }
193 
194 
195 
196 
197 void GenericPageCache::SetMarkedPreviewBitmap (
198     const CacheKey aKey,
199     const Bitmap& rMarkedBitmap)
200 {
201     OSL_ASSERT(aKey != NULL);
202 
203     ProvideCacheAndProcessor();
204     const SdrPage* pPage = mpCacheContext->GetPage(aKey);
205     mpBitmapCache->SetMarkedBitmap(pPage, rMarkedBitmap);
206 }
207 
208 
209 
210 
211 void GenericPageCache::RequestPreviewBitmap (
212     const CacheKey aKey,
213     const bool bMayBeUpToDate)
214 {
215     OSL_ASSERT(aKey != NULL);
216 
217     const SdrPage* pPage = mpCacheContext->GetPage(aKey);
218 
219     ProvideCacheAndProcessor();
220 
221     // Determine if the available bitmap is up to date.
222     bool bIsUpToDate = false;
223     if (bMayBeUpToDate)
224         bIsUpToDate = mpBitmapCache->BitmapIsUpToDate (pPage);
225     if (bIsUpToDate)
226     {
227         const Bitmap aPreview (mpBitmapCache->GetBitmap(pPage));
228         if (aPreview.IsEmpty() || aPreview.GetSizePixel()!=maPreviewSize)
229               bIsUpToDate = false;
230     }
231 
232     if ( ! bIsUpToDate)
233     {
234         // No, the bitmap is not up-to-date.  Request a new one.
235         RequestPriorityClass ePriorityClass (NOT_VISIBLE);
236         if (mpCacheContext->IsVisible(aKey))
237         {
238             if (mpBitmapCache->HasBitmap(pPage))
239                 ePriorityClass = VISIBLE_OUTDATED_PREVIEW;
240             else
241                 ePriorityClass = VISIBLE_NO_PREVIEW;
242         }
243         maRequestQueue.AddRequest(aKey, ePriorityClass);
244         mpQueueProcessor->Start(ePriorityClass);
245     }
246 }
247 
248 
249 
250 
251 bool GenericPageCache::InvalidatePreviewBitmap (const CacheKey aKey)
252 {
253     // Invalidate the page in all caches that reference it, not just this one.
254     ::boost::shared_ptr<cache::PageCacheManager> pCacheManager (
255         cache::PageCacheManager::Instance());
256     if (pCacheManager)
257         return pCacheManager->InvalidatePreviewBitmap(
258             mpCacheContext->GetModel(),
259             aKey);
260     else if (mpBitmapCache.get() != NULL)
261         return mpBitmapCache->InvalidateBitmap(mpCacheContext->GetPage(aKey));
262     else
263         return false;
264 }
265 
266 
267 
268 
269 void GenericPageCache::ReleasePreviewBitmap (const CacheKey aKey)
270 {
271     if (mpBitmapCache.get() != NULL)
272     {
273         // Suspend the queue processing temporarily to avoid the reinsertion
274         // of the request that is to be deleted.
275         mpQueueProcessor->Stop();
276 
277         maRequestQueue.RemoveRequest(aKey);
278         mpQueueProcessor->RemoveRequest(aKey);
279 
280         // Resume the queue processing.
281         if ( ! maRequestQueue.IsEmpty())
282         {
283             try
284             {
285                 mpQueueProcessor->Start(maRequestQueue.GetFrontPriorityClass());
286             }
287             catch (::com::sun::star::uno::RuntimeException)
288             {
289             }
290         }
291     }
292 
293     // We do not relase the preview bitmap that is associated with the page
294     // of the given request data because this method is called when the
295     // request data, typically a view-object-contact object, is destroyed.
296     // The page object usually lives longer than that and thus the preview
297     // bitmap may be used later on.
298 }
299 
300 
301 
302 
303 void GenericPageCache::InvalidateCache (const bool bUpdateCache)
304 {
305     if (mpBitmapCache)
306     {
307         // When the cache is being invalidated then it makes no sense to
308         // continue creating preview bitmaps.  However, this may be
309         // re-started below.
310         mpQueueProcessor->Stop();
311         maRequestQueue.Clear();
312 
313         // Mark the previews in the cache as not being up-to-date anymore.
314         // Depending on the given bUpdateCache flag we start to create new
315         // preview bitmaps.
316         mpBitmapCache->InvalidateCache();
317         if (bUpdateCache)
318             RequestFactory()(maRequestQueue, mpCacheContext);
319     }
320 }
321 
322 
323 
324 
325 void GenericPageCache::SetPreciousFlag (
326     const CacheKey aKey,
327     const bool bIsPrecious)
328 {
329     ProvideCacheAndProcessor();
330 
331     // Change the request priority class according to the new precious flag.
332     if (bIsPrecious)
333     {
334         if (mpBitmapCache->HasBitmap(mpCacheContext->GetPage(aKey)))
335             maRequestQueue.ChangeClass(aKey,VISIBLE_OUTDATED_PREVIEW);
336         else
337             maRequestQueue.ChangeClass(aKey,VISIBLE_NO_PREVIEW);
338     }
339     else
340     {
341         if (mpBitmapCache->IsFull())
342         {
343             // When the bitmap cache is full then requests for slides that
344             // are not visible are removed.
345             maRequestQueue.RemoveRequest(aKey);
346         }
347         else
348             maRequestQueue.ChangeClass(aKey,NOT_VISIBLE);
349     }
350 
351     mpBitmapCache->SetPrecious(mpCacheContext->GetPage(aKey), bIsPrecious);
352 }
353 
354 
355 
356 
357 void GenericPageCache::Pause (void)
358 {
359     ProvideCacheAndProcessor();
360     if (mpQueueProcessor.get() != NULL)
361         mpQueueProcessor->Pause();
362 }
363 
364 
365 
366 
367 void GenericPageCache::Resume (void)
368 {
369     ProvideCacheAndProcessor();
370     if (mpQueueProcessor.get() != NULL)
371         mpQueueProcessor->Resume();
372 }
373 
374 
375 
376 } } } // end of namespace ::sd::slidesorter::cache
377 
378 
379 
380