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