1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "PresenterPreviewCache.hxx"
21 
22 #include <cache/SlsPageCache.hxx>
23 #include <cache/SlsCacheContext.hxx>
24 #include <vcl/bitmapex.hxx>
25 #include <sdpage.hxx>
26 #include <cppcanvas/vclfactory.hxx>
27 #include <com/sun/star/drawing/XDrawPage.hpp>
28 
29 namespace com { namespace sun { namespace star { namespace uno { class XComponentContext; } } } }
30 
31 using namespace ::com::sun::star;
32 using namespace ::com::sun::star::uno;
33 using namespace ::sd::slidesorter::cache;
34 
35 namespace sd { namespace presenter {
36 
37 class PresenterPreviewCache::PresenterCacheContext : public CacheContext
38 {
39 public:
40     PresenterCacheContext();
41 
42     void SetDocumentSlides (
43         const Reference<container::XIndexAccess>& rxSlides,
44         const Reference<XInterface>& rxDocument);
45     void SetVisibleSlideRange (
46         const sal_Int32 nFirstVisibleSlideIndex,
47         const sal_Int32 nLastVisibleSlideIndex);
48     const SdrPage* GetPage (const sal_Int32 nSlideIndex) const;
49     void AddPreviewCreationNotifyListener (const Reference<drawing::XSlidePreviewCacheListener>& rxListener);
50     void RemovePreviewCreationNotifyListener (const Reference<drawing::XSlidePreviewCacheListener>& rxListener);
51 
52     // CacheContext
53     virtual void NotifyPreviewCreation (CacheKey aKey) override;
54     virtual bool IsIdle() override;
55     virtual bool IsVisible (CacheKey aKey) override;
56     virtual const SdrPage* GetPage (CacheKey aKey) override;
57     virtual std::shared_ptr<std::vector<CacheKey> > GetEntryList (bool bVisible) override;
58     virtual sal_Int32 GetPriority (CacheKey aKey) override;
59     virtual css::uno::Reference<css::uno::XInterface> GetModel() override;
60 
61 private:
62     Reference<container::XIndexAccess> mxSlides;
63     Reference<XInterface> mxDocument;
64     sal_Int32 mnFirstVisibleSlideIndex;
65     sal_Int32 mnLastVisibleSlideIndex;
66     typedef ::std::vector<css::uno::Reference<css::drawing::XSlidePreviewCacheListener> > ListenerContainer;
67     ListenerContainer maListeners;
68 
69     void CallListeners (const sal_Int32 nSlideIndex);
70 };
71 
72 //===== PresenterPreviewCache =================================================
73 
PresenterPreviewCache()74 PresenterPreviewCache::PresenterPreviewCache ()
75     : PresenterPreviewCacheInterfaceBase(m_aMutex),
76       maPreviewSize(Size(200,200)),
77       mpCacheContext(new PresenterCacheContext()),
78       mpCache(new PageCache(maPreviewSize, Bitmap::HasFastScale(), mpCacheContext))
79 {
80 }
81 
~PresenterPreviewCache()82 PresenterPreviewCache::~PresenterPreviewCache()
83 {
84 }
85 
86 //----- XInitialize -----------------------------------------------------------
87 
initialize(const Sequence<Any> & rArguments)88 void SAL_CALL PresenterPreviewCache::initialize (const Sequence<Any>& rArguments)
89 {
90     if (rArguments.hasElements())
91         throw RuntimeException();
92 }
93 
94 //----- XSlidePreviewCache ----------------------------------------------------
95 
setDocumentSlides(const Reference<container::XIndexAccess> & rxSlides,const Reference<XInterface> & rxDocument)96 void SAL_CALL PresenterPreviewCache::setDocumentSlides (
97     const Reference<container::XIndexAccess>& rxSlides,
98     const Reference<XInterface>& rxDocument)
99 {
100     ThrowIfDisposed();
101     OSL_ASSERT(mpCacheContext != nullptr);
102 
103     mpCacheContext->SetDocumentSlides(rxSlides, rxDocument);
104 }
105 
setVisibleRange(sal_Int32 nFirstVisibleSlideIndex,sal_Int32 nLastVisibleSlideIndex)106 void SAL_CALL PresenterPreviewCache::setVisibleRange (
107     sal_Int32 nFirstVisibleSlideIndex,
108     sal_Int32 nLastVisibleSlideIndex)
109 {
110     ThrowIfDisposed();
111     OSL_ASSERT(mpCacheContext != nullptr);
112 
113     mpCacheContext->SetVisibleSlideRange (nFirstVisibleSlideIndex, nLastVisibleSlideIndex);
114 }
115 
setPreviewSize(const css::geometry::IntegerSize2D & rSize)116 void SAL_CALL PresenterPreviewCache::setPreviewSize (
117     const css::geometry::IntegerSize2D& rSize)
118 {
119     ThrowIfDisposed();
120     OSL_ASSERT(mpCache != nullptr);
121 
122     maPreviewSize = Size(rSize.Width, rSize.Height);
123     mpCache->ChangeSize(maPreviewSize, Bitmap::HasFastScale());
124 }
125 
getSlidePreview(sal_Int32 nSlideIndex,const Reference<rendering::XCanvas> & rxCanvas)126 Reference<rendering::XBitmap> SAL_CALL PresenterPreviewCache::getSlidePreview (
127     sal_Int32 nSlideIndex,
128     const Reference<rendering::XCanvas>& rxCanvas)
129 {
130     ThrowIfDisposed();
131     OSL_ASSERT(mpCacheContext != nullptr);
132 
133     cppcanvas::CanvasSharedPtr pCanvas (
134         cppcanvas::VCLFactory::createCanvas(rxCanvas));
135 
136     const SdrPage* pPage = mpCacheContext->GetPage(nSlideIndex);
137     if (pPage == nullptr)
138         throw RuntimeException();
139 
140     const BitmapEx aPreview (mpCache->GetPreviewBitmap(pPage,true));
141     if (aPreview.IsEmpty())
142         return nullptr;
143     else
144         return cppcanvas::VCLFactory::createBitmap(
145             pCanvas,
146             aPreview)->getUNOBitmap();
147 }
148 
addPreviewCreationNotifyListener(const Reference<drawing::XSlidePreviewCacheListener> & rxListener)149 void SAL_CALL PresenterPreviewCache::addPreviewCreationNotifyListener (
150     const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
151 {
152     if (rBHelper.bDisposed || rBHelper.bInDispose)
153         return;
154     if (rxListener.is())
155         mpCacheContext->AddPreviewCreationNotifyListener(rxListener);
156 }
157 
removePreviewCreationNotifyListener(const css::uno::Reference<css::drawing::XSlidePreviewCacheListener> & rxListener)158 void SAL_CALL PresenterPreviewCache::removePreviewCreationNotifyListener (
159     const css::uno::Reference<css::drawing::XSlidePreviewCacheListener>& rxListener)
160 {
161     ThrowIfDisposed();
162     mpCacheContext->RemovePreviewCreationNotifyListener(rxListener);
163 }
164 
pause()165 void SAL_CALL PresenterPreviewCache::pause()
166 {
167     ThrowIfDisposed();
168     OSL_ASSERT(mpCache != nullptr);
169     mpCache->Pause();
170 }
171 
resume()172 void SAL_CALL PresenterPreviewCache::resume()
173 {
174     ThrowIfDisposed();
175     OSL_ASSERT(mpCache != nullptr);
176     mpCache->Resume();
177 }
178 
ThrowIfDisposed()179 void PresenterPreviewCache::ThrowIfDisposed()
180 {
181     if (rBHelper.bDisposed || rBHelper.bInDispose)
182     {
183         throw lang::DisposedException ("PresenterPreviewCache object has already been disposed",
184             static_cast<uno::XWeak*>(this));
185     }
186 }
187 
188 //===== PresenterPreviewCache::PresenterCacheContext ==========================
189 
PresenterCacheContext()190 PresenterPreviewCache::PresenterCacheContext::PresenterCacheContext()
191     : mxSlides(),
192       mxDocument(),
193       mnFirstVisibleSlideIndex(-1),
194       mnLastVisibleSlideIndex(-1),
195       maListeners()
196 {
197 }
198 
SetDocumentSlides(const Reference<container::XIndexAccess> & rxSlides,const Reference<XInterface> & rxDocument)199 void PresenterPreviewCache::PresenterCacheContext::SetDocumentSlides (
200     const Reference<container::XIndexAccess>& rxSlides,
201     const Reference<XInterface>& rxDocument)
202 {
203     mxSlides = rxSlides;
204     mxDocument = rxDocument;
205     mnFirstVisibleSlideIndex = -1;
206     mnLastVisibleSlideIndex = -1;
207 }
208 
SetVisibleSlideRange(const sal_Int32 nFirstVisibleSlideIndex,const sal_Int32 nLastVisibleSlideIndex)209 void PresenterPreviewCache::PresenterCacheContext::SetVisibleSlideRange (
210     const sal_Int32 nFirstVisibleSlideIndex,
211     const sal_Int32 nLastVisibleSlideIndex)
212 {
213     if (nFirstVisibleSlideIndex > nLastVisibleSlideIndex || nFirstVisibleSlideIndex<0)
214     {
215         mnFirstVisibleSlideIndex = -1;
216         mnLastVisibleSlideIndex = -1;
217     }
218     else
219     {
220         mnFirstVisibleSlideIndex = nFirstVisibleSlideIndex;
221         mnLastVisibleSlideIndex = nLastVisibleSlideIndex;
222     }
223     if (mxSlides.is() && mnLastVisibleSlideIndex >= mxSlides->getCount())
224         mnLastVisibleSlideIndex = mxSlides->getCount() - 1;
225 }
226 
AddPreviewCreationNotifyListener(const Reference<drawing::XSlidePreviewCacheListener> & rxListener)227 void PresenterPreviewCache::PresenterCacheContext::AddPreviewCreationNotifyListener (
228     const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
229 {
230     maListeners.push_back(rxListener);
231 }
232 
RemovePreviewCreationNotifyListener(const Reference<drawing::XSlidePreviewCacheListener> & rxListener)233 void PresenterPreviewCache::PresenterCacheContext::RemovePreviewCreationNotifyListener (
234     const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
235 {
236     auto iListener = std::find(maListeners.begin(), maListeners.end(), rxListener);
237     if (iListener != maListeners.end())
238         maListeners.erase(iListener);
239 }
240 
241 //----- CacheContext ----------------------------------------------------------
242 
NotifyPreviewCreation(CacheKey aKey)243 void PresenterPreviewCache::PresenterCacheContext::NotifyPreviewCreation (
244     CacheKey aKey)
245 {
246     if ( ! mxSlides.is())
247         return;
248     const sal_Int32 nCount(mxSlides->getCount());
249     for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
250         if (aKey == GetPage(nIndex))
251             CallListeners(nIndex);
252 }
253 
IsIdle()254 bool PresenterPreviewCache::PresenterCacheContext::IsIdle()
255 {
256     return true;
257 }
258 
IsVisible(CacheKey aKey)259 bool PresenterPreviewCache::PresenterCacheContext::IsVisible (CacheKey aKey)
260 {
261     if (mnFirstVisibleSlideIndex < 0)
262         return false;
263     for (sal_Int32 nIndex=mnFirstVisibleSlideIndex; nIndex<=mnLastVisibleSlideIndex; ++nIndex)
264     {
265         const SdrPage* pPage = GetPage(nIndex);
266         if (pPage == aKey)
267             return true;
268     }
269     return false;
270 }
271 
GetPage(CacheKey aKey)272 const SdrPage* PresenterPreviewCache::PresenterCacheContext::GetPage (CacheKey aKey)
273 {
274     return aKey;
275 }
276 
277 std::shared_ptr<std::vector<CacheKey> >
GetEntryList(bool bVisible)278     PresenterPreviewCache::PresenterCacheContext::GetEntryList (bool bVisible)
279 {
280     std::shared_ptr<std::vector<CacheKey> > pKeys (new std::vector<CacheKey>);
281 
282     if ( ! mxSlides.is())
283         return pKeys;
284 
285     const sal_Int32 nFirstIndex (bVisible ? mnFirstVisibleSlideIndex : 0);
286     const sal_Int32 nLastIndex (bVisible ? mnLastVisibleSlideIndex : mxSlides->getCount()-1);
287 
288     if (nFirstIndex < 0)
289         return pKeys;
290 
291     for (sal_Int32 nIndex=nFirstIndex; nIndex<=nLastIndex; ++nIndex)
292     {
293         pKeys->push_back(GetPage(nIndex));
294     }
295 
296     return pKeys;
297 }
298 
GetPriority(CacheKey aKey)299 sal_Int32 PresenterPreviewCache::PresenterCacheContext::GetPriority (CacheKey aKey)
300 {
301     if ( ! mxSlides.is())
302         return 0;
303 
304     const sal_Int32 nCount (mxSlides->getCount());
305 
306     for (sal_Int32 nIndex=mnFirstVisibleSlideIndex; nIndex<=mnLastVisibleSlideIndex; ++nIndex)
307         if (aKey == GetPage(nIndex))
308             return -nCount-1+nIndex;
309 
310     for (sal_Int32 nIndex=0; nIndex<=nCount; ++nIndex)
311         if (aKey == GetPage(nIndex))
312             return nIndex;
313 
314     return 0;
315 }
316 
GetModel()317 Reference<XInterface> PresenterPreviewCache::PresenterCacheContext::GetModel()
318 {
319     return mxDocument;
320 }
321 
GetPage(const sal_Int32 nSlideIndex) const322 const SdrPage* PresenterPreviewCache::PresenterCacheContext::GetPage (
323     const sal_Int32 nSlideIndex) const
324 {
325     if ( ! mxSlides.is())
326         return nullptr;
327     if (nSlideIndex < 0 || nSlideIndex >= mxSlides->getCount())
328         return nullptr;
329 
330     Reference<drawing::XDrawPage> xSlide (mxSlides->getByIndex(nSlideIndex), UNO_QUERY);
331     const SdPage* pPage = SdPage::getImplementation(xSlide);
332     return dynamic_cast<const SdrPage*>(pPage);
333 }
334 
CallListeners(const sal_Int32 nIndex)335 void PresenterPreviewCache::PresenterCacheContext::CallListeners (
336     const sal_Int32 nIndex)
337 {
338     ListenerContainer aListeners (maListeners);
339     for (const auto& rxListener : aListeners)
340     {
341         try
342         {
343             rxListener->notifyPreviewCreation(nIndex);
344         }
345         catch (lang::DisposedException&)
346         {
347             RemovePreviewCreationNotifyListener(rxListener);
348         }
349     }
350 }
351 
352 } } // end of namespace ::sd::presenter
353 
354 
355 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
com_sun_star_comp_Draw_PresenterPreviewCache_get_implementation(css::uno::XComponentContext *,css::uno::Sequence<css::uno::Any> const &)356 com_sun_star_comp_Draw_PresenterPreviewCache_get_implementation(css::uno::XComponentContext*,
357                                                                 css::uno::Sequence<css::uno::Any> const &)
358 {
359     return cppu::acquire(new sd::presenter::PresenterPreviewCache);
360 }
361 
362 
363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
364