xref: /trunk/main/embeddedobj/source/msole/olevisual.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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