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_embeddedobj.hxx" 30 #include <com/sun/star/lang/DisposedException.hpp> 31 #include <com/sun/star/embed/EmbedStates.hpp> 32 #include <com/sun/star/embed/EmbedMapUnits.hpp> 33 #include <com/sun/star/embed/EmbedMisc.hpp> 34 #include <com/sun/star/embed/Aspects.hpp> 35 #include <com/sun/star/io/XSeekable.hpp> 36 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp> 37 38 #include <rtl/logfile.hxx> 39 40 #include <oleembobj.hxx> 41 #include <olecomponent.hxx> 42 #include <comphelper/mimeconfighelper.hxx> 43 #include <comphelper/seqstream.hxx> 44 45 using namespace ::com::sun::star; 46 using namespace ::comphelper; 47 48 embed::VisualRepresentation OleEmbeddedObject::GetVisualRepresentationInNativeFormat_Impl( 49 const uno::Reference< io::XStream > xCachedVisRepr ) 50 throw ( uno::Exception ) 51 { 52 embed::VisualRepresentation aVisualRepr; 53 54 // TODO: detect the format in the future for now use workaround 55 uno::Reference< io::XInputStream > xInStream = xCachedVisRepr->getInputStream(); 56 uno::Reference< io::XSeekable > xSeekable( xCachedVisRepr, uno::UNO_QUERY ); 57 if ( !xInStream.is() || !xSeekable.is() ) 58 throw uno::RuntimeException(); 59 60 uno::Sequence< sal_Int8 > aSeq( 2 ); 61 xInStream->readBytes( aSeq, 2 ); 62 xSeekable->seek( 0 ); 63 if ( aSeq.getLength() == 2 && aSeq[0] == 'B' && aSeq[1] == 'M' ) 64 { 65 // it's a bitmap 66 aVisualRepr.Flavor = datatransfer::DataFlavor( 67 ::rtl::OUString::createFromAscii( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ), 68 ::rtl::OUString::createFromAscii( "Bitmap" ), 69 ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); 70 } 71 else 72 { 73 // it's a metafile 74 aVisualRepr.Flavor = datatransfer::DataFlavor( 75 ::rtl::OUString::createFromAscii( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ), 76 ::rtl::OUString::createFromAscii( "Windows Metafile" ), 77 ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); 78 } 79 80 sal_Int32 nStreamLength = (sal_Int32)xSeekable->getLength(); 81 uno::Sequence< sal_Int8 > aRepresent( nStreamLength ); 82 xInStream->readBytes( aRepresent, nStreamLength ); 83 aVisualRepr.Data <<= aRepresent; 84 85 return aVisualRepr; 86 } 87 88 void SAL_CALL OleEmbeddedObject::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize ) 89 throw ( lang::IllegalArgumentException, 90 embed::WrongStateException, 91 uno::Exception, 92 uno::RuntimeException ) 93 { 94 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::setVisualAreaSize" ); 95 96 // begin wrapping related part ==================== 97 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; 98 if ( xWrappedObject.is() ) 99 { 100 // the object was converted to OOo embedded object, the current implementation is now only a wrapper 101 xWrappedObject->setVisualAreaSize( nAspect, aSize ); 102 return; 103 } 104 // end wrapping related part ==================== 105 106 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 107 if ( m_bDisposed ) 108 throw lang::DisposedException(); // TODO 109 110 OSL_ENSURE( nAspect != embed::Aspects::MSOLE_ICON, "For iconified objects no graphical replacement is required!\n" ); 111 if ( nAspect == embed::Aspects::MSOLE_ICON ) 112 // no representation can be retrieved 113 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ), 114 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 115 116 if ( m_nObjectState == -1 ) 117 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object is not loaded!\n" ), 118 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 119 120 #ifdef WNT 121 // RECOMPOSE_ON_RESIZE misc flag means that the object has to be switched to running state on resize. 122 // SetExtent() is called only for objects that require it, 123 // it should not be called for MSWord documents to workaround problem i49369 124 // If cached size is not set, that means that this is the size initialization, so there is no need to set the real size 125 sal_Bool bAllowToSetExtent = 126 ( ( getStatus( nAspect ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE ) 127 && !MimeConfigurationHelper::ClassIDsEqual( m_aClassID, MimeConfigurationHelper::GetSequenceClassID( 0x00020906L, 0x0000, 0x0000, 128 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 ) ) 129 && m_bHasCachedSize ); 130 131 if ( m_nObjectState == embed::EmbedStates::LOADED && bAllowToSetExtent ) 132 { 133 aGuard.clear(); 134 try { 135 changeState( embed::EmbedStates::RUNNING ); 136 } 137 catch( uno::Exception& ) 138 { 139 OSL_ENSURE( sal_False, "The object should not be resized without activation!\n" ); 140 } 141 aGuard.reset(); 142 } 143 144 if ( m_pOleComponent && m_nObjectState != embed::EmbedStates::LOADED && bAllowToSetExtent ) 145 { 146 awt::Size aSizeToSet = aSize; 147 aGuard.clear(); 148 try { 149 m_pOleComponent->SetExtent( aSizeToSet, nAspect ); // will throw an exception in case of failure 150 m_bHasSizeToSet = sal_False; 151 } 152 catch( uno::Exception& ) 153 { 154 // some objects do not allow to set the size even in running state 155 m_bHasSizeToSet = sal_True; 156 m_aSizeToSet = aSizeToSet; 157 m_nAspectToSet = nAspect; 158 } 159 aGuard.reset(); 160 } 161 #endif 162 163 // cache the values 164 m_bHasCachedSize = sal_True; 165 m_aCachedSize = aSize; 166 m_nCachedAspect = nAspect; 167 } 168 169 awt::Size SAL_CALL OleEmbeddedObject::getVisualAreaSize( sal_Int64 nAspect ) 170 throw ( lang::IllegalArgumentException, 171 embed::WrongStateException, 172 uno::Exception, 173 uno::RuntimeException ) 174 { 175 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getVisualAreaSize" ); 176 177 // begin wrapping related part ==================== 178 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; 179 if ( xWrappedObject.is() ) 180 { 181 // the object was converted to OOo embedded object, the current implementation is now only a wrapper 182 return xWrappedObject->getVisualAreaSize( nAspect ); 183 } 184 // end wrapping related part ==================== 185 186 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 187 if ( m_bDisposed ) 188 throw lang::DisposedException(); // TODO 189 190 OSL_ENSURE( nAspect != embed::Aspects::MSOLE_ICON, "For iconified objects no graphical replacement is required!\n" ); 191 if ( nAspect == embed::Aspects::MSOLE_ICON ) 192 // no representation can be retrieved 193 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ), 194 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 195 196 if ( m_nObjectState == -1 ) 197 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object is not loaded!\n" ), 198 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 199 200 awt::Size aResult; 201 202 #ifdef WNT 203 // TODO/LATER: Support different aspects 204 if ( m_pOleComponent && !m_bHasSizeToSet && nAspect == embed::Aspects::MSOLE_CONTENT ) 205 { 206 try 207 { 208 // the cached size updated every time the object is stored 209 if ( m_bHasCachedSize ) 210 { 211 aResult = m_aCachedSize; 212 } 213 else 214 { 215 // there is no internal cache 216 awt::Size aSize; 217 aGuard.clear(); 218 219 sal_Bool bSuccess = sal_False; 220 if ( getCurrentState() == embed::EmbedStates::LOADED ) 221 { 222 OSL_ENSURE( sal_False, "Loaded object has no cached size!\n" ); 223 224 // try to switch the object to RUNNING state and request the value again 225 try { 226 changeState( embed::EmbedStates::RUNNING ); 227 } 228 catch( uno::Exception ) 229 { 230 throw embed::NoVisualAreaSizeException( 231 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No size available!\n" ) ), 232 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 233 } 234 } 235 236 try 237 { 238 // first try to get size using replacement image 239 aSize = m_pOleComponent->GetExtent( nAspect ); // will throw an exception in case of failure 240 bSuccess = sal_True; 241 } 242 catch( uno::Exception& ) 243 { 244 } 245 246 if ( !bSuccess ) 247 { 248 try 249 { 250 // second try the cached replacement image 251 aSize = m_pOleComponent->GetCachedExtent( nAspect ); // will throw an exception in case of failure 252 bSuccess = sal_True; 253 } 254 catch( uno::Exception& ) 255 { 256 } 257 } 258 259 if ( !bSuccess ) 260 { 261 try 262 { 263 // third try the size reported by the object 264 aSize = m_pOleComponent->GetReccomendedExtent( nAspect ); // will throw an exception in case of failure 265 bSuccess = sal_True; 266 } 267 catch( uno::Exception& ) 268 { 269 } 270 } 271 272 if ( !bSuccess ) 273 throw embed::NoVisualAreaSizeException( 274 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No size available!\n" ) ), 275 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 276 277 aGuard.reset(); 278 279 m_aCachedSize = aSize; 280 m_nCachedAspect = nAspect; 281 m_bHasCachedSize = sal_True; 282 283 aResult = m_aCachedSize; 284 } 285 } 286 catch ( embed::NoVisualAreaSizeException& ) 287 { 288 throw; 289 } 290 catch ( uno::Exception& ) 291 { 292 throw embed::NoVisualAreaSizeException( 293 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No size available!\n" ) ), 294 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 295 } 296 } 297 else 298 #endif 299 { 300 // return cached value 301 if ( m_bHasCachedSize ) 302 { 303 OSL_ENSURE( nAspect == m_nCachedAspect, "Unexpected aspect is requested!\n" ); 304 aResult = m_aCachedSize; 305 } 306 else 307 { 308 throw embed::NoVisualAreaSizeException( 309 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No size available!\n" ) ), 310 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 311 } 312 } 313 314 return aResult; 315 } 316 317 embed::VisualRepresentation SAL_CALL OleEmbeddedObject::getPreferredVisualRepresentation( sal_Int64 nAspect ) 318 throw ( lang::IllegalArgumentException, 319 embed::WrongStateException, 320 uno::Exception, 321 uno::RuntimeException ) 322 { 323 RTL_LOGFILE_CONTEXT( aLog, "embeddedobj (mv76033) OleEmbeddedObject::getPreferredVisualRepresentation" ); 324 325 // begin wrapping related part ==================== 326 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; 327 if ( xWrappedObject.is() ) 328 { 329 // the object was converted to OOo embedded object, the current implementation is now only a wrapper 330 return xWrappedObject->getPreferredVisualRepresentation( nAspect ); 331 } 332 // end wrapping related part ==================== 333 334 ::osl::MutexGuard aGuard( m_aMutex ); 335 if ( m_bDisposed ) 336 throw lang::DisposedException(); // TODO 337 338 OSL_ENSURE( nAspect != embed::Aspects::MSOLE_ICON, "For iconified objects no graphical replacement is required!\n" ); 339 if ( nAspect == embed::Aspects::MSOLE_ICON ) 340 // no representation can be retrieved 341 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ), 342 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 343 344 // TODO: if the object has cached representation then it should be returned 345 // TODO: if the object has no cached representation and is in loaded state it should switch itself to the running state 346 if ( m_nObjectState == -1 ) 347 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object is not loaded!\n" ), 348 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 349 350 embed::VisualRepresentation aVisualRepr; 351 352 // TODO: in case of different aspects they must be applied to the mediatype and XTransferable must be used 353 // the cache is used only as a fallback if object is not in loaded state 354 if ( !m_xCachedVisualRepresentation.is() && ( !m_bVisReplInitialized || m_bVisReplInStream ) 355 && m_nObjectState == embed::EmbedStates::LOADED ) 356 { 357 m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream, sal_True ); 358 SetVisReplInStream( m_xCachedVisualRepresentation.is() ); 359 } 360 361 if ( m_xCachedVisualRepresentation.is() ) 362 { 363 return GetVisualRepresentationInNativeFormat_Impl( m_xCachedVisualRepresentation ); 364 } 365 #ifdef WNT 366 else if ( m_pOleComponent ) 367 { 368 try 369 { 370 if ( m_nObjectState == embed::EmbedStates::LOADED ) 371 changeState( embed::EmbedStates::RUNNING ); 372 373 datatransfer::DataFlavor aDataFlavor( 374 ::rtl::OUString::createFromAscii( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" ), 375 ::rtl::OUString::createFromAscii( "Windows Metafile" ), 376 ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); 377 378 aVisualRepr.Data = m_pOleComponent->getTransferData( aDataFlavor ); 379 aVisualRepr.Flavor = aDataFlavor; 380 381 uno::Sequence< sal_Int8 > aVisReplSeq; 382 aVisualRepr.Data >>= aVisReplSeq; 383 if ( aVisReplSeq.getLength() ) 384 { 385 m_xCachedVisualRepresentation = GetNewFilledTempStream_Impl( 386 uno::Reference< io::XInputStream > ( static_cast< io::XInputStream* > ( 387 new ::comphelper::SequenceInputStream( aVisReplSeq ) ) ) ); 388 } 389 390 return aVisualRepr; 391 } 392 catch( uno::Exception& ) 393 {} 394 } 395 #endif 396 397 // the cache is used only as a fallback if object is not in loaded state 398 if ( !m_xCachedVisualRepresentation.is() && ( !m_bVisReplInitialized || m_bVisReplInStream ) ) 399 { 400 m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream ); 401 SetVisReplInStream( m_xCachedVisualRepresentation.is() ); 402 } 403 404 if ( !m_xCachedVisualRepresentation.is() ) 405 { 406 // no representation can be retrieved 407 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ), 408 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 409 } 410 411 return GetVisualRepresentationInNativeFormat_Impl( m_xCachedVisualRepresentation ); 412 } 413 414 sal_Int32 SAL_CALL OleEmbeddedObject::getMapUnit( sal_Int64 nAspect ) 415 throw ( uno::Exception, 416 uno::RuntimeException) 417 { 418 // begin wrapping related part ==================== 419 uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; 420 if ( xWrappedObject.is() ) 421 { 422 // the object was converted to OOo embedded object, the current implementation is now only a wrapper 423 return xWrappedObject->getMapUnit( nAspect ); 424 } 425 // end wrapping related part ==================== 426 427 ::osl::MutexGuard aGuard( m_aMutex ); 428 if ( m_bDisposed ) 429 throw lang::DisposedException(); // TODO 430 431 OSL_ENSURE( nAspect != embed::Aspects::MSOLE_ICON, "For iconified objects no graphical replacement is required!\n" ); 432 if ( nAspect == embed::Aspects::MSOLE_ICON ) 433 // no representation can be retrieved 434 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "Illegal call!\n" ), 435 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 436 437 if ( m_nObjectState == -1 ) 438 throw embed::WrongStateException( ::rtl::OUString::createFromAscii( "The object is not loaded!\n" ), 439 uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) ); 440 441 return embed::EmbedMapUnits::ONE_100TH_MM; 442 } 443 444 445