1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_slideshow.hxx"
26 
27 // must be first
28 #include <canvas/debug.hxx>
29 #include <tools/diagnose_ex.h>
30 #include <canvas/verbosetrace.hxx>
31 
32 #include <math.h>
33 
34 #include <comphelper/anytostring.hxx>
35 #include <cppuhelper/exc_hlp.hxx>
36 
37 #include <vcl/window.hxx>
38 #include <vcl/syschild.hxx>
39 #include <vcl/salbtype.hxx>
40 
41 #include <basegfx/tools/canvastools.hxx>
42 #include <basegfx/numeric/ftools.hxx>
43 #include <basegfx/polygon/b2dpolygon.hxx>
44 #include <basegfx/point/b2dpoint.hxx>
45 #include <basegfx/matrix/b2dhommatrix.hxx>
46 #include <basegfx/polygon/b2dpolygontools.hxx>
47 #include <basegfx/range/b2irange.hxx>
48 #include <canvas/canvastools.hxx>
49 #include <cppcanvas/vclfactory.hxx>
50 #include <cppcanvas/basegfxfactory.hxx>
51 #include <cppcanvas/basegfxfactory.hxx>
52 #include <avmedia/mediawindow.hxx>
53 
54 #include <com/sun/star/media/XManager.hpp>
55 #include <com/sun/star/media/XPlayer.hpp>
56 #include <com/sun/star/media/XPlayerWindow.hpp>
57 #include <com/sun/star/beans/XPropertySet.hpp>
58 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
59 #include <com/sun/star/lang/NoSupportException.hpp>
60 #include <com/sun/star/awt/XWindow.hpp>
61 #include <com/sun/star/rendering/XCanvas.hpp>
62 #include <com/sun/star/lang/XComponent.hdl>
63 
64 #include "viewmediashape.hxx"
65 #include "mediashape.hxx"
66 #include "tools.hxx"
67 #include "unoview.hxx"
68 
69 using namespace ::com::sun::star;
70 
71 namespace slideshow
72 {
73     namespace internal
74     {
ViewMediaShape(const ViewLayerSharedPtr & rViewLayer,const uno::Reference<drawing::XShape> & rxShape,const uno::Reference<uno::XComponentContext> & rxContext)75         ViewMediaShape::ViewMediaShape( const ViewLayerSharedPtr&                       rViewLayer,
76 										const uno::Reference< drawing::XShape >&        rxShape,
77                                         const uno::Reference< uno::XComponentContext >& rxContext ) :
78 			mpViewLayer( rViewLayer ),
79 			mpMediaWindow(),
80 			maWindowOffset( 0, 0 ),
81             maBounds(),
82 			mxShape( rxShape ),
83 			mxPlayer(),
84 			mxPlayerWindow(),
85             mxComponentContext( rxContext ),
86             mbIsSoundEnabled(true)
87         {
88             ENSURE_OR_THROW( mxShape.is(), "ViewMediaShape::ViewMediaShape(): Invalid Shape" );
89             ENSURE_OR_THROW( mpViewLayer, "ViewMediaShape::ViewMediaShape(): Invalid View" );
90             ENSURE_OR_THROW( mpViewLayer->getCanvas(), "ViewMediaShape::ViewMediaShape(): Invalid ViewLayer canvas" );
91             ENSURE_OR_THROW( mxComponentContext.is(), "ViewMediaShape::ViewMediaShape(): Invalid component context" );
92 
93             UnoViewSharedPtr pUnoView (::boost::dynamic_pointer_cast<UnoView>(rViewLayer));
94             if (pUnoView)
95             {
96                 mbIsSoundEnabled = pUnoView->isSoundEnabled();
97             }
98         }
99 
100 		// ---------------------------------------------------------------------
101 
~ViewMediaShape()102 		ViewMediaShape::~ViewMediaShape()
103 		{
104             try
105             {
106                 endMedia();
107             }
108             catch (uno::Exception &)
109             {
110                 OSL_ENSURE( false, rtl::OUStringToOString(
111                                 comphelper::anyToString(
112                                     cppu::getCaughtException() ),
113                                 RTL_TEXTENCODING_UTF8 ).getStr() );
114             }
115 		}
116 
117 		// ---------------------------------------------------------------------
118 
getViewLayer() const119         ViewLayerSharedPtr ViewMediaShape::getViewLayer() const
120         {
121             return mpViewLayer;
122         }
123 
124 		// ---------------------------------------------------------------------
125 
startMedia()126         bool ViewMediaShape::startMedia()
127         {
128             if( !mxPlayer.is() )
129 			    implInitialize( maBounds );
130 
131             if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
132 				mxPlayer->start();
133 
134 			return true;
135         }
136 
137 		// ---------------------------------------------------------------------
138 
endMedia()139         void ViewMediaShape::endMedia()
140         {
141 			// shutdown player window
142 			if( mxPlayerWindow.is() )
143 			{
144 				uno::Reference< lang::XComponent > xComponent( mxPlayerWindow, uno::UNO_QUERY );
145 
146 				if( xComponent.is() )
147 					xComponent->dispose();
148 
149 				mxPlayerWindow.clear();
150 			}
151 
152             mpMediaWindow = ::std::auto_ptr< SystemChildWindow >();
153 
154 			// shutdown player
155 			if( mxPlayer.is() )
156 			{
157 				mxPlayer->stop();
158 
159 				uno::Reference< lang::XComponent > xComponent( mxPlayer, uno::UNO_QUERY );
160 
161 				if( xComponent.is() )
162 					xComponent->dispose();
163 
164 				mxPlayer.clear();
165 			}
166 		}
167 
168 		// ---------------------------------------------------------------------
169 
pauseMedia()170         void ViewMediaShape::pauseMedia()
171         {
172             if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
173 				mxPlayer->stop();
174 		}
175 
176 		// ---------------------------------------------------------------------
177 
setMediaTime(double fTime)178         void ViewMediaShape::setMediaTime(double fTime)
179         {
180             if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
181 				mxPlayer->setMediaTime(fTime);
182         }
183 
184 		// ---------------------------------------------------------------------
185 
render(const::basegfx::B2DRectangle & rBounds) const186         bool ViewMediaShape::render( const ::basegfx::B2DRectangle&	rBounds ) const
187         {
188             ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();;
189 
190             if( !pCanvas )
191                 return false;
192 
193 			if( !mpMediaWindow.get() && !mxPlayerWindow.is() )
194 			{
195                 // fill the shape background with black
196                 fillRect( pCanvas,
197                           rBounds,
198                           0x000000FFU );
199 			}
200 
201             return true;
202         }
203 
resize(const::basegfx::B2DRectangle & rNewBounds) const204         bool ViewMediaShape::resize( const ::basegfx::B2DRectangle&	rNewBounds ) const
205         {
206             maBounds = rNewBounds;
207 
208             ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();;
209 
210             if( !pCanvas )
211                 return false;
212 
213 			if( !mxPlayerWindow.is() )
214                 return true;
215 
216             uno::Reference< beans::XPropertySet > xPropSet( pCanvas->getUNOCanvas()->getDevice(),
217                                                             uno::UNO_QUERY );
218 
219             uno::Reference< awt::XWindow > xParentWindow;
220             if( xPropSet.is() &&
221                 getPropertyValue( xParentWindow,
222                                   xPropSet,
223                                   ::rtl::OUString::createFromAscii( "Window" )) )
224             {
225                 const awt::Rectangle aRect( xParentWindow->getPosSize() );
226 
227                 maWindowOffset.X = aRect.X;
228                 maWindowOffset.Y = aRect.Y;
229             }
230 
231             ::basegfx::B2DRange aTmpRange;
232             ::canvas::tools::calcTransformedRectBounds( aTmpRange,
233                                                         rNewBounds,
234                                                         mpViewLayer->getTransformation() );
235             const ::basegfx::B2IRange& rRangePix(
236                 ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
237 
238             mxPlayerWindow->setEnable( !rRangePix.isEmpty() );
239 
240             if( rRangePix.isEmpty() )
241                 return true;
242 
243             const Point aPosPixel( rRangePix.getMinX() + maWindowOffset.X,
244                                    rRangePix.getMinY() + maWindowOffset.Y );
245             const Size	aSizePixel( rRangePix.getMaxX() - rRangePix.getMinX(),
246                                     rRangePix.getMaxY() - rRangePix.getMinY() );
247 
248             if( mpMediaWindow.get() )
249             {
250                 mpMediaWindow->SetPosSizePixel( aPosPixel, aSizePixel );
251                 mxPlayerWindow->setPosSize( 0, 0,
252                                             aSizePixel.Width(), aSizePixel.Height(),
253                                             0 );
254             }
255             else
256             {
257                 mxPlayerWindow->setPosSize( aPosPixel.X(), aPosPixel.Y(),
258                                             aSizePixel.Width(), aSizePixel.Height(),
259                                             0 );
260             }
261 
262 			return true;
263         }
264 
265 		// ---------------------------------------------------------------------
266 
implInitialize(const::basegfx::B2DRectangle & rBounds)267 		bool ViewMediaShape::implInitialize( const ::basegfx::B2DRectangle& rBounds )
268 		{
269 			if( !mxPlayer.is() && mxShape.is() )
270 			{
271 				ENSURE_OR_RETURN_FALSE( mpViewLayer->getCanvas(),
272                                    "ViewMediaShape::update(): Invalid layer canvas" );
273 
274 				uno::Reference< rendering::XCanvas > xCanvas( mpViewLayer->getCanvas()->getUNOCanvas() );
275 
276 				if( xCanvas.is() )
277 				{
278 					uno::Reference< beans::XPropertySet >	xPropSet;
279 					::rtl::OUString 						aURL;
280 
281 					try
282 					{
283 						xPropSet.set( mxShape, uno::UNO_QUERY );
284 
285 						// create Player
286 						if( xPropSet.is() &&
287 							( xPropSet->getPropertyValue(
288                                   ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaURL" ) ) ) >>=aURL ) )
289 						{
290 							implInitializeMediaPlayer( aURL );
291 						}
292 
293 						// create visible object
294 						uno::Sequence< uno::Any > aDeviceParams;
295 
296 						if( ::canvas::tools::getDeviceInfo( xCanvas, aDeviceParams ).getLength() > 1 )
297 						{
298 							::rtl::OUString aImplName;
299 
300 							aDeviceParams[ 0 ] >>= aImplName;
301 
302 							if( aImplName.endsWithIgnoreAsciiCaseAsciiL(
303                                     RTL_CONSTASCII_STRINGPARAM("VCL") ))
304                             {
305 								implInitializeVCLBasedPlayerWindow( rBounds, aDeviceParams );
306                             }
307 							else if( aImplName.endsWithIgnoreAsciiCaseAsciiL(
308                                          RTL_CONSTASCII_STRINGPARAM("DX")) ||
309 									 aImplName.endsWithIgnoreAsciiCaseAsciiL(
310                                          RTL_CONSTASCII_STRINGPARAM("DX9")))
311                             {
312 								implInitializeDXBasedPlayerWindow( rBounds, aDeviceParams );
313                             }
314 						}
315 
316 						// set player properties
317 						implSetMediaProperties( xPropSet );
318 					}
319                     catch( uno::RuntimeException& )
320                     {
321                         throw;
322                     }
323 					catch( uno::Exception& )
324 					{
325                         OSL_ENSURE( false,
326                                     rtl::OUStringToOString(
327                                         comphelper::anyToString( cppu::getCaughtException() ),
328                                         RTL_TEXTENCODING_UTF8 ).getStr() );
329 					}
330 				}
331 			}
332 
333 			return mxPlayer.is() || mxPlayerWindow.is();
334 	    }
335 
336 		// ---------------------------------------------------------------------
337 
implSetMediaProperties(const uno::Reference<beans::XPropertySet> & rxProps)338 		void ViewMediaShape::implSetMediaProperties( const uno::Reference< beans::XPropertySet >& rxProps )
339 		{
340 			if( mxPlayer.is() )
341 			{
342 				mxPlayer->setMediaTime( 0.0 );
343 
344                 if( rxProps.is() )
345                 {
346 					sal_Bool bLoop( false );
347 					getPropertyValue( bLoop,
348                                       rxProps,
349                                       ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Loop" )));
350 					mxPlayer->setPlaybackLoop( bLoop );
351 
352 					sal_Bool bMute( false );
353 					getPropertyValue( bMute,
354                                       rxProps,
355                                       ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Mute" )));
356 					mxPlayer->setMute( bMute || !mbIsSoundEnabled);
357 
358 					sal_Int16 nVolumeDB(0);
359 					getPropertyValue( nVolumeDB,
360                                       rxProps,
361                                       ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VolumeDB" )));
362 					mxPlayer->setVolumeDB( nVolumeDB );
363 
364                     if( mxPlayerWindow.is() )
365                     {
366 						media::ZoomLevel eZoom(media::ZoomLevel_FIT_TO_WINDOW);
367 						getPropertyValue( eZoom,
368                                           rxProps,
369                                           ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Zoom" )));
370 						mxPlayerWindow->setZoomLevel( eZoom );
371 					}
372 				}
373 			}
374 		}
375 
376 		// ---------------------------------------------------------------------
377 
implInitializeMediaPlayer(const::rtl::OUString & rMediaURL)378 		void ViewMediaShape::implInitializeMediaPlayer( const ::rtl::OUString& rMediaURL )
379 		{
380 			if( !mxPlayer.is() )
381 			{
382 				try
383 				{
384 					if( rMediaURL.getLength() )
385 					{
386 						mxPlayer.set( avmedia::MediaWindow::createPlayer( rMediaURL ),
387                             uno::UNO_QUERY );
388 					}
389 				}
390                 catch( uno::RuntimeException& )
391                 {
392                     throw;
393                 }
394 				catch( const uno::Exception& )
395 				{
396                     throw lang::NoSupportException(
397                         rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
398                                            "No video support for ") ) + rMediaURL,
399                         uno::Reference<uno::XInterface>() );
400 				}
401 			}
402 		}
403 
404 		// ---------------------------------------------------------------------
405 
implInitializeVCLBasedPlayerWindow(const::basegfx::B2DRectangle & rBounds,const uno::Sequence<uno::Any> & rVCLDeviceParams)406 		bool ViewMediaShape::implInitializeVCLBasedPlayerWindow( const ::basegfx::B2DRectangle&   rBounds,
407 																 const uno::Sequence< uno::Any >& rVCLDeviceParams)
408 		{
409 			if( !mpMediaWindow.get() && !rBounds.isEmpty() )
410 			{
411 				try
412 				{
413 					sal_Int64 aVal=0;
414 
415 					rVCLDeviceParams[ 1 ] >>= aVal;
416 
417 					Window* pWindow = reinterpret_cast< Window* >( aVal );
418 
419 					if( pWindow )
420 					{
421 						::basegfx::B2DRange aTmpRange;
422 						::canvas::tools::calcTransformedRectBounds( aTmpRange,
423                                                                     rBounds,
424 																	mpViewLayer->getTransformation() );
425                         const ::basegfx::B2IRange& rRangePix(
426                             ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
427 
428 						if( !rRangePix.isEmpty() )
429 						{
430 							uno::Sequence< uno::Any > 	aArgs( 3 );
431 							awt::Rectangle				aAWTRect( rRangePix.getMinX(),
432 																  rRangePix.getMinY(),
433 														  		  rRangePix.getMaxX() - rRangePix.getMinX(),
434 														  		  rRangePix.getMaxY() - rRangePix.getMinY() );
435 
436 							mpMediaWindow = ::std::auto_ptr< SystemChildWindow >( new
437                                                 SystemChildWindow( pWindow, WB_CLIPCHILDREN ) );
438 							mpMediaWindow->SetBackground( Color( COL_BLACK ) );
439 							mpMediaWindow->SetPosSizePixel( Point( aAWTRect.X, aAWTRect.Y ),
440                                                            Size( aAWTRect.Width, aAWTRect.Height ) );
441 							mpMediaWindow->Show();
442 
443 							if( mxPlayer.is() )
444 							{
445 								aArgs[ 0 ] = uno::makeAny(
446                                     sal::static_int_cast< sal_IntPtr >( mpMediaWindow->GetParentWindowHandle() ) );
447 
448 								aAWTRect.X = aAWTRect.Y = 0;
449 								aArgs[ 1 ] = uno::makeAny( aAWTRect );
450 
451                                 aArgs[ 2 ] = uno::makeAny( reinterpret_cast< sal_IntPtr >( mpMediaWindow.get() ) );
452 
453 								mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
454 
455 								if( mxPlayerWindow.is() )
456 								{
457 									mxPlayerWindow->setVisible( true );
458 									mxPlayerWindow->setEnable( true );
459 								}
460 							}
461 						}
462 					}
463 				}
464                 catch( uno::RuntimeException& )
465                 {
466                     throw;
467                 }
468 				catch( uno::Exception& )
469 				{
470                     OSL_ENSURE( false,
471                                 rtl::OUStringToOString(
472                                     comphelper::anyToString( cppu::getCaughtException() ),
473                                     RTL_TEXTENCODING_UTF8 ).getStr() );
474 				}
475 			}
476 
477 			return mxPlayerWindow.is();
478 		}
479 
480 		// ---------------------------------------------------------------------
481 
implInitializeDXBasedPlayerWindow(const::basegfx::B2DRectangle & rBounds,const uno::Sequence<uno::Any> & rDXDeviceParams)482 		bool ViewMediaShape::implInitializeDXBasedPlayerWindow( const ::basegfx::B2DRectangle&   rBounds,
483 																const uno::Sequence< uno::Any >& rDXDeviceParams )
484 		{
485             if( !mxPlayerWindow.is() )
486 	    	{
487         		try
488 		        {
489 				    if( rDXDeviceParams.getLength() == 2 )
490 				    {
491 					    sal_Int64 aWNDVal=0;
492 
493 					    rDXDeviceParams[ 1 ] >>= aWNDVal;
494 
495 					    if( aWNDVal )
496 					    {
497 						    ::basegfx::B2DRange aTmpRange;
498 						    ::canvas::tools::calcTransformedRectBounds( aTmpRange,
499                                                                         rBounds,
500 																	    mpViewLayer->getTransformation() );
501                             const ::basegfx::B2IRange& rRangePix(
502                                 ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
503 
504 						    if( !rRangePix.isEmpty() )
505 						    {
506 							    uno::Sequence< uno::Any > 	aArgs( 2 );
507 							    awt::Rectangle				aAWTRect( rRangePix.getMinX() + maWindowOffset.X,
508                                                                       rRangePix.getMinY() + maWindowOffset.Y,
509                                                                       rRangePix.getMaxX() - rRangePix.getMinX(),
510                                                                       rRangePix.getMaxY() - rRangePix.getMinY() );
511 
512 							    if( mxPlayer.is() )
513 							    {
514 								    aArgs[ 0 ] = uno::makeAny( sal::static_int_cast< sal_Int32 >( aWNDVal) );
515 								    aArgs[ 1 ] = uno::makeAny( aAWTRect );
516 
517 								    mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
518 							    }
519 						    }
520 					    }
521 				    }
522     			}
523                 catch( uno::RuntimeException& )
524                 {
525                     throw;
526                 }
527 	    	    catch( uno::Exception& )
528 		        {
529                     OSL_ENSURE( false,
530                                 rtl::OUStringToOString(
531                                     comphelper::anyToString( cppu::getCaughtException() ),
532                                     RTL_TEXTENCODING_UTF8 ).getStr() );
533 		        }
534 		    }
535 
536 			return mxPlayerWindow.is();
537 		}
538 	}
539 }
540