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