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