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