LibreOffice Module svx (master) 1
svdomedia.cxx
Go to the documentation of this file.
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.
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 <config_features.h>
21
22#include <svx/svdomedia.hxx>
23
24#include <com/sun/star/text/GraphicCrop.hpp>
25
26#include <rtl/ustring.hxx>
27#include <sal/log.hxx>
28
29#include <ucbhelper/content.hxx>
32#include <LibreOfficeKit/LibreOfficeKitEnums.h>
33#include <comphelper/lok.hxx>
34#include <sfx2/lokhelper.hxx>
35#include <boost/property_tree/json_parser.hpp>
36
37#include <vcl/svapp.hxx>
38
39#include <svx/svdmodel.hxx>
40#include <svx/dialmgr.hxx>
41#include <svx/strings.hrc>
45
46using namespace ::com::sun::star;
47
48
50{
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;
61};
62
64: SdrRectObj(rSdrModel)
65 ,m_xImpl( new Impl )
66{
67}
68
69SdrMediaObj::SdrMediaObj(SdrModel& rSdrModel, SdrMediaObj const & rSource)
70: SdrRectObj(rSdrModel, rSource)
71 ,m_xImpl( new Impl )
72{
73#if HAVE_FEATURE_AVMEDIA
74 m_xImpl->m_pTempFile = rSource.m_xImpl->m_pTempFile; // before props
75#endif
77 m_xImpl->m_xCachedSnapshot = rSource.m_xImpl->m_xCachedSnapshot;
78}
79
81 SdrModel& rSdrModel,
82 const tools::Rectangle& rRect)
83: SdrRectObj(rSdrModel, rRect)
84 ,m_xImpl( new Impl )
85{
86 osl_atomic_increment(&m_refCount);
87
88 const bool bUndo(rSdrModel.IsUndoEnabled());
89 rSdrModel.EnableUndo(false);
91 rSdrModel.EnableUndo(bUndo);
92
93 osl_atomic_decrement(&m_refCount);
94}
95
97{
98}
99
101{
102 return false;
103}
104
105std::unique_ptr<sdr::contact::ViewContact> SdrMediaObj::CreateObjectSpecificViewContact()
106{
107 return std::make_unique<sdr::contact::ViewContactOfSdrMediaObj>( *this );
108}
109
111{
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;
130}
131
133{
134 return SdrObjKind::Media;
135}
136
138{
139 OUString sName(SvxResId(STR_ObjNameSingulMEDIA));
140
141 OUString aName(GetName());
142
143 if (!aName.isEmpty())
144 sName += " '" + aName + "'";
145
146 return sName;
147}
148
150{
151 return SvxResId(STR_ObjNamePluralMEDIA);
152}
153
155{
156 return new SdrMediaObj(rTargetModel, *this);
157}
158
159uno::Reference< graphic::XGraphic > const & SdrMediaObj::getSnapshot() const
160{
161#if HAVE_FEATURE_AVMEDIA
162 if( !m_xImpl->m_xCachedSnapshot.is() )
163 {
164 Graphic aGraphic = m_xImpl->m_MediaProperties.getGraphic();
165 if (!aGraphic.IsNone())
166 {
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)
171 {
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;
179 }
180
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;
185 }
186
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;
193
194 m_xImpl->m_xPlayerListener.set(new avmedia::PlayerListener(
195 [this, xCachedSnapshot, aRealURL, sReferer, sMimeType](const css::uno::Reference<css::media::XPlayer>& rPlayer){
197 uno::Reference<graphic::XGraphic> xGraphic
198 = m_xImpl->m_MediaProperties.getGraphic().GetXGraphic();
199 m_xImpl->m_xCachedSnapshot = avmedia::MediaWindow::grabFrame(rPlayer, xGraphic);
201 }));
202
203 avmedia::MediaWindow::grabFrame(aRealURL, sReferer, sMimeType, m_xImpl->m_xPlayerListener);
204 }
205#endif
206 return m_xImpl->m_xCachedSnapshot;
207}
208
209void SdrMediaObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool bShrinkOnly /* = false */ )
210{
211 Size aSize( Application::GetDefaultDevice()->PixelToLogic(
212 static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).getPreferredSize(),
213 MapMode(MapUnit::Map100thMM)) );
214 Size aMaxSize( rMaxRect.GetSize() );
215
216 if( aSize.IsEmpty() )
217 return;
218
219 Point aPos( rMaxRect.TopLeft() );
220
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() )
226 {
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());
231
232 // scale graphic to page size
233 if ( fGrfWH < fWinWH )
234 {
235 aSize.setWidth( static_cast<tools::Long>(aMaxSize.Height() * fGrfWH) );
236 aSize.setHeight( aMaxSize.Height() );
237 }
238 else if ( fGrfWH > 0.F )
239 {
240 aSize.setWidth( aMaxSize.Width() );
241 aSize.setHeight( static_cast<tools::Long>(aMaxSize.Width() / fGrfWH) );
242 }
243
244 aPos = rMaxRect.Center();
245 }
246
247 if( bShrinkOnly )
248 aPos = maRect.TopLeft();
249
250 aPos.AdjustX( -(aSize.Width() / 2) );
251 aPos.AdjustY( -(aSize.Height() / 2) );
252 SetLogicRect( tools::Rectangle( aPos, aSize ) );
253}
254
255void SdrMediaObj::setURL( const OUString& rURL, const OUString& rReferer, const OUString& rMimeType )
256{
257 ::avmedia::MediaItem aURLItem;
258#if HAVE_FEATURE_AVMEDIA
259 if( !rMimeType.isEmpty() )
260 m_xImpl->m_MediaProperties.setMimeType(rMimeType);
261 aURLItem.setURL( rURL, "", rReferer );
262#else
263 (void) rMimeType;
264 (void) rURL;
265 (void) rReferer;
266#endif
267 setMediaProperties( aURLItem );
268}
269
270const OUString& SdrMediaObj::getURL() const
271{
272#if HAVE_FEATURE_AVMEDIA
273 return m_xImpl->m_MediaProperties.getURL();
274#else
275 static OUString ret;
276 return ret;
277#endif
278}
279
280const OUString& SdrMediaObj::getTempURL() const
281{
282#if HAVE_FEATURE_AVMEDIA
283 return m_xImpl->m_MediaProperties.getTempURL();
284#else
285static OUString ret;
286 return ret;
287#endif
288}
289
290void SdrMediaObj::setMediaProperties( const ::avmedia::MediaItem& rState )
291{
292 mediaPropertiesChanged( rState );
293 static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).executeMediaItem( getMediaProperties() );
294}
295
296const ::avmedia::MediaItem& SdrMediaObj::getMediaProperties() const
297{
298 return m_xImpl->m_MediaProperties;
299}
300
301uno::Reference<io::XInputStream> SdrMediaObj::GetInputStream() const
302{
303#if HAVE_FEATURE_AVMEDIA
304 if (!m_xImpl->m_pTempFile)
305 {
306 SAL_WARN("svx", "this is only intended for embedded media");
307 return nullptr;
308 }
309 ucbhelper::Content tempFile(m_xImpl->m_pTempFile->m_TempFileURL,
310 uno::Reference<ucb::XCommandEnvironment>(),
312 return tempFile.openStream();
313#else
314 return nullptr;
315#endif
316}
317
318void SdrMediaObj::SetInputStream(uno::Reference<io::XInputStream> const& xStream)
319{
320#if !HAVE_FEATURE_AVMEDIA
321 (void) xStream;
322#else
323 if (m_xImpl->m_pTempFile || m_xImpl->m_LastFailedPkgURL.isEmpty())
324 {
325 SAL_WARN("svx", "this is only intended for embedded media");
326 return;
327 }
328
329 OUString tempFileURL;
330 const bool bSuccess(
331 ::avmedia::CreateMediaTempFile(
332 xStream,
333 tempFileURL,
334 u""));
335
336 if (bSuccess)
337 {
338 m_xImpl->m_pTempFile = std::make_shared<::avmedia::MediaTempFile>(tempFileURL);
339 m_xImpl->m_MediaProperties.setURL(
340 m_xImpl->m_LastFailedPkgURL, tempFileURL, "");
341 }
342 m_xImpl->m_LastFailedPkgURL.clear(); // once only
343#endif
344}
345
347#if HAVE_FEATURE_AVMEDIA
348static bool lcl_HandlePackageURL(
349 OUString const & rURL,
350 const SdrModel& rModel,
351 OUString & o_rTempFileURL)
352{
354 uno::Reference<io::XInputStream> xInStream;
355 try {
356 xInStream = rModel.GetDocumentStream(rURL, sourceProxy);
357 }
358 catch (container::NoSuchElementException const&)
359 {
360 SAL_INFO("svx", "not found: '" << rURL << "'");
361 return false;
362 }
363 catch (uno::Exception const&)
364 {
365 TOOLS_WARN_EXCEPTION("svx", "");
366 return false;
367 }
368 if (!xInStream.is())
369 {
370 SAL_WARN("svx", "no stream?");
371 return false;
372 }
373 // Make sure the temporary copy has the same file name extension as the original media file
374 // (like .mp4). That seems to be important for some AVFoundation APIs. For random extension-less
375 // file names, they don't seem to even bother looking inside the file.
376 sal_Int32 nLastDot = rURL.lastIndexOf('.');
377 sal_Int32 nLastSlash = rURL.lastIndexOf('/');
378 OUString sDesiredExtension;
379 if (nLastDot > nLastSlash && nLastDot+1 < rURL.getLength())
380 sDesiredExtension = rURL.copy(nLastDot);
381 return ::avmedia::CreateMediaTempFile(xInStream, o_rTempFileURL, sDesiredExtension);
382}
383#endif
384
385void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProperties )
386{
387 bool bBroadcastChanged = false;
388#if HAVE_FEATURE_AVMEDIA
389 const AVMediaSetMask nMaskSet = rNewProperties.getMaskSet();
390
391 // use only a subset of MediaItem properties for own properties
392 if( AVMediaSetMask::MIME_TYPE & nMaskSet )
393 m_xImpl->m_MediaProperties.setMimeType( rNewProperties.getMimeType() );
394
395 if (nMaskSet & AVMediaSetMask::GRAPHIC)
396 {
397 m_xImpl->m_MediaProperties.setGraphic(rNewProperties.getGraphic());
398 }
399
400 if (nMaskSet & AVMediaSetMask::CROP)
401 {
402 m_xImpl->m_MediaProperties.setCrop(rNewProperties.getCrop());
403 }
404
405 if( ( AVMediaSetMask::URL & nMaskSet ) &&
406 ( rNewProperties.getURL() != getURL() ))
407 {
408 m_xImpl->m_xCachedSnapshot.clear();
409 m_xImpl->m_xPlayerListener.clear();
410 OUString const& url(rNewProperties.getURL());
411 if (url.startsWithIgnoreAsciiCase("vnd.sun.star.Package:"))
412 {
413 if ( !m_xImpl->m_pTempFile
414 || (m_xImpl->m_pTempFile->m_TempFileURL !=
415 rNewProperties.getTempURL()))
416 {
417 OUString tempFileURL;
418 const bool bSuccess(
419 lcl_HandlePackageURL(
420 url,
422 tempFileURL));
423
424 if (bSuccess)
425 {
426 m_xImpl->m_pTempFile =
427 std::make_shared<::avmedia::MediaTempFile>(tempFileURL);
428 m_xImpl->m_MediaProperties.setURL(url, tempFileURL, "");
429 }
430 else // this case is for Clone via operator=
431 {
432 m_xImpl->m_pTempFile.reset();
433 m_xImpl->m_MediaProperties.setURL("", "", "");
434 // UGLY: oox import also gets here, because unlike ODF
435 // getDocumentStorage() is not the imported file...
436 m_xImpl->m_LastFailedPkgURL = url;
437 }
438 }
439 else
440 {
441 m_xImpl->m_MediaProperties.setURL(url,
442 rNewProperties.getTempURL(), "");
443 }
444 }
445 else
446 {
447 m_xImpl->m_pTempFile.reset();
448 m_xImpl->m_MediaProperties.setURL(url, "", rNewProperties.getReferer());
449 }
450 bBroadcastChanged = true;
451 }
452
453 if( AVMediaSetMask::LOOP & nMaskSet )
454 m_xImpl->m_MediaProperties.setLoop( rNewProperties.isLoop() );
455
456 if( AVMediaSetMask::MUTE & nMaskSet )
457 m_xImpl->m_MediaProperties.setMute( rNewProperties.isMute() );
458
459 if( AVMediaSetMask::VOLUMEDB & nMaskSet )
460 m_xImpl->m_MediaProperties.setVolumeDB( rNewProperties.getVolumeDB() );
461
462 if( AVMediaSetMask::ZOOM & nMaskSet )
463 m_xImpl->m_MediaProperties.setZoom( rNewProperties.getZoom() );
464#else
465 (void) rNewProperties;
466#endif
467
468 if( bBroadcastChanged )
469 {
470 SetChanged();
472 }
473}
474
476{
477 if (!m_xImpl->m_MediaProperties.getTempURL().isEmpty())
478 {
479 const auto mediaId = reinterpret_cast<std::size_t>(this);
480
481 boost::property_tree::ptree json;
482 json.put("action", "update");
483 json.put("id", mediaId);
484 json.put("url", m_xImpl->m_MediaProperties.getTempURL());
485
487 json.put("x", aRect.getX());
488 json.put("y", aRect.getY());
489 json.put("w", aRect.getOpenWidth());
490 json.put("h", aRect.getOpenHeight());
491
493 }
494}
495
496/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
static OutputDevice * GetDefaultDevice()
bool Crop(const tools::Rectangle &rRectPixel)
css::uno::Reference< css::graphic::XGraphic > GetXGraphic() const
Size GetPrefSize() const
bool IsNone() const
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Size GetSizePixel(const OutputDevice *pRefDevice=nullptr) const
virtual OUString TakeObjNameSingul() const override
Definition: svdomedia.cxx:137
css::uno::Reference< css::io::XInputStream > GetInputStream() const
Definition: svdomedia.cxx:301
virtual void TakeObjInfo(SdrObjTransformInfoRec &rInfo) const override
Definition: svdomedia.cxx:110
void setMediaProperties(const ::avmedia::MediaItem &rState)
Definition: svdomedia.cxx:290
virtual SdrObjKind GetObjIdentifier() const override
Definition: svdomedia.cxx:132
const OUString & getTempURL() const
Returns the URL to the temporary extracted media file.
Definition: svdomedia.cxx:280
const OUString & getURL() const
Definition: svdomedia.cxx:270
css::uno::Reference< css::graphic::XGraphic > const & getSnapshot() const
Definition: svdomedia.cxx:159
const ::avmedia::MediaItem & getMediaProperties() const
Definition: svdomedia.cxx:296
virtual bool HasTextEdit() const override
Definition: svdomedia.cxx:100
virtual rtl::Reference< SdrObject > CloneSdrObject(SdrModel &rTargetModel) const override
Definition: svdomedia.cxx:154
virtual OUString TakeObjNamePlural() const override
Definition: svdomedia.cxx:149
virtual std::unique_ptr< sdr::contact::ViewContact > CreateObjectSpecificViewContact() override
Definition: svdomedia.cxx:105
void mediaPropertiesChanged(const ::avmedia::MediaItem &rNewState)
copy a stream from XStorage to temp file
Definition: svdomedia.cxx:385
virtual ~SdrMediaObj() override
Definition: svdomedia.cxx:96
void notifyPropertiesForLOKit()
When Lokit is enabled, notify the media details.
Definition: svdomedia.cxx:475
void setURL(const OUString &rURL, const OUString &rReferer, const OUString &rMimeType=OUString())
Definition: svdomedia.cxx:255
virtual void AdjustToMaxRect(const tools::Rectangle &rMaxRect, bool bShrinkOnly=false) override
Definition: svdomedia.cxx:209
std::unique_ptr< Impl > m_xImpl
Definition: svdomedia.hxx:85
SdrMediaObj(SdrModel &rSdrModel)
Definition: svdomedia.cxx:63
void SetInputStream(css::uno::Reference< css::io::XInputStream > const &)
Definition: svdomedia.cxx:318
css::uno::Reference< css::io::XInputStream > GetDocumentStream(OUString const &rURL, ::comphelper::LifecycleProxy const &rProxy) const
Definition: svdmodel.cxx:750
void EnableUndo(bool bEnable)
enables (true) or disables (false) recording of undo actions If undo actions are added while undo is ...
Definition: svdmodel.cxx:518
bool IsUndoEnabled() const
returns true if undo is currently enabled This returns false if undo was disabled using EnableUndo( f...
Definition: svdmodel.cxx:530
Provides information about various ZObject properties.
Definition: svdobj.hxx:197
void ActionChanged() const
Definition: svdobj.cxx:273
void MakeNameUnique()
Definition: svdobj.cxx:3098
void BroadcastObjectChange() const
Definition: svdobj.cxx:978
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:289
virtual void SetLogicRect(const tools::Rectangle &rRect)
Definition: svdobj.cxx:1699
virtual const OUString & GetName() const
Definition: svdobj.cxx:769
sdr::contact::ViewContact & GetViewContact() const
Definition: svdobj.cxx:261
virtual void SetChanged()
Definition: svdobj.cxx:1002
Rectangle objects (rectangle, circle, ...)
Definition: svdorect.hxx:39
tools::Rectangle maRect
Definition: svdotext.hxx:168
static void notifyMediaUpdate(boost::property_tree::ptree &json)
bool IsEmpty() const
constexpr tools::Long getHeight() const
constexpr tools::Long Height() const
constexpr tools::Long getWidth() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
bool setURL(const OUString &rURL, const OUString &rTempURL, const OUString &rReferer)
static css::uno::Reference< css::graphic::XGraphic > grabFrame(const css::uno::Reference< css::media::XPlayer > &rPlayer, const css::uno::Reference< css::graphic::XGraphic > &rGraphic=nullptr)
oslInterlockedCount m_refCount
constexpr Point Center() const
tools::Long getY() const
constexpr Point TopLeft() const
tools::Long getOpenHeight() const
constexpr Size GetSize() const
tools::Long getX() const
tools::Long getOpenWidth() const
css::uno::Reference< css::io::XInputStream > openStream()
#define TOOLS_WARN_EXCEPTION(area, stream)
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
float u
OUString sName
OUString aName
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
AVMediaSetMask
Reference< XComponentContext > getProcessComponentContext()
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
long Long
rtl::Reference< avmedia::PlayerListener > m_xPlayerListener
Definition: svdomedia.cxx:59
OUString m_LastFailedPkgURL
Definition: svdomedia.cxx:60
uno::Reference< graphic::XGraphic > m_xCachedSnapshot
Definition: svdomedia.cxx:58
::avmedia::MediaItem m_MediaProperties
Definition: svdomedia.cxx:51
SdrObjKind
Definition: svdobjkind.hxx:25
@ Media
custom shape