/src/libreoffice/embeddedobj/source/msole/olevisual.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <com/sun/star/lang/DisposedException.hpp> |
21 | | #include <com/sun/star/embed/EmbedStates.hpp> |
22 | | #include <com/sun/star/embed/EmbedMapUnits.hpp> |
23 | | #include <com/sun/star/embed/EmbedMisc.hpp> |
24 | | #include <com/sun/star/embed/Aspects.hpp> |
25 | | #include <com/sun/star/embed/WrongStateException.hpp> |
26 | | #include <com/sun/star/io/XSeekable.hpp> |
27 | | #include <com/sun/star/embed/NoVisualAreaSizeException.hpp> |
28 | | |
29 | | #include <oleembobj.hxx> |
30 | | #if defined (_WIN32) |
31 | | #include <comphelper/mimeconfighelper.hxx> |
32 | | #endif |
33 | | #include <comphelper/seqstream.hxx> |
34 | | #include <filter/msfilter/classids.hxx> |
35 | | #include <sal/log.hxx> |
36 | | |
37 | | #if defined(_WIN32) |
38 | | #include "olecomponent.hxx" |
39 | | #include <comphelper/diagnose_ex.hxx> |
40 | | #endif |
41 | | |
42 | | using namespace ::com::sun::star; |
43 | | using namespace ::comphelper; |
44 | | |
45 | | embed::VisualRepresentation OleEmbeddedObject::GetVisualRepresentationInNativeFormat_Impl( |
46 | | const uno::Reference< io::XStream >& xCachedVisRepr ) |
47 | 0 | { |
48 | 0 | embed::VisualRepresentation aVisualRepr; |
49 | | |
50 | | // TODO: detect the format in the future for now use workaround |
51 | 0 | uno::Reference< io::XInputStream > xInStream = xCachedVisRepr->getInputStream(); |
52 | 0 | if ( !xInStream.is() ) |
53 | 0 | throw uno::RuntimeException( |
54 | 0 | u"Failed to retrieve input stream from cached visual representation. "_ustr |
55 | 0 | ); |
56 | 0 | uno::Reference< io::XSeekable > xSeekable( xCachedVisRepr, uno::UNO_QUERY_THROW ); |
57 | |
|
58 | 0 | uno::Sequence< sal_Int8 > aSeq( 2 ); |
59 | 0 | xInStream->readBytes( aSeq, 2 ); |
60 | 0 | xSeekable->seek( 0 ); |
61 | 0 | if ( aSeq.getLength() == 2 && aSeq[0] == 'B' && aSeq[1] == 'M' ) |
62 | 0 | { |
63 | | // it's a bitmap |
64 | 0 | aVisualRepr.Flavor = datatransfer::DataFlavor( |
65 | 0 | u"application/x-openoffice-bitmap;windows_formatname=\"Bitmap\""_ustr, |
66 | 0 | u"Bitmap"_ustr, |
67 | 0 | cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); |
68 | 0 | } |
69 | 0 | else |
70 | 0 | { |
71 | | // it's a metafile |
72 | 0 | aVisualRepr.Flavor = datatransfer::DataFlavor( |
73 | 0 | u"application/x-openoffice-wmf;windows_formatname=\"Image WMF\""_ustr, |
74 | 0 | u"Windows Metafile"_ustr, |
75 | 0 | cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); |
76 | 0 | } |
77 | |
|
78 | 0 | sal_Int32 nStreamLength = static_cast<sal_Int32>(xSeekable->getLength()); |
79 | 0 | uno::Sequence< sal_Int8 > aRepresent( nStreamLength ); |
80 | 0 | xInStream->readBytes( aRepresent, nStreamLength ); |
81 | 0 | aVisualRepr.Data <<= aRepresent; |
82 | |
|
83 | 0 | return aVisualRepr; |
84 | 0 | } |
85 | | |
86 | | void SAL_CALL OleEmbeddedObject::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize ) |
87 | 0 | { |
88 | | // begin wrapping related part ==================== |
89 | 0 | uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
90 | 0 | if ( xWrappedObject.is() ) |
91 | 0 | { |
92 | | // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
93 | 0 | xWrappedObject->setVisualAreaSize( nAspect, aSize ); |
94 | 0 | return; |
95 | 0 | } |
96 | | // end wrapping related part ==================== |
97 | | |
98 | 0 | ::osl::ResettableMutexGuard aGuard( m_aMutex ); |
99 | 0 | if ( m_bDisposed ) |
100 | 0 | throw lang::DisposedException(); // TODO |
101 | | |
102 | 0 | SAL_WARN_IF( nAspect == embed::Aspects::MSOLE_ICON, "embeddedobj.ole", "For iconified objects no graphical replacement is required!" ); |
103 | 0 | if ( nAspect == embed::Aspects::MSOLE_ICON ) |
104 | | // no representation can be retrieved |
105 | 0 | throw embed::WrongStateException( u"Illegal call!"_ustr, |
106 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
107 | | |
108 | 0 | if ( m_nObjectState == -1 ) |
109 | 0 | throw embed::WrongStateException( u"The object is not loaded!"_ustr, |
110 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
111 | | |
112 | | #ifdef _WIN32 |
113 | | // RECOMPOSE_ON_RESIZE misc flag means that the object has to be switched to running state on resize. |
114 | | // SetExtent() is called only for objects that require it, |
115 | | // it should not be called for MSWord documents to workaround problem i49369 |
116 | | // If cached size is not set, that means that this is the size initialization, so there is no need to set the real size |
117 | | bool bAllowToSetExtent = |
118 | | ( ( getStatus( nAspect ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE ) |
119 | | && !MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(MSO_WW8_CLASSID)) |
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( const uno::Exception& ) |
129 | | { |
130 | | SAL_WARN( "embeddedobj.ole", "The object should not be resized without activation!" ); |
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 = false; |
142 | | } |
143 | | catch( const uno::Exception& ) |
144 | | { |
145 | | // some objects do not allow to set the size even in running state |
146 | | m_bHasSizeToSet = true; |
147 | | m_aSizeToSet = aSizeToSet; |
148 | | m_nAspectToSet = nAspect; |
149 | | } |
150 | | aGuard.reset(); |
151 | | } |
152 | | #endif |
153 | | |
154 | | // cache the values |
155 | 0 | m_bHasCachedSize = true; |
156 | 0 | m_aCachedSize = aSize; |
157 | 0 | m_nCachedAspect = nAspect; |
158 | 0 | } |
159 | | |
160 | | awt::Size OleEmbeddedObject::getVisualAreaSize_impl(sal_Int64 nAspect, |
161 | | osl::ResettableMutexGuard& guard) |
162 | 0 | { |
163 | | // begin wrapping related part ==================== |
164 | 0 | uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
165 | 0 | if ( xWrappedObject.is() ) |
166 | 0 | { |
167 | 0 | osl::ResettableMutexGuardScopedReleaser area(guard); |
168 | | // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
169 | 0 | return xWrappedObject->getVisualAreaSize( nAspect ); |
170 | 0 | } |
171 | | // end wrapping related part ==================== |
172 | | |
173 | 0 | if ( m_bDisposed ) |
174 | 0 | throw lang::DisposedException(); // TODO |
175 | | |
176 | 0 | SAL_WARN_IF( nAspect == embed::Aspects::MSOLE_ICON, "embeddedobj.ole", "For iconified objects no graphical replacement is required!" ); |
177 | 0 | if ( nAspect == embed::Aspects::MSOLE_ICON ) |
178 | | // no representation can be retrieved |
179 | 0 | throw embed::WrongStateException( u"Illegal call!"_ustr, |
180 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
181 | | |
182 | 0 | if ( m_nObjectState == -1 ) |
183 | 0 | throw embed::WrongStateException( u"The object is not loaded!"_ustr, |
184 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
185 | | |
186 | 0 | awt::Size aResult; |
187 | |
|
188 | | #ifdef _WIN32 |
189 | | // TODO/LATER: Support different aspects |
190 | | if ( m_pOleComponent && !m_bHasSizeToSet && nAspect == embed::Aspects::MSOLE_CONTENT ) |
191 | | { |
192 | | try |
193 | | { |
194 | | // the cached size updated every time the object is stored |
195 | | if ( m_bHasCachedSize ) |
196 | | { |
197 | | aResult = m_aCachedSize; |
198 | | } |
199 | | else |
200 | | { |
201 | | // there is no internal cache |
202 | | awt::Size aSize; |
203 | | |
204 | | { // => unguarded |
205 | | osl::ResettableMutexGuardScopedReleaser area(guard); |
206 | | |
207 | | bool bBackToLoaded = false; |
208 | | |
209 | | bool bSuccess = false; |
210 | | if ( getCurrentState() == embed::EmbedStates::LOADED ) |
211 | | { |
212 | | SAL_WARN( "embeddedobj.ole", "Loaded object has no cached size!" ); |
213 | | |
214 | | // try to switch the object to RUNNING state and request the value again |
215 | | try { |
216 | | changeState( embed::EmbedStates::RUNNING ); |
217 | | // the links should be switched back to loaded state to avoid too |
218 | | // many open MathType instances |
219 | | bBackToLoaded = true; |
220 | | } |
221 | | catch( const uno::Exception& ) |
222 | | { |
223 | | throw embed::NoVisualAreaSizeException( |
224 | | "No size available!", |
225 | | static_cast< ::cppu::OWeakObject* >(this) ); |
226 | | } |
227 | | } |
228 | | |
229 | | try |
230 | | { |
231 | | // first try to get size using replacement image |
232 | | aSize = m_pOleComponent->GetExtent( nAspect ); // will throw an exception in case of failure |
233 | | bSuccess = true; |
234 | | } |
235 | | catch( const uno::Exception& ) |
236 | | { |
237 | | TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetExtent() failed:"); |
238 | | } |
239 | | |
240 | | if (bBackToLoaded) |
241 | | { |
242 | | try |
243 | | { |
244 | | changeState(embed::EmbedStates::LOADED); |
245 | | } |
246 | | catch( const uno::Exception& ) |
247 | | { |
248 | | TOOLS_WARN_EXCEPTION("embeddedobj.ole", "ignoring "); |
249 | | } |
250 | | } |
251 | | |
252 | | if ( !bSuccess ) |
253 | | { |
254 | | try |
255 | | { |
256 | | // second try the cached replacement image |
257 | | aSize = m_pOleComponent->GetCachedExtent( nAspect ); // will throw an exception in case of failure |
258 | | bSuccess = true; |
259 | | } |
260 | | catch( const uno::Exception& ) |
261 | | { |
262 | | TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetCachedExtent() failed:"); |
263 | | } |
264 | | } |
265 | | |
266 | | if ( !bSuccess ) |
267 | | { |
268 | | try |
269 | | { |
270 | | // third try the size reported by the object |
271 | | aSize = m_pOleComponent->GetRecommendedExtent( nAspect ); // will throw an exception in case of failure |
272 | | bSuccess = true; |
273 | | } |
274 | | catch( const uno::Exception& ) |
275 | | { |
276 | | TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetRecommendedExtent() failed:"); |
277 | | } |
278 | | } |
279 | | |
280 | | if ( !bSuccess ) |
281 | | throw embed::NoVisualAreaSizeException( |
282 | | "No size available!", |
283 | | static_cast< ::cppu::OWeakObject* >(this) ); |
284 | | |
285 | | } // <= unguarded |
286 | | |
287 | | m_aCachedSize = aSize; |
288 | | m_nCachedAspect = nAspect; |
289 | | m_bHasCachedSize = true; |
290 | | |
291 | | aResult = m_aCachedSize; |
292 | | } |
293 | | } |
294 | | catch ( const embed::NoVisualAreaSizeException& ) |
295 | | { |
296 | | throw; |
297 | | } |
298 | | catch ( const uno::Exception& ) |
299 | | { |
300 | | throw embed::NoVisualAreaSizeException( |
301 | | "No size available!", |
302 | | static_cast< ::cppu::OWeakObject* >(this) ); |
303 | | } |
304 | | } |
305 | | else |
306 | | #endif |
307 | 0 | { |
308 | | // return cached value |
309 | 0 | if ( !m_bHasCachedSize ) |
310 | 0 | { |
311 | 0 | throw embed::NoVisualAreaSizeException( |
312 | 0 | u"No size available!"_ustr, |
313 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
314 | 0 | } |
315 | 0 | SAL_WARN_IF( nAspect != m_nCachedAspect, "embeddedobj.ole", "Unexpected aspect is requested!" ); |
316 | 0 | aResult = m_aCachedSize; |
317 | 0 | } |
318 | | |
319 | 0 | return aResult; |
320 | 0 | } |
321 | | |
322 | | awt::Size SAL_CALL OleEmbeddedObject::getVisualAreaSize( sal_Int64 nAspect ) |
323 | 0 | { |
324 | 0 | osl::ResettableMutexGuard aGuard(m_aMutex); |
325 | 0 | return getVisualAreaSize_impl(nAspect, aGuard); |
326 | 0 | } |
327 | | |
328 | | embed::VisualRepresentation SAL_CALL OleEmbeddedObject::getPreferredVisualRepresentation( sal_Int64 nAspect ) |
329 | 0 | { |
330 | | // begin wrapping related part ==================== |
331 | 0 | uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
332 | 0 | if ( xWrappedObject.is() ) |
333 | 0 | { |
334 | | // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
335 | 0 | return xWrappedObject->getPreferredVisualRepresentation( nAspect ); |
336 | 0 | } |
337 | | // end wrapping related part ==================== |
338 | | |
339 | 0 | osl::ResettableMutexGuard aGuard(m_aMutex); |
340 | 0 | if ( m_bDisposed ) |
341 | 0 | throw lang::DisposedException(); // TODO |
342 | | |
343 | 0 | SAL_WARN_IF( nAspect == embed::Aspects::MSOLE_ICON, "embeddedobj.ole", "For iconified objects no graphical replacement is required!" ); |
344 | 0 | if ( nAspect == embed::Aspects::MSOLE_ICON ) |
345 | | // no representation can be retrieved |
346 | 0 | throw embed::WrongStateException( u"Illegal call!"_ustr, |
347 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
348 | | |
349 | | // TODO: if the object has cached representation then it should be returned |
350 | | // TODO: if the object has no cached representation and is in loaded state it should switch itself to the running state |
351 | 0 | if ( m_nObjectState == -1 ) |
352 | 0 | throw embed::WrongStateException( u"The object is not loaded!"_ustr, |
353 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
354 | | |
355 | | // TODO: in case of different aspects they must be applied to the mediatype and XTransferable must be used |
356 | | // the cache is used only as a fallback if object is not in loaded state |
357 | 0 | if ( !m_xCachedVisualRepresentation.is() && ( !m_bVisReplInitialized || m_bVisReplInStream ) |
358 | 0 | && m_nObjectState == embed::EmbedStates::LOADED ) |
359 | 0 | { |
360 | 0 | m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream, aGuard, true ); |
361 | 0 | SetVisReplInStream( m_xCachedVisualRepresentation.is() ); |
362 | 0 | } |
363 | |
|
364 | | #ifdef _WIN32 |
365 | | if ( !m_xCachedVisualRepresentation.is() && m_pOleComponent ) |
366 | | { |
367 | | try |
368 | | { |
369 | | datatransfer::DataFlavor aDataFlavor( |
370 | | "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"", |
371 | | "Windows Metafile", |
372 | | cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); |
373 | | |
374 | | embed::VisualRepresentation aVisualRepr; |
375 | | { |
376 | | osl::ResettableMutexGuardScopedReleaser clearedMutex(aGuard); |
377 | | if ( m_nObjectState == embed::EmbedStates::LOADED ) |
378 | | changeState( embed::EmbedStates::RUNNING ); |
379 | | aVisualRepr.Data = m_pOleComponent->getTransferData(aDataFlavor); |
380 | | } |
381 | | aVisualRepr.Flavor = aDataFlavor; |
382 | | |
383 | | uno::Sequence< sal_Int8 > aVisReplSeq; |
384 | | aVisualRepr.Data >>= aVisReplSeq; |
385 | | if ( aVisReplSeq.getLength() ) |
386 | | { |
387 | | m_xCachedVisualRepresentation = GetNewFilledTempStream_Impl( |
388 | | uno::Reference< io::XInputStream >( |
389 | | new ::comphelper::SequenceInputStream(aVisReplSeq))); |
390 | | } |
391 | | |
392 | | return aVisualRepr; |
393 | | } |
394 | | catch( const uno::Exception& ) |
395 | | {} |
396 | | } |
397 | | #endif |
398 | | |
399 | | // the cache is used only as a fallback if object is not in loaded state |
400 | 0 | if ( !m_xCachedVisualRepresentation.is() && ( !m_bVisReplInitialized || m_bVisReplInStream ) ) |
401 | 0 | { |
402 | 0 | m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream, aGuard ); |
403 | 0 | SetVisReplInStream( m_xCachedVisualRepresentation.is() ); |
404 | 0 | } |
405 | |
|
406 | 0 | if ( !m_xCachedVisualRepresentation.is() ) |
407 | 0 | { |
408 | | // no representation can be retrieved |
409 | 0 | throw embed::WrongStateException( u"Illegal call!"_ustr, |
410 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
411 | 0 | } |
412 | | |
413 | 0 | return GetVisualRepresentationInNativeFormat_Impl( m_xCachedVisualRepresentation ); |
414 | 0 | } |
415 | | |
416 | | sal_Int32 SAL_CALL OleEmbeddedObject::getMapUnit( sal_Int64 nAspect ) |
417 | 0 | { |
418 | | // begin wrapping related part ==================== |
419 | 0 | uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject; |
420 | 0 | if ( xWrappedObject.is() ) |
421 | 0 | { |
422 | | // the object was converted to OOo embedded object, the current implementation is now only a wrapper |
423 | 0 | return xWrappedObject->getMapUnit( nAspect ); |
424 | 0 | } |
425 | | // end wrapping related part ==================== |
426 | | |
427 | 0 | ::osl::MutexGuard aGuard( m_aMutex ); |
428 | 0 | if ( m_bDisposed ) |
429 | 0 | throw lang::DisposedException(); // TODO |
430 | | |
431 | 0 | SAL_WARN_IF( nAspect == embed::Aspects::MSOLE_ICON, "embeddedobj.ole", "For iconified objects no graphical replacement is required!" ); |
432 | 0 | if ( nAspect == embed::Aspects::MSOLE_ICON ) |
433 | | // no representation can be retrieved |
434 | 0 | throw embed::WrongStateException( u"Illegal call!"_ustr, |
435 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
436 | | |
437 | 0 | if ( m_nObjectState == -1 ) |
438 | 0 | throw embed::WrongStateException( u"The object is not loaded!"_ustr, |
439 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
440 | | |
441 | 0 | return embed::EmbedMapUnits::ONE_100TH_MM; |
442 | 0 | } |
443 | | |
444 | | |
445 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |