bump product version to 6.3.0.0.beta1
[LibreOffice.git] / toolkit / source / awt / animatedimagespeer.cxx
blob4d1be4be96e76a130773b82de27ee7e63ac7447d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <toolkit/awt/animatedimagespeer.hxx>
22 #include <toolkit/helper/property.hxx>
24 #include <com/sun/star/awt/XAnimatedImages.hpp>
25 #include <com/sun/star/awt/Size.hpp>
26 #include <com/sun/star/graphic/GraphicProvider.hpp>
27 #include <com/sun/star/graphic/XGraphicProvider.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/graphic/XGraphic.hpp>
30 #include <com/sun/star/awt/ImageScaleMode.hpp>
32 #include <comphelper/namedvaluecollection.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <rtl/ustrbuf.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <tools/urlobj.hxx>
37 #include <vcl/throbber.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/settings.hxx>
41 #include <limits>
42 #include <string_view>
44 namespace toolkit
48 using ::com::sun::star::uno::XComponentContext;
49 using ::com::sun::star::uno::Reference;
50 using ::com::sun::star::uno::XInterface;
51 using ::com::sun::star::uno::UNO_QUERY;
52 using ::com::sun::star::uno::UNO_QUERY_THROW;
53 using ::com::sun::star::uno::Exception;
54 using ::com::sun::star::uno::RuntimeException;
55 using ::com::sun::star::uno::Any;
56 using ::com::sun::star::uno::Sequence;
57 using ::com::sun::star::lang::EventObject;
58 using ::com::sun::star::container::ContainerEvent;
59 using ::com::sun::star::awt::XAnimatedImages;
60 using ::com::sun::star::awt::Size;
61 using ::com::sun::star::graphic::XGraphicProvider;
62 using ::com::sun::star::beans::XPropertySet;
63 using ::com::sun::star::graphic::XGraphic;
65 namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode;
68 //= AnimatedImagesPeer_Data
70 struct CachedImage
72 OUString sImageURL;
73 mutable Reference< XGraphic > xGraphic;
75 CachedImage()
76 :sImageURL()
77 ,xGraphic()
81 explicit CachedImage( OUString const& i_imageURL )
82 :sImageURL( i_imageURL )
83 ,xGraphic()
88 struct AnimatedImagesPeer_Data
90 AnimatedImagesPeer& rAntiImpl;
91 ::std::vector< ::std::vector< CachedImage > > aCachedImageSets;
93 explicit AnimatedImagesPeer_Data( AnimatedImagesPeer& i_antiImpl )
94 :rAntiImpl( i_antiImpl )
95 ,aCachedImageSets()
101 //= helper
103 namespace
106 OUString lcl_getHighContrastURL( OUString const& i_imageURL )
108 INetURLObject aURL( i_imageURL );
109 if ( aURL.GetProtocol() != INetProtocol::PrivSoffice )
111 OSL_VERIFY( aURL.insertName( "sifr", false, 0 ) );
112 return aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
114 // the private: scheme is not considered to be hierarchical by INetURLObject, so manually insert the
115 // segment
116 const sal_Int32 separatorPos = i_imageURL.indexOf( '/' );
117 ENSURE_OR_RETURN( separatorPos != -1, "lcl_getHighContrastURL: unsupported URL scheme - cannot automatically determine HC version!", i_imageURL );
119 OUStringBuffer composer;
120 composer.append( std::u16string_view(i_imageURL).substr(0, separatorPos) );
121 composer.append( "/sifr" );
122 composer.append( std::u16string_view(i_imageURL).substr(separatorPos) );
123 return composer.makeStringAndClear();
127 bool lcl_ensureImage_throw( Reference< XGraphicProvider > const& i_graphicProvider, const bool i_isHighContrast, const CachedImage& i_cachedImage )
129 if ( !i_cachedImage.xGraphic.is() )
131 ::comphelper::NamedValueCollection aMediaProperties;
132 if ( i_isHighContrast )
134 // try (to find) the high-contrast version of the graphic first
135 aMediaProperties.put( "URL", lcl_getHighContrastURL( i_cachedImage.sImageURL ) );
136 i_cachedImage.xGraphic.set( i_graphicProvider->queryGraphic( aMediaProperties.getPropertyValues() ), UNO_QUERY );
138 if ( !i_cachedImage.xGraphic.is() )
140 aMediaProperties.put( "URL", i_cachedImage.sImageURL );
141 i_cachedImage.xGraphic.set( i_graphicProvider->queryGraphic( aMediaProperties.getPropertyValues() ), UNO_QUERY );
144 return i_cachedImage.xGraphic.is();
148 Size lcl_getGraphicSizePixel( Reference< XGraphic > const& i_graphic )
150 Size aSizePixel;
153 if ( i_graphic.is() )
155 const Reference< XPropertySet > xGraphicProps( i_graphic, UNO_QUERY_THROW );
156 OSL_VERIFY( xGraphicProps->getPropertyValue("SizePixel") >>= aSizePixel );
159 catch( const Exception& )
161 DBG_UNHANDLED_EXCEPTION("toolkit");
163 return aSizePixel;
167 void lcl_init( Sequence< OUString > const& i_imageURLs, ::std::vector< CachedImage >& o_images )
169 o_images.resize(0);
170 size_t count = size_t( i_imageURLs.getLength() );
171 o_images.reserve( count );
172 for ( size_t i = 0; i < count; ++i )
174 o_images.emplace_back( i_imageURLs[i] );
179 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data& i_data )
181 VclPtr<Throbber> pThrobber = i_data.rAntiImpl.GetAsDynamic<Throbber>();
182 if ( !pThrobber )
183 return;
187 // collect the image sizes of the different image sets
188 const Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
189 const Reference< XGraphicProvider > xGraphicProvider( css::graphic::GraphicProvider::create(xContext) );
191 const bool isHighContrast = pThrobber->GetSettings().GetStyleSettings().GetHighContrastMode();
193 sal_Int32 nPreferredSet = -1;
194 const size_t nImageSetCount = i_data.aCachedImageSets.size();
195 if ( nImageSetCount < 2 )
197 nPreferredSet = sal_Int32( nImageSetCount ) - 1;
199 else
201 ::std::vector< Size > aImageSizes( nImageSetCount );
202 for ( size_t nImageSet = 0; nImageSet < nImageSetCount; ++nImageSet )
204 ::std::vector< CachedImage > const& rImageSet( i_data.aCachedImageSets[ nImageSet ] );
205 if ( ( rImageSet.empty() )
206 || ( !lcl_ensureImage_throw( xGraphicProvider, isHighContrast, rImageSet[0] ) )
209 aImageSizes[ nImageSet ] = Size( SAL_MAX_INT32, SAL_MAX_INT32 );
211 else
213 aImageSizes[ nImageSet ] = lcl_getGraphicSizePixel( rImageSet[0].xGraphic );
217 // find the set with the smallest difference between window size and image size
218 const ::Size aWindowSizePixel = pThrobber->GetSizePixel();
219 long nMinimalDistance = ::std::numeric_limits< long >::max();
220 for ( ::std::vector< Size >::const_iterator check = aImageSizes.begin();
221 check != aImageSizes.end();
222 ++check
225 if ( ( check->Width > aWindowSizePixel.Width() )
226 || ( check->Height > aWindowSizePixel.Height() )
228 // do not use an image set which doesn't fit into the window
229 continue;
231 const sal_Int64 distance =
232 ( aWindowSizePixel.Width() - check->Width ) * ( aWindowSizePixel.Width() - check->Width )
233 + ( aWindowSizePixel.Height() - check->Height ) * ( aWindowSizePixel.Height() - check->Height );
234 if ( distance < nMinimalDistance )
236 nMinimalDistance = distance;
237 nPreferredSet = check - aImageSizes.begin();
242 // found a set?
243 std::vector< Image > aImages;
244 if ( ( nPreferredSet >= 0 ) && ( size_t( nPreferredSet ) < nImageSetCount ) )
246 // => set the images
247 ::std::vector< CachedImage > const& rImageSet( i_data.aCachedImageSets[ nPreferredSet ] );
248 aImages.resize( rImageSet.size() );
249 sal_Int32 imageIndex = 0;
250 for ( const auto& rCachedImage : rImageSet )
252 lcl_ensureImage_throw( xGraphicProvider, isHighContrast, rCachedImage );
253 aImages[ imageIndex++ ] = Image(rCachedImage.xGraphic);
256 pThrobber->setImageList( aImages );
258 catch( const Exception& )
260 DBG_UNHANDLED_EXCEPTION("toolkit");
265 void lcl_updateImageList_nothrow( AnimatedImagesPeer_Data& i_data, const Reference< XAnimatedImages >& i_images )
269 const sal_Int32 nImageSetCount = i_images->getImageSetCount();
270 i_data.aCachedImageSets.resize(0);
271 for ( sal_Int32 set = 0; set < nImageSetCount; ++set )
273 const Sequence< OUString > aImageURLs( i_images->getImageSet( set ) );
274 ::std::vector< CachedImage > aImages;
275 lcl_init( aImageURLs, aImages );
276 i_data.aCachedImageSets.push_back( aImages );
279 lcl_updateImageList_nothrow( i_data );
281 catch( const Exception& )
283 DBG_UNHANDLED_EXCEPTION("toolkit");
289 //= AnimatedImagesPeer
292 AnimatedImagesPeer::AnimatedImagesPeer()
293 :AnimatedImagesPeer_Base()
294 ,m_xData( new AnimatedImagesPeer_Data( *this ) )
299 AnimatedImagesPeer::~AnimatedImagesPeer()
304 void SAL_CALL AnimatedImagesPeer::startAnimation()
306 SolarMutexGuard aGuard;
307 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
308 if (pThrobber)
309 pThrobber->start();
312 void SAL_CALL AnimatedImagesPeer::stopAnimation()
314 SolarMutexGuard aGuard;
315 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
316 if (pThrobber)
317 pThrobber->stop();
320 sal_Bool SAL_CALL AnimatedImagesPeer::isAnimationRunning()
322 SolarMutexGuard aGuard;
323 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
324 if (pThrobber)
325 return pThrobber->isRunning();
326 return false;
329 void SAL_CALL AnimatedImagesPeer::setProperty( const OUString& i_propertyName, const Any& i_value )
331 SolarMutexGuard aGuard;
333 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
334 if ( pThrobber )
336 VCLXWindow::setProperty( i_propertyName, i_value );
337 return;
340 const sal_uInt16 nPropertyId = GetPropertyId( i_propertyName );
341 switch ( nPropertyId )
343 case BASEPROPERTY_STEP_TIME:
345 sal_Int32 nStepTime( 0 );
346 if ( i_value >>= nStepTime )
347 pThrobber->setStepTime( nStepTime );
348 break;
350 case BASEPROPERTY_AUTO_REPEAT:
352 bool bRepeat( true );
353 if ( i_value >>= bRepeat )
354 pThrobber->setRepeat( bRepeat );
355 break;
358 case BASEPROPERTY_IMAGE_SCALE_MODE:
360 sal_Int16 nScaleMode( ImageScaleMode::ANISOTROPIC );
361 VclPtr<ImageControl> pImageControl = GetAsDynamic< ImageControl >();
362 if ( pImageControl && ( i_value >>= nScaleMode ) )
363 pImageControl->SetScaleMode( nScaleMode );
365 break;
367 default:
368 AnimatedImagesPeer_Base::setProperty( i_propertyName, i_value );
369 break;
374 Any SAL_CALL AnimatedImagesPeer::getProperty( const OUString& i_propertyName )
376 SolarMutexGuard aGuard;
378 Any aReturn;
380 VclPtr<Throbber> pThrobber = GetAsDynamic<Throbber>();
381 if ( !pThrobber )
382 return VCLXWindow::getProperty( i_propertyName );
384 const sal_uInt16 nPropertyId = GetPropertyId( i_propertyName );
385 switch ( nPropertyId )
387 case BASEPROPERTY_STEP_TIME:
388 aReturn <<= pThrobber->getStepTime();
389 break;
391 case BASEPROPERTY_AUTO_REPEAT:
392 aReturn <<= pThrobber->getRepeat();
393 break;
395 case BASEPROPERTY_IMAGE_SCALE_MODE:
397 VclPtr<ImageControl> pImageControl = GetAsDynamic<ImageControl>();
398 aReturn <<= ( pImageControl ? pImageControl->GetScaleMode() : ImageScaleMode::ANISOTROPIC );
400 break;
402 default:
403 aReturn = AnimatedImagesPeer_Base::getProperty( i_propertyName );
404 break;
407 return aReturn;
411 void AnimatedImagesPeer::ProcessWindowEvent( const VclWindowEvent& i_windowEvent )
413 if ( i_windowEvent.GetId() == VclEventId::WindowResize )
415 lcl_updateImageList_nothrow( *m_xData );
418 AnimatedImagesPeer_Base::ProcessWindowEvent( i_windowEvent );
422 void AnimatedImagesPeer::impl_updateImages_nolck( const Reference< XInterface >& i_animatedImages )
424 SolarMutexGuard aGuard;
426 lcl_updateImageList_nothrow( *m_xData, Reference< XAnimatedImages >( i_animatedImages, UNO_QUERY_THROW ) );
430 void SAL_CALL AnimatedImagesPeer::elementInserted( const ContainerEvent& i_event )
432 SolarMutexGuard aGuard;
433 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW );
435 sal_Int32 nPosition(0);
436 OSL_VERIFY( i_event.Accessor >>= nPosition );
437 size_t position = size_t( nPosition );
438 if ( position > m_xData->aCachedImageSets.size() )
440 OSL_ENSURE( false, "AnimatedImagesPeer::elementInserted: illegal accessor/index!" );
441 lcl_updateImageList_nothrow( *m_xData, xAnimatedImages );
444 Sequence< OUString > aImageURLs;
445 OSL_VERIFY( i_event.Element >>= aImageURLs );
446 ::std::vector< CachedImage > aImages;
447 lcl_init( aImageURLs, aImages );
448 m_xData->aCachedImageSets.insert( m_xData->aCachedImageSets.begin() + position, aImages );
449 lcl_updateImageList_nothrow( *m_xData );
453 void SAL_CALL AnimatedImagesPeer::elementRemoved( const ContainerEvent& i_event )
455 SolarMutexGuard aGuard;
456 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW );
458 sal_Int32 nPosition(0);
459 OSL_VERIFY( i_event.Accessor >>= nPosition );
460 size_t position = size_t( nPosition );
461 if ( position >= m_xData->aCachedImageSets.size() )
463 OSL_ENSURE( false, "AnimatedImagesPeer::elementRemoved: illegal accessor/index!" );
464 lcl_updateImageList_nothrow( *m_xData, xAnimatedImages );
467 m_xData->aCachedImageSets.erase( m_xData->aCachedImageSets.begin() + position );
468 lcl_updateImageList_nothrow( *m_xData );
472 void SAL_CALL AnimatedImagesPeer::elementReplaced( const ContainerEvent& i_event )
474 SolarMutexGuard aGuard;
475 Reference< XAnimatedImages > xAnimatedImages( i_event.Source, UNO_QUERY_THROW );
477 sal_Int32 nPosition(0);
478 OSL_VERIFY( i_event.Accessor >>= nPosition );
479 size_t position = size_t( nPosition );
480 if ( position >= m_xData->aCachedImageSets.size() )
482 OSL_ENSURE( false, "AnimatedImagesPeer::elementReplaced: illegal accessor/index!" );
483 lcl_updateImageList_nothrow( *m_xData, xAnimatedImages );
486 Sequence< OUString > aImageURLs;
487 OSL_VERIFY( i_event.Element >>= aImageURLs );
488 ::std::vector< CachedImage > aImages;
489 lcl_init( aImageURLs, aImages );
490 m_xData->aCachedImageSets[ position ] = aImages;
491 lcl_updateImageList_nothrow( *m_xData );
495 void SAL_CALL AnimatedImagesPeer::disposing( const EventObject& i_event )
497 VCLXWindow::disposing( i_event );
501 void SAL_CALL AnimatedImagesPeer::modified( const EventObject& i_event )
503 impl_updateImages_nolck( i_event.Source );
507 void SAL_CALL AnimatedImagesPeer::dispose( )
509 AnimatedImagesPeer_Base::dispose();
510 SolarMutexGuard aGuard;
511 m_xData->aCachedImageSets.resize(0);
515 } // namespace toolkit
518 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */