LibreOffice Module sdext (master)  1
PresenterSlidePreview.cxx
Go to the documentation of this file.
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 
25 #include <com/sun/star/awt/XWindowPeer.hpp>
26 #include <com/sun/star/rendering/CompositeOperation.hpp>
27 
28 using namespace ::com::sun::star;
29 using namespace ::com::sun::star::uno;
30 using namespace ::com::sun::star::drawing::framework;
31 
32 namespace
33 {
34  // Use a super sample factor greater than 1 to achieve a poor mans
35  // antialiasing effect for slide previews.
36  const sal_Int16 gnSuperSampleFactor = 2;
37 }
38 
39 namespace sdext::presenter {
40 
41 //===== PresenterSlidePreview =================================================
42 
44  const Reference<XComponentContext>& rxContext,
45  const Reference<XResourceId>& rxViewId,
46  const Reference<XPane>& rxAnchorPane,
47  const ::rtl::Reference<PresenterController>& rpPresenterController)
49  mpPresenterController(rpPresenterController),
50  mxViewId(rxViewId),
51  mnSlideAspectRatio(28.0 / 21.0)
52 {
53  if ( ! rxContext.is()
54  || ! rxViewId.is()
55  || ! rxAnchorPane.is()
56  || ! rpPresenterController.is())
57  {
58  throw RuntimeException(
59  "PresenterSlidePreview can not be constructed due to empty argument",
60  static_cast<XWeak*>(this));
61  }
62 
63  mxWindow = rxAnchorPane->getWindow();
64  mxCanvas = rxAnchorPane->getCanvas();
65 
66  if (mxWindow.is())
67  {
68  mxWindow->addWindowListener(this);
69  mxWindow->addPaintListener(this);
70 
71  Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
72  if (xPeer.is())
73  xPeer->setBackground(util::Color(0xff000000));
74 
75  mxWindow->setVisible(true);
76  }
77 
79  mnSlideAspectRatio = mpPresenterController->GetSlideAspectRatio();
80 
81  Reference<lang::XMultiComponentFactory> xFactory = rxContext->getServiceManager();
82  if (xFactory.is())
83  mxPreviewRenderer.set(
84  xFactory->createInstanceWithContext(
85  "com.sun.star.drawing.SlideRenderer",
86  rxContext),
87  UNO_QUERY);
88  mpBitmaps = std::make_shared<PresenterBitmapContainer>(
89  "PresenterScreenSettings/ScrollBar/Bitmaps",
90  std::shared_ptr<PresenterBitmapContainer>(),
91  rxContext,
92  mxCanvas);
93  Resize();
94 }
95 
97 {
98 }
99 
101 {
102  if (mxWindow.is())
103  {
104  mxWindow->removeWindowListener(this);
105  mxWindow->removePaintListener(this);
106  mxWindow = nullptr;
107  mxCanvas = nullptr;
108  }
109 
110  Reference<lang::XComponent> xComponent (mxPreviewRenderer, UNO_QUERY);
111  if (xComponent.is())
112  xComponent->dispose();
113 }
114 
115 //----- XResourceId -----------------------------------------------------------
116 
117 Reference<XResourceId> SAL_CALL PresenterSlidePreview::getResourceId()
118 {
119  return mxViewId;
120 }
121 
123 {
124  return false;
125 }
126 
127 //----- XWindowListener -------------------------------------------------------
128 
129 void SAL_CALL PresenterSlidePreview::windowResized (const awt::WindowEvent&)
130 {
131  ThrowIfDisposed();
132  ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
133  Resize();
134 }
135 
136 void SAL_CALL PresenterSlidePreview::windowMoved (const awt::WindowEvent&) {}
137 
138 void SAL_CALL PresenterSlidePreview::windowShown (const lang::EventObject&)
139 {
140  ThrowIfDisposed();
141  ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
142  Resize();
143 }
144 
145 void SAL_CALL PresenterSlidePreview::windowHidden (const lang::EventObject&) {}
146 
147 //----- XPaintListener --------------------------------------------------------
148 
149 void SAL_CALL PresenterSlidePreview::windowPaint (const awt::PaintEvent& rEvent)
150 {
151  ThrowIfDisposed();
152 
153  ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
154  if (mxWindow.is())
155  Paint(awt::Rectangle(
156  rEvent.UpdateRect.X,
157  rEvent.UpdateRect.Y,
158  rEvent.UpdateRect.Width,
159  rEvent.UpdateRect.Height));
160 }
161 
162 //----- lang::XEventListener --------------------------------------------------
163 
164 void SAL_CALL PresenterSlidePreview::disposing (const lang::EventObject& rEvent)
165 {
166  if (rEvent.Source == mxWindow)
167  {
168  mxWindow = nullptr;
169  mxCanvas = nullptr;
170  mxPreview = nullptr;
171  }
172 }
173 
174 //----- XDrawView -------------------------------------------------------------
175 
177 {
178  ThrowIfDisposed();
179  ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
180  SetSlide(rxSlide);
181 }
182 
184 {
185  ThrowIfDisposed();
186  return nullptr;
187 }
188 
189 
191 {
192  mxCurrentSlide = rxPage;
193  mxPreview = nullptr;
194 
195  // The preview is not transparent, therefore only this window, not its
196  // parent, has to be invalidated.
197  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
198 }
199 
200 void PresenterSlidePreview::Paint (const awt::Rectangle& rBoundingBox)
201 {
202  if ( ! mxWindow.is())
203  return;
204  if ( ! mxCanvas.is())
205  return;
206  if ( ! mxPreviewRenderer.is())
207  return;
208 
209  // Make sure that a preview in the correct size exists.
210  awt::Rectangle aWindowBox (mxWindow->getPosSize());
211 
212  bool bCustomAnimation = false;
213  bool bTransition = false;
214  if( mxCurrentSlide.is() )
215  {
218  }
219 
220  if ( ! mxPreview.is() && mxCurrentSlide.is())
221  {
222  // Create a new preview bitmap.
223  mxPreview = mxPreviewRenderer->createPreviewForCanvas(
225  awt::Size(aWindowBox.Width, aWindowBox.Height),
226  gnSuperSampleFactor,
227  mxCanvas);
228  }
229 
230  // Determine the bounding box of the preview.
231  awt::Rectangle aPreviewBox;
232  if (mxPreview.is())
233  {
234  const geometry::IntegerSize2D aPreviewSize (mxPreview->getSize());
235  aPreviewBox = awt::Rectangle(
236  (aWindowBox.Width - aPreviewSize.Width)/2,
237  (aWindowBox.Height - aPreviewSize.Height)/2,
238  aPreviewSize.Width,
239  aPreviewSize.Height);
240  }
241  else
242  {
243  if (mnSlideAspectRatio > 0)
244  {
245  const awt::Size aPreviewSize (mxPreviewRenderer->calculatePreviewSize(
246  mnSlideAspectRatio,awt::Size(aWindowBox.Width, aWindowBox.Height)));
247  aPreviewBox = awt::Rectangle(
248  (aWindowBox.Width - aPreviewSize.Width)/2,
249  (aWindowBox.Height - aPreviewSize.Height)/2,
250  aPreviewSize.Width,
251  aPreviewSize.Height);
252  }
253  }
254 
255  // Paint the background.
256  mpPresenterController->GetCanvasHelper()->Paint(
257  mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
258  mxCanvas,
259  rBoundingBox,
260  awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
261  aPreviewBox);
262 
263  // Paint the preview.
264  const rendering::ViewState aViewState(
265  geometry::AffineMatrix2D(1,0,0, 0,1,0),
266  nullptr);
267 
268  Sequence<double> aBackgroundColor(4);
269  rendering::RenderState aRenderState (
270  geometry::AffineMatrix2D(1, 0, aPreviewBox.X, 0, 1, aPreviewBox.Y),
271  nullptr,
272  aBackgroundColor,
273  rendering::CompositeOperation::SOURCE);
274  PresenterCanvasHelper::SetDeviceColor(aRenderState, 0x00000000);
275  if (mxPreview.is())
276  {
277  mxCanvas->drawBitmap(mxPreview, aViewState, aRenderState);
278  if( bTransition )
279  {
280  const awt::Rectangle aTransitionPreviewBox(5, aWindowBox.Height-20, 0, 0);
281  SharedBitmapDescriptor aTransitionDescriptor = mpBitmaps->GetBitmap("Transition");
282  Reference<rendering::XBitmap> xTransitionIcon (aTransitionDescriptor->GetNormalBitmap());
283  rendering::RenderState aTransitionRenderState (
284  geometry::AffineMatrix2D(1, 0, aTransitionPreviewBox.X, 0, 1, aTransitionPreviewBox.Y),
285  nullptr,
286  aBackgroundColor,
287  rendering::CompositeOperation::SOURCE);
288  mxCanvas->drawBitmap(xTransitionIcon, aViewState, aTransitionRenderState);
289  }
290  if( bCustomAnimation )
291  {
292  const awt::Rectangle aAnimationPreviewBox(5, aWindowBox.Height-40, 0, 0);
293  SharedBitmapDescriptor aAnimationDescriptor = mpBitmaps->GetBitmap("Animation");
294  Reference<rendering::XBitmap> xAnimationIcon (aAnimationDescriptor->GetNormalBitmap());
295  rendering::RenderState aAnimationRenderState (
296  geometry::AffineMatrix2D(1, 0, aAnimationPreviewBox.X, 0, 1, aAnimationPreviewBox.Y),
297  nullptr,
298  aBackgroundColor,
299  rendering::CompositeOperation::SOURCE);
300  mxCanvas->drawBitmap(xAnimationIcon, aViewState, aAnimationRenderState);
301  }
302  }
303  else
304  {
305  if (mnSlideAspectRatio > 0)
306  {
307  Reference<rendering::XPolyPolygon2D> xPolygon (
308  PresenterGeometryHelper::CreatePolygon(aPreviewBox, mxCanvas->getDevice()));
309  if (xPolygon.is())
310  mxCanvas->fillPolyPolygon(xPolygon, aViewState, aRenderState);
311  }
312  }
313 
314  Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
315  if (xSpriteCanvas.is())
316  xSpriteCanvas->updateScreen(false);
317 }
318 
320 {
321  if (mxPreviewRenderer.is() && mxPreview.is())
322  {
323  const awt::Rectangle aWindowBox (mxWindow->getPosSize());
324  const awt::Size aNewPreviewSize (mxPreviewRenderer->calculatePreviewSize(
326  awt::Size(aWindowBox.Width, aWindowBox.Height)));
327  const geometry::IntegerSize2D aPreviewSize (mxPreview->getSize());
328  if (aNewPreviewSize.Width==aPreviewSize.Width
329  && aNewPreviewSize.Height==aPreviewSize.Height)
330  {
331  // The size of the window may have changed but the preview would
332  // be painted in the same size (but not necessarily at the same
333  // position.)
334  return;
335  }
336  }
338 }
339 
341 {
342  if (PresenterSlidePreviewInterfaceBase::rBHelper.bDisposed || PresenterSlidePreviewInterfaceBase::rBHelper.bInDispose)
343  {
344  throw lang::DisposedException (
345  "PresenterSlidePreview object has already been disposed",
346  static_cast<uno::XWeak*>(this));
347  }
348 }
349 
350 } // end of namespace ::sdext::presenter
351 
352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::shared_ptr< PresenterBitmapContainer > mpBitmaps
std::shared_ptr< PresenterBitmapContainer > mpBitmaps
css::uno::Reference< css::drawing::framework::XResourceId > mxViewId
css::uno::Reference< css::awt::XWindow > mxWindow
css::uno::Reference< css::rendering::XCanvas > mxCanvas
virtual void SAL_CALL disposing() override
static bool HasCustomAnimation(css::uno::Reference< css::drawing::XDrawPage > const &rxPage)
css::uno::Reference< css::rendering::XCanvas > mxCanvas
virtual sal_Bool SAL_CALL isAnchorOnly() override
std::shared_ptr< PresenterBitmapContainer::BitmapDescriptor > SharedBitmapDescriptor
std::mutex m_aMutex
css::uno::Reference< css::drawing::XDrawPage > mxCurrentSlide
The current slide for which a preview is displayed.
virtual void SAL_CALL windowMoved(const css::awt::WindowEvent &rEvent) override
void Resize()
React to a resize of the anchor pane.
virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getCurrentPage() override
virtual void SAL_CALL windowHidden(const css::lang::EventObject &rEvent) override
css::uno::Reference< css::drawing::XSlideRenderer > mxPreviewRenderer
css::uno::Reference< css::rendering::XBitmap > mxPreview
This Image holds the preview of the current slide.
unsigned char sal_Bool
virtual void SAL_CALL setCurrentPage(const css::uno::Reference< css::drawing::XDrawPage > &rxSlide) override
void SetSlide(const css::uno::Reference< css::drawing::XDrawPage > &rxPage)
Set the given slide as the current slide of the called PresenterSlidePreview object.
static css::uno::Reference< css::rendering::XPolyPolygon2D > CreatePolygon(const css::awt::Rectangle &rBox, const css::uno::Reference< css::rendering::XGraphicDevice > &rxDevice)
::rtl::Reference< PresenterController > mpPresenterController
::cppu::WeakComponentImplHelper< css::drawing::framework::XView, css::drawing::XDrawView, css::awt::XPaintListener, css::awt::XWindowListener > PresenterSlidePreviewInterfaceBase
virtual void SAL_CALL windowResized(const css::awt::WindowEvent &rEvent) override
rtl::Reference< PresenterController > mpPresenterController
virtual void SAL_CALL windowPaint(const css::awt::PaintEvent &rEvent) override
virtual void SAL_CALL windowShown(const css::lang::EventObject &rEvent) override
static void SetDeviceColor(css::rendering::RenderState &rRenderState, const css::util::Color aColor)
virtual css::uno::Reference< css::drawing::framework::XResourceId > SAL_CALL getResourceId() override
PresenterSlidePreview(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::drawing::framework::XResourceId > &rxViewId, const css::uno::Reference< css::drawing::framework::XPane > &rxAnchorPane, const ::rtl::Reference< PresenterController > &rpPresenterController)
Reference< XSingleServiceFactory > xFactory
css::uno::Reference< css::awt::XWindow > mxWindow
void Paint(const css::awt::Rectangle &rBoundingBox)
Paint the preview of the current slide centered in the window of the anchor pane. ...
static bool HasTransition(css::uno::Reference< css::drawing::XDrawPage > const &rxPage)