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