1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
22 #include <svx/svdomedia.hxx>
24 #include <rtl/ustring.hxx>
25 #include <rtl/ustrbuf.hxx>
26 #include <sal/log.hxx>
28 #include <ucbhelper/content.hxx>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/storagehelper.hxx>
32 #include <vcl/svapp.hxx>
34 #include <svx/svdmodel.hxx>
35 #include <svx/dialmgr.hxx>
36 #include <svx/strings.hrc>
37 #include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
38 #include <avmedia/mediawindow.hxx>
39 #include <tools/diagnose_ex.h>
41 using namespace ::com::sun::star
;
44 struct SdrMediaObj::Impl
46 ::avmedia::MediaItem m_MediaProperties
;
47 // Note: the temp file is read only, until it is deleted!
48 // It may be shared between multiple documents in case of copy/paste,
49 // hence the shared_ptr.
50 std::shared_ptr
< ::avmedia::MediaTempFile
> m_pTempFile
;
51 uno::Reference
< graphic::XGraphic
> m_xCachedSnapshot
;
52 OUString m_LastFailedPkgURL
;
55 SdrMediaObj::SdrMediaObj(SdrModel
& rSdrModel
)
56 : SdrRectObj(rSdrModel
)
61 SdrMediaObj::SdrMediaObj(
63 const tools::Rectangle
& rRect
)
64 : SdrRectObj(rSdrModel
, rRect
)
69 SdrMediaObj::~SdrMediaObj()
73 bool SdrMediaObj::HasTextEdit() const
78 std::unique_ptr
<sdr::contact::ViewContact
> SdrMediaObj::CreateObjectSpecificViewContact()
80 return std::make_unique
<sdr::contact::ViewContactOfSdrMediaObj
>( *this );
83 void SdrMediaObj::TakeObjInfo( SdrObjTransformInfoRec
& rInfo
) const
85 rInfo
.bMoveAllowed
= true;
86 rInfo
.bResizeFreeAllowed
= true;
87 rInfo
.bResizePropAllowed
= true;
88 rInfo
.bRotateFreeAllowed
= false;
89 rInfo
.bRotate90Allowed
= false;
90 rInfo
.bMirrorFreeAllowed
= false;
91 rInfo
.bMirror45Allowed
= false;
92 rInfo
.bMirror90Allowed
= false;
93 rInfo
.bTransparenceAllowed
= false;
94 rInfo
.bShearAllowed
= false;
95 rInfo
.bEdgeRadiusAllowed
= false;
96 rInfo
.bNoOrthoDesired
= false;
97 rInfo
.bNoContortion
= false;
98 rInfo
.bCanConvToPath
= false;
99 rInfo
.bCanConvToPoly
= false;
100 rInfo
.bCanConvToContour
= false;
101 rInfo
.bCanConvToPathLineToArea
= false;
102 rInfo
.bCanConvToPolyLineToArea
= false;
105 SdrObjKind
SdrMediaObj::GetObjIdentifier() const
110 OUString
SdrMediaObj::TakeObjNameSingul() const
112 OUStringBuffer
sName(SvxResId(STR_ObjNameSingulMEDIA
));
114 OUString
aName(GetName());
116 if (!aName
.isEmpty())
124 return sName
.makeStringAndClear();
127 OUString
SdrMediaObj::TakeObjNamePlural() const
129 return SvxResId(STR_ObjNamePluralMEDIA
);
132 SdrMediaObj
* SdrMediaObj::CloneSdrObject(SdrModel
& rTargetModel
) const
134 return CloneHelper
< SdrMediaObj
>(rTargetModel
);
137 SdrMediaObj
& SdrMediaObj::operator=(const SdrMediaObj
& rObj
)
141 SdrRectObj::operator=( rObj
);
143 m_xImpl
->m_pTempFile
= rObj
.m_xImpl
->m_pTempFile
; // before props
144 setMediaProperties( rObj
.getMediaProperties() );
145 m_xImpl
->m_xCachedSnapshot
= rObj
.m_xImpl
->m_xCachedSnapshot
;
149 uno::Reference
< graphic::XGraphic
> const & SdrMediaObj::getSnapshot() const
151 #if HAVE_FEATURE_AVMEDIA
152 if( !m_xImpl
->m_xCachedSnapshot
.is() )
154 OUString aRealURL
= m_xImpl
->m_MediaProperties
.getTempURL();
155 if( aRealURL
.isEmpty() )
156 aRealURL
= m_xImpl
->m_MediaProperties
.getURL();
157 m_xImpl
->m_xCachedSnapshot
= avmedia::MediaWindow::grabFrame( aRealURL
, m_xImpl
->m_MediaProperties
.getReferer(), m_xImpl
->m_MediaProperties
.getMimeType());
160 return m_xImpl
->m_xCachedSnapshot
;
163 void SdrMediaObj::AdjustToMaxRect( const tools::Rectangle
& rMaxRect
, bool bShrinkOnly
/* = false */ )
165 Size
aSize( Application::GetDefaultDevice()->PixelToLogic(
166 static_cast< sdr::contact::ViewContactOfSdrMediaObj
& >( GetViewContact() ).getPreferredSize(),
167 MapMode(MapUnit::Map100thMM
)) );
168 Size
aMaxSize( rMaxRect
.GetSize() );
170 if( aSize
.IsEmpty() )
173 Point
aPos( rMaxRect
.TopLeft() );
175 // if graphic is too large, fit it to the page
176 if ( (!bShrinkOnly
||
177 ( aSize
.Height() > aMaxSize
.Height() ) ||
178 ( aSize
.Width() > aMaxSize
.Width() ) )&&
179 aSize
.Height() && aMaxSize
.Height() )
181 float fGrfWH
= static_cast<float>(aSize
.Width()) /
182 static_cast<float>(aSize
.Height());
183 float fWinWH
= static_cast<float>(aMaxSize
.Width()) /
184 static_cast<float>(aMaxSize
.Height());
186 // scale graphic to page size
187 if ( fGrfWH
< fWinWH
)
189 aSize
.setWidth( static_cast<tools::Long
>(aMaxSize
.Height() * fGrfWH
) );
190 aSize
.setHeight( aMaxSize
.Height() );
192 else if ( fGrfWH
> 0.F
)
194 aSize
.setWidth( aMaxSize
.Width() );
195 aSize
.setHeight( static_cast<tools::Long
>(aMaxSize
.Width() / fGrfWH
) );
198 aPos
= rMaxRect
.Center();
202 aPos
= maRect
.TopLeft();
204 aPos
.AdjustX( -(aSize
.Width() / 2) );
205 aPos
.AdjustY( -(aSize
.Height() / 2) );
206 SetLogicRect( tools::Rectangle( aPos
, aSize
) );
209 void SdrMediaObj::setURL( const OUString
& rURL
, const OUString
& rReferer
, const OUString
& rMimeType
)
211 ::avmedia::MediaItem aURLItem
;
212 #if HAVE_FEATURE_AVMEDIA
213 if( !rMimeType
.isEmpty() )
214 m_xImpl
->m_MediaProperties
.setMimeType(rMimeType
);
215 aURLItem
.setURL( rURL
, "", rReferer
);
221 setMediaProperties( aURLItem
);
224 const OUString
& SdrMediaObj::getURL() const
226 #if HAVE_FEATURE_AVMEDIA
227 return m_xImpl
->m_MediaProperties
.getURL();
234 void SdrMediaObj::setMediaProperties( const ::avmedia::MediaItem
& rState
)
236 mediaPropertiesChanged( rState
);
237 static_cast< sdr::contact::ViewContactOfSdrMediaObj
& >( GetViewContact() ).executeMediaItem( getMediaProperties() );
240 const ::avmedia::MediaItem
& SdrMediaObj::getMediaProperties() const
242 return m_xImpl
->m_MediaProperties
;
245 uno::Reference
<io::XInputStream
> SdrMediaObj::GetInputStream() const
247 if (!m_xImpl
->m_pTempFile
)
249 SAL_WARN("svx", "this is only intended for embedded media");
252 ucbhelper::Content
tempFile(m_xImpl
->m_pTempFile
->m_TempFileURL
,
253 uno::Reference
<ucb::XCommandEnvironment
>(),
254 comphelper::getProcessComponentContext());
255 return tempFile
.openStream();
258 void SdrMediaObj::SetInputStream(uno::Reference
<io::XInputStream
> const& xStream
)
260 if (m_xImpl
->m_pTempFile
|| m_xImpl
->m_LastFailedPkgURL
.isEmpty())
262 SAL_WARN("svx", "this is only intended for embedded media");
266 OUString tempFileURL
;
268 ::avmedia::CreateMediaTempFile(
275 m_xImpl
->m_pTempFile
= std::make_shared
<::avmedia::MediaTempFile
>(tempFileURL
);
276 #if HAVE_FEATURE_AVMEDIA
277 m_xImpl
->m_MediaProperties
.setURL(
278 m_xImpl
->m_LastFailedPkgURL
, tempFileURL
, "");
281 m_xImpl
->m_LastFailedPkgURL
.clear(); // once only
284 /// copy a stream from XStorage to temp file
285 #if HAVE_FEATURE_AVMEDIA
286 static bool lcl_HandlePackageURL(
287 OUString
const & rURL
,
288 const SdrModel
& rModel
,
289 OUString
& o_rTempFileURL
)
291 ::comphelper::LifecycleProxy sourceProxy
;
292 uno::Reference
<io::XInputStream
> xInStream
;
294 xInStream
= rModel
.GetDocumentStream(rURL
, sourceProxy
);
296 catch (container::NoSuchElementException
const&)
298 SAL_INFO("svx", "not found: '" << rURL
<< "'");
301 catch (uno::Exception
const&)
303 TOOLS_WARN_EXCEPTION("svx", "");
308 SAL_WARN("svx", "no stream?");
311 // Make sure the temporary copy has the same file name extension as the original media file
312 // (like .mp4). That seems to be important for some AVFoundation APIs. For random extension-less
313 // file names, they don't seem to even bother looking inside the file.
314 sal_Int32 nLastDot
= rURL
.lastIndexOf('.');
315 sal_Int32 nLastSlash
= rURL
.lastIndexOf('/');
316 OUString sDesiredExtension
;
317 if (nLastDot
> nLastSlash
&& nLastDot
+1 < rURL
.getLength())
318 sDesiredExtension
= rURL
.copy(nLastDot
);
319 return ::avmedia::CreateMediaTempFile(xInStream
, o_rTempFileURL
, sDesiredExtension
);
323 void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem
& rNewProperties
)
325 bool bBroadcastChanged
= false;
326 #if HAVE_FEATURE_AVMEDIA
327 const AVMediaSetMask nMaskSet
= rNewProperties
.getMaskSet();
329 // use only a subset of MediaItem properties for own properties
330 if( AVMediaSetMask::MIME_TYPE
& nMaskSet
)
331 m_xImpl
->m_MediaProperties
.setMimeType( rNewProperties
.getMimeType() );
333 if( ( AVMediaSetMask::URL
& nMaskSet
) &&
334 ( rNewProperties
.getURL() != getURL() ))
336 m_xImpl
->m_xCachedSnapshot
.clear();
337 OUString
const& url(rNewProperties
.getURL());
338 if (url
.startsWithIgnoreAsciiCase("vnd.sun.star.Package:"))
340 if ( !m_xImpl
->m_pTempFile
341 || (m_xImpl
->m_pTempFile
->m_TempFileURL
!=
342 rNewProperties
.getTempURL()))
344 OUString tempFileURL
;
346 lcl_HandlePackageURL(
348 getSdrModelFromSdrObject(),
353 m_xImpl
->m_pTempFile
=
354 std::make_shared
<::avmedia::MediaTempFile
>(tempFileURL
);
355 m_xImpl
->m_MediaProperties
.setURL(url
, tempFileURL
, "");
357 else // this case is for Clone via operator=
359 m_xImpl
->m_pTempFile
.reset();
360 m_xImpl
->m_MediaProperties
.setURL("", "", "");
361 // UGLY: oox import also gets here, because unlike ODF
362 // getDocumentStorage() is not the imported file...
363 m_xImpl
->m_LastFailedPkgURL
= url
;
368 m_xImpl
->m_MediaProperties
.setURL(url
,
369 rNewProperties
.getTempURL(), "");
374 m_xImpl
->m_pTempFile
.reset();
375 m_xImpl
->m_MediaProperties
.setURL(url
, "", rNewProperties
.getReferer());
377 bBroadcastChanged
= true;
380 if( AVMediaSetMask::LOOP
& nMaskSet
)
381 m_xImpl
->m_MediaProperties
.setLoop( rNewProperties
.isLoop() );
383 if( AVMediaSetMask::MUTE
& nMaskSet
)
384 m_xImpl
->m_MediaProperties
.setMute( rNewProperties
.isMute() );
386 if( AVMediaSetMask::VOLUMEDB
& nMaskSet
)
387 m_xImpl
->m_MediaProperties
.setVolumeDB( rNewProperties
.getVolumeDB() );
389 if( AVMediaSetMask::ZOOM
& nMaskSet
)
390 m_xImpl
->m_MediaProperties
.setZoom( rNewProperties
.getZoom() );
392 (void) rNewProperties
;
395 if( bBroadcastChanged
)
398 BroadcastObjectChange();
402 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */