Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / svdraw / svdomedia.cxx
blob0bb99f1ae46f178145d23f84da0c499aa6f89e01
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */
2 /*
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 <com/sun/star/text/GraphicCrop.hpp>
26 #include <rtl/ustring.hxx>
27 #include <sal/log.hxx>
29 #include <ucbhelper/content.hxx>
30 #include <comphelper/processfactory.hxx>
31 #include <comphelper/storagehelper.hxx>
32 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
33 #include <comphelper/lok.hxx>
34 #include <sfx2/lokhelper.hxx>
35 #include <boost/property_tree/json_parser.hpp>
37 #include <vcl/svapp.hxx>
39 #include <svx/svdmodel.hxx>
40 #include <svx/dialmgr.hxx>
41 #include <svx/strings.hrc>
42 #include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
43 #include <avmedia/mediawindow.hxx>
44 #include <comphelper/diagnose_ex.hxx>
46 using namespace ::com::sun::star;
49 struct SdrMediaObj::Impl
51 ::avmedia::MediaItem m_MediaProperties;
52 #if HAVE_FEATURE_AVMEDIA
53 // Note: the temp file is read only, until it is deleted!
54 // It may be shared between multiple documents in case of copy/paste,
55 // hence the shared_ptr.
56 std::shared_ptr< ::avmedia::MediaTempFile > m_pTempFile;
57 #endif
58 uno::Reference< graphic::XGraphic > m_xCachedSnapshot;
59 rtl::Reference<avmedia::PlayerListener> m_xPlayerListener;
60 OUString m_LastFailedPkgURL;
63 SdrMediaObj::SdrMediaObj(SdrModel& rSdrModel)
64 : SdrRectObj(rSdrModel)
65 ,m_xImpl( new Impl )
69 SdrMediaObj::SdrMediaObj(SdrModel& rSdrModel, SdrMediaObj const & rSource)
70 : SdrRectObj(rSdrModel, rSource)
71 ,m_xImpl( new Impl )
73 #if HAVE_FEATURE_AVMEDIA
74 m_xImpl->m_pTempFile = rSource.m_xImpl->m_pTempFile; // before props
75 #endif
76 setMediaProperties( rSource.getMediaProperties() );
77 m_xImpl->m_xCachedSnapshot = rSource.m_xImpl->m_xCachedSnapshot;
80 SdrMediaObj::SdrMediaObj(
81 SdrModel& rSdrModel,
82 const tools::Rectangle& rRect)
83 : SdrRectObj(rSdrModel, rRect)
84 ,m_xImpl( new Impl )
86 osl_atomic_increment(&m_refCount);
88 const bool bUndo(rSdrModel.IsUndoEnabled());
89 rSdrModel.EnableUndo(false);
90 MakeNameUnique();
91 rSdrModel.EnableUndo(bUndo);
93 osl_atomic_decrement(&m_refCount);
96 SdrMediaObj::~SdrMediaObj()
100 bool SdrMediaObj::HasTextEdit() const
102 return false;
105 std::unique_ptr<sdr::contact::ViewContact> SdrMediaObj::CreateObjectSpecificViewContact()
107 return std::make_unique<sdr::contact::ViewContactOfSdrMediaObj>( *this );
110 void SdrMediaObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
112 rInfo.bMoveAllowed = true;
113 rInfo.bResizeFreeAllowed = true;
114 rInfo.bResizePropAllowed = true;
115 rInfo.bRotateFreeAllowed = false;
116 rInfo.bRotate90Allowed = false;
117 rInfo.bMirrorFreeAllowed = false;
118 rInfo.bMirror45Allowed = false;
119 rInfo.bMirror90Allowed = false;
120 rInfo.bTransparenceAllowed = false;
121 rInfo.bShearAllowed = false;
122 rInfo.bEdgeRadiusAllowed = false;
123 rInfo.bNoOrthoDesired = false;
124 rInfo.bNoContortion = false;
125 rInfo.bCanConvToPath = false;
126 rInfo.bCanConvToPoly = false;
127 rInfo.bCanConvToContour = false;
128 rInfo.bCanConvToPathLineToArea = false;
129 rInfo.bCanConvToPolyLineToArea = false;
132 SdrObjKind SdrMediaObj::GetObjIdentifier() const
134 return SdrObjKind::Media;
137 OUString SdrMediaObj::TakeObjNameSingul() const
139 OUString sName(SvxResId(STR_ObjNameSingulMEDIA));
141 OUString aName(GetName());
143 if (!aName.isEmpty())
144 sName += " '" + aName + "'";
146 return sName;
149 OUString SdrMediaObj::TakeObjNamePlural() const
151 return SvxResId(STR_ObjNamePluralMEDIA);
154 rtl::Reference<SdrObject> SdrMediaObj::CloneSdrObject(SdrModel& rTargetModel) const
156 return new SdrMediaObj(rTargetModel, *this);
159 uno::Reference< graphic::XGraphic > const & SdrMediaObj::getSnapshot() const
161 #if HAVE_FEATURE_AVMEDIA
162 if( !m_xImpl->m_xCachedSnapshot.is() )
164 Graphic aGraphic = m_xImpl->m_MediaProperties.getGraphic();
165 if (!aGraphic.IsNone())
167 Size aPref = aGraphic.GetPrefSize();
168 Size aPixel = aGraphic.GetSizePixel();
169 const text::GraphicCrop& rCrop = m_xImpl->m_MediaProperties.getCrop();
170 if (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0)
172 tools::Long nLeft = aPixel.getWidth() * rCrop.Left / aPref.getWidth();
173 tools::Long nTop = aPixel.getHeight() * rCrop.Top / aPref.getHeight();
174 tools::Long nRight = aPixel.getWidth() * rCrop.Right / aPref.getWidth();
175 tools::Long nBottom = aPixel.getHeight() * rCrop.Bottom / aPref.getHeight();
176 BitmapEx aBitmapEx = aGraphic.GetBitmapEx();
177 aBitmapEx.Crop({nLeft, nTop, aPixel.getWidth() - nRight, aPixel.getHeight() - nBottom});
178 aGraphic = aBitmapEx;
181 // We have an explicit graphic for this media object, then go with that instead of
182 // generating our own one.
183 m_xImpl->m_xCachedSnapshot = aGraphic.GetXGraphic();
184 return m_xImpl->m_xCachedSnapshot;
187 OUString aRealURL = m_xImpl->m_MediaProperties.getTempURL();
188 if( aRealURL.isEmpty() )
189 aRealURL = m_xImpl->m_MediaProperties.getURL();
190 OUString sReferer = m_xImpl->m_MediaProperties.getReferer();
191 OUString sMimeType = m_xImpl->m_MediaProperties.getMimeType();
192 uno::Reference<graphic::XGraphic> xCachedSnapshot = m_xImpl->m_xCachedSnapshot;
194 m_xImpl->m_xPlayerListener.set(new avmedia::PlayerListener(
195 [this, xCachedSnapshot, aRealURL, sReferer, sMimeType](const css::uno::Reference<css::media::XPlayer>& rPlayer){
196 SolarMutexGuard g;
197 uno::Reference<graphic::XGraphic> xGraphic
198 = m_xImpl->m_MediaProperties.getGraphic().GetXGraphic();
199 m_xImpl->m_xCachedSnapshot = avmedia::MediaWindow::grabFrame(rPlayer, xGraphic);
200 ActionChanged();
201 }));
203 avmedia::MediaWindow::grabFrame(aRealURL, sReferer, sMimeType, m_xImpl->m_xPlayerListener);
205 #endif
206 return m_xImpl->m_xCachedSnapshot;
209 void SdrMediaObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool bShrinkOnly /* = false */ )
211 Size aSize( Application::GetDefaultDevice()->PixelToLogic(
212 static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).getPreferredSize(),
213 MapMode(MapUnit::Map100thMM)) );
214 Size aMaxSize( rMaxRect.GetSize() );
216 if( aSize.IsEmpty() )
217 return;
219 Point aPos( rMaxRect.TopLeft() );
221 // if graphic is too large, fit it to the page
222 if ( (!bShrinkOnly ||
223 ( aSize.Height() > aMaxSize.Height() ) ||
224 ( aSize.Width() > aMaxSize.Width() ) )&&
225 aSize.Height() && aMaxSize.Height() )
227 float fGrfWH = static_cast<float>(aSize.Width()) /
228 static_cast<float>(aSize.Height());
229 float fWinWH = static_cast<float>(aMaxSize.Width()) /
230 static_cast<float>(aMaxSize.Height());
232 // scale graphic to page size
233 if ( fGrfWH < fWinWH )
235 aSize.setWidth( static_cast<tools::Long>(aMaxSize.Height() * fGrfWH) );
236 aSize.setHeight( aMaxSize.Height() );
238 else if ( fGrfWH > 0.F )
240 aSize.setWidth( aMaxSize.Width() );
241 aSize.setHeight( static_cast<tools::Long>(aMaxSize.Width() / fGrfWH) );
244 aPos = rMaxRect.Center();
247 if( bShrinkOnly )
248 aPos = getRectangle().TopLeft();
250 aPos.AdjustX( -(aSize.Width() / 2) );
251 aPos.AdjustY( -(aSize.Height() / 2) );
252 SetLogicRect( tools::Rectangle( aPos, aSize ) );
255 void SdrMediaObj::setURL(const OUString& rURL, const OUString& rReferer)
257 ::avmedia::MediaItem aURLItem;
258 #if HAVE_FEATURE_AVMEDIA
259 aURLItem.setURL( rURL, "", rReferer );
260 #else
261 (void) rURL;
262 (void) rReferer;
263 #endif
264 setMediaProperties( aURLItem );
267 const OUString& SdrMediaObj::getURL() const
269 #if HAVE_FEATURE_AVMEDIA
270 return m_xImpl->m_MediaProperties.getURL();
271 #else
272 static OUString ret;
273 return ret;
274 #endif
277 const OUString& SdrMediaObj::getTempURL() const
279 #if HAVE_FEATURE_AVMEDIA
280 return m_xImpl->m_MediaProperties.getTempURL();
281 #else
282 static OUString ret;
283 return ret;
284 #endif
287 void SdrMediaObj::setMediaProperties( const ::avmedia::MediaItem& rState )
289 mediaPropertiesChanged( rState );
290 static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).executeMediaItem( getMediaProperties() );
293 const ::avmedia::MediaItem& SdrMediaObj::getMediaProperties() const
295 return m_xImpl->m_MediaProperties;
298 uno::Reference<io::XInputStream> SdrMediaObj::GetInputStream() const
300 #if HAVE_FEATURE_AVMEDIA
301 if (!m_xImpl->m_pTempFile)
303 SAL_WARN("svx", "this is only intended for embedded media");
304 return nullptr;
306 ucbhelper::Content tempFile(m_xImpl->m_pTempFile->m_TempFileURL,
307 uno::Reference<ucb::XCommandEnvironment>(),
308 comphelper::getProcessComponentContext());
309 return tempFile.openStream();
310 #else
311 return nullptr;
312 #endif
315 void SdrMediaObj::SetInputStream(uno::Reference<io::XInputStream> const& xStream)
317 #if !HAVE_FEATURE_AVMEDIA
318 (void) xStream;
319 #else
320 if (m_xImpl->m_pTempFile || m_xImpl->m_LastFailedPkgURL.isEmpty())
322 SAL_WARN("svx", "this is only intended for embedded media");
323 return;
326 OUString tempFileURL;
327 const bool bSuccess(
328 ::avmedia::CreateMediaTempFile(
329 xStream,
330 tempFileURL,
331 u""));
333 if (bSuccess)
335 m_xImpl->m_pTempFile = std::make_shared<::avmedia::MediaTempFile>(tempFileURL);
336 m_xImpl->m_MediaProperties.setURL(
337 m_xImpl->m_LastFailedPkgURL, tempFileURL, "");
339 m_xImpl->m_LastFailedPkgURL.clear(); // once only
340 #endif
343 /// copy a stream from XStorage to temp file
344 #if HAVE_FEATURE_AVMEDIA
345 static bool lcl_HandlePackageURL(
346 OUString const & rURL,
347 const SdrModel& rModel,
348 OUString & o_rTempFileURL)
350 ::comphelper::LifecycleProxy sourceProxy;
351 uno::Reference<io::XInputStream> xInStream;
352 try {
353 xInStream = rModel.GetDocumentStream(rURL, sourceProxy);
355 catch (container::NoSuchElementException const&)
357 SAL_INFO("svx", "not found: '" << rURL << "'");
358 return false;
360 catch (uno::Exception const&)
362 TOOLS_WARN_EXCEPTION("svx", "");
363 return false;
365 if (!xInStream.is())
367 SAL_WARN("svx", "no stream?");
368 return false;
370 // Make sure the temporary copy has the same file name extension as the original media file
371 // (like .mp4). That seems to be important for some AVFoundation APIs. For random extension-less
372 // file names, they don't seem to even bother looking inside the file.
373 sal_Int32 nLastDot = rURL.lastIndexOf('.');
374 sal_Int32 nLastSlash = rURL.lastIndexOf('/');
375 OUString sDesiredExtension;
376 if (nLastDot > nLastSlash && nLastDot+1 < rURL.getLength())
377 sDesiredExtension = rURL.copy(nLastDot);
378 return ::avmedia::CreateMediaTempFile(xInStream, o_rTempFileURL, sDesiredExtension);
380 #endif
382 void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProperties )
384 bool bBroadcastChanged = false;
385 #if HAVE_FEATURE_AVMEDIA
386 const AVMediaSetMask nMaskSet = rNewProperties.getMaskSet();
388 // use only a subset of MediaItem properties for own properties
389 if( AVMediaSetMask::MIME_TYPE & nMaskSet )
390 m_xImpl->m_MediaProperties.setMimeType( rNewProperties.getMimeType() );
392 if (nMaskSet & AVMediaSetMask::GRAPHIC)
394 m_xImpl->m_MediaProperties.setGraphic(rNewProperties.getGraphic());
397 if (nMaskSet & AVMediaSetMask::CROP)
399 m_xImpl->m_MediaProperties.setCrop(rNewProperties.getCrop());
402 if( ( AVMediaSetMask::URL & nMaskSet ) &&
403 ( rNewProperties.getURL() != getURL() ))
405 m_xImpl->m_xCachedSnapshot.clear();
406 m_xImpl->m_xPlayerListener.clear();
407 OUString const& url(rNewProperties.getURL());
408 if (url.startsWithIgnoreAsciiCase("vnd.sun.star.Package:"))
410 if ( !m_xImpl->m_pTempFile
411 || (m_xImpl->m_pTempFile->m_TempFileURL !=
412 rNewProperties.getTempURL()))
414 OUString tempFileURL;
415 const bool bSuccess(
416 lcl_HandlePackageURL(
417 url,
418 getSdrModelFromSdrObject(),
419 tempFileURL));
421 if (bSuccess)
423 m_xImpl->m_pTempFile =
424 std::make_shared<::avmedia::MediaTempFile>(tempFileURL);
425 m_xImpl->m_MediaProperties.setURL(url, tempFileURL, "");
427 else // this case is for Clone via operator=
429 m_xImpl->m_pTempFile.reset();
430 m_xImpl->m_MediaProperties.setURL("", "", "");
431 // UGLY: oox import also gets here, because unlike ODF
432 // getDocumentStorage() is not the imported file...
433 m_xImpl->m_LastFailedPkgURL = url;
436 else
438 m_xImpl->m_MediaProperties.setURL(url,
439 rNewProperties.getTempURL(), "");
442 else
444 m_xImpl->m_pTempFile.reset();
445 m_xImpl->m_MediaProperties.setURL(url, "", rNewProperties.getReferer());
447 bBroadcastChanged = true;
450 if( AVMediaSetMask::LOOP & nMaskSet )
451 m_xImpl->m_MediaProperties.setLoop( rNewProperties.isLoop() );
453 if( AVMediaSetMask::MUTE & nMaskSet )
454 m_xImpl->m_MediaProperties.setMute( rNewProperties.isMute() );
456 if( AVMediaSetMask::VOLUMEDB & nMaskSet )
457 m_xImpl->m_MediaProperties.setVolumeDB( rNewProperties.getVolumeDB() );
459 if( AVMediaSetMask::ZOOM & nMaskSet )
460 m_xImpl->m_MediaProperties.setZoom( rNewProperties.getZoom() );
461 #else
462 (void) rNewProperties;
463 #endif
465 if( bBroadcastChanged )
467 SetChanged();
468 BroadcastObjectChange();
472 void SdrMediaObj::notifyPropertiesForLOKit()
474 #if HAVE_FEATURE_AVMEDIA
475 if (!m_xImpl->m_MediaProperties.getTempURL().isEmpty())
477 const auto mediaId = reinterpret_cast<std::size_t>(this);
479 boost::property_tree::ptree json;
480 json.put("action", "update");
481 json.put("id", mediaId);
482 json.put("url", m_xImpl->m_MediaProperties.getTempURL());
484 const tools::Rectangle aRect = o3tl::convert(getRectangle(), o3tl::Length::mm100, o3tl::Length::twip);
485 json.put("x", aRect.getX());
486 json.put("y", aRect.getY());
487 json.put("w", aRect.getOpenWidth());
488 json.put("h", aRect.getOpenHeight());
490 SfxLokHelper::notifyMediaUpdate(json);
492 #endif
495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */