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
33#include <vcl/svapp.hxx>
34
35#include <svx/svdmodel.hxx>
36#include <svx/dialmgr.hxx>
37#include <svx/strings.hrc>
41
42using namespace ::com::sun::star;
43
44
46{
48#if HAVE_FEATURE_AVMEDIA
49 // Note: the temp file is read only, until it is deleted!
50 // It may be shared between multiple documents in case of copy/paste,
51 // hence the shared_ptr.
52 std::shared_ptr< ::avmedia::MediaTempFile > m_pTempFile;
53#endif
54 uno::Reference< graphic::XGraphic > m_xCachedSnapshot;
57};
58
60: SdrRectObj(rSdrModel)
61 ,m_xImpl( new Impl )
62{
63}
64
65SdrMediaObj::SdrMediaObj(SdrModel& rSdrModel, SdrMediaObj const & rSource)
66: SdrRectObj(rSdrModel, rSource)
67 ,m_xImpl( new Impl )
68{
69#if HAVE_FEATURE_AVMEDIA
70 m_xImpl->m_pTempFile = rSource.m_xImpl->m_pTempFile; // before props
71#endif
73 m_xImpl->m_xCachedSnapshot = rSource.m_xImpl->m_xCachedSnapshot;
74}
75
77 SdrModel& rSdrModel,
78 const tools::Rectangle& rRect)
79: SdrRectObj(rSdrModel, rRect)
80 ,m_xImpl( new Impl )
81{
82 osl_atomic_increment(&m_refCount);
83
84 const bool bUndo(rSdrModel.IsUndoEnabled());
85 rSdrModel.EnableUndo(false);
87 rSdrModel.EnableUndo(bUndo);
88
89 osl_atomic_decrement(&m_refCount);
90}
91
93{
94}
95
97{
98 return false;
99}
100
101std::unique_ptr<sdr::contact::ViewContact> SdrMediaObj::CreateObjectSpecificViewContact()
102{
103 return std::make_unique<sdr::contact::ViewContactOfSdrMediaObj>( *this );
104}
105
107{
108 rInfo.bMoveAllowed = true;
109 rInfo.bResizeFreeAllowed = true;
110 rInfo.bResizePropAllowed = true;
111 rInfo.bRotateFreeAllowed = false;
112 rInfo.bRotate90Allowed = false;
113 rInfo.bMirrorFreeAllowed = false;
114 rInfo.bMirror45Allowed = false;
115 rInfo.bMirror90Allowed = false;
116 rInfo.bTransparenceAllowed = false;
117 rInfo.bShearAllowed = false;
118 rInfo.bEdgeRadiusAllowed = false;
119 rInfo.bNoOrthoDesired = false;
120 rInfo.bNoContortion = false;
121 rInfo.bCanConvToPath = false;
122 rInfo.bCanConvToPoly = false;
123 rInfo.bCanConvToContour = false;
124 rInfo.bCanConvToPathLineToArea = false;
125 rInfo.bCanConvToPolyLineToArea = false;
126}
127
129{
130 return SdrObjKind::Media;
131}
132
134{
135 OUString sName(SvxResId(STR_ObjNameSingulMEDIA));
136
137 OUString aName(GetName());
138
139 if (!aName.isEmpty())
140 sName += " '" + aName + "'";
141
142 return sName;
143}
144
146{
147 return SvxResId(STR_ObjNamePluralMEDIA);
148}
149
151{
152 return new SdrMediaObj(rTargetModel, *this);
153}
154
155uno::Reference< graphic::XGraphic > const & SdrMediaObj::getSnapshot() const
156{
157#if HAVE_FEATURE_AVMEDIA
158 if( !m_xImpl->m_xCachedSnapshot.is() )
159 {
160 Graphic aGraphic = m_xImpl->m_MediaProperties.getGraphic();
161 if (!aGraphic.IsNone())
162 {
163 Size aPref = aGraphic.GetPrefSize();
164 Size aPixel = aGraphic.GetSizePixel();
165 const text::GraphicCrop& rCrop = m_xImpl->m_MediaProperties.getCrop();
166 if (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0)
167 {
168 tools::Long nLeft = aPixel.getWidth() * rCrop.Left / aPref.getWidth();
169 tools::Long nTop = aPixel.getHeight() * rCrop.Top / aPref.getHeight();
170 tools::Long nRight = aPixel.getWidth() * rCrop.Right / aPref.getWidth();
171 tools::Long nBottom = aPixel.getHeight() * rCrop.Bottom / aPref.getHeight();
172 BitmapEx aBitmapEx = aGraphic.GetBitmapEx();
173 aBitmapEx.Crop({nLeft, nTop, aPixel.getWidth() - nRight, aPixel.getHeight() - nBottom});
174 aGraphic = aBitmapEx;
175 }
176
177 // We have an explicit graphic for this media object, then go with that instead of
178 // generating our own one.
179 m_xImpl->m_xCachedSnapshot = aGraphic.GetXGraphic();
180 return m_xImpl->m_xCachedSnapshot;
181 }
182
183 OUString aRealURL = m_xImpl->m_MediaProperties.getTempURL();
184 if( aRealURL.isEmpty() )
185 aRealURL = m_xImpl->m_MediaProperties.getURL();
186 OUString sReferer = m_xImpl->m_MediaProperties.getReferer();
187 OUString sMimeType = m_xImpl->m_MediaProperties.getMimeType();
188 uno::Reference<graphic::XGraphic> xCachedSnapshot = m_xImpl->m_xCachedSnapshot;
189
190 m_xImpl->m_xPlayerListener.set(new avmedia::PlayerListener(
191 [this, xCachedSnapshot, aRealURL, sReferer, sMimeType](const css::uno::Reference<css::media::XPlayer>& rPlayer){
193 uno::Reference<graphic::XGraphic> xGraphic
194 = m_xImpl->m_MediaProperties.getGraphic().GetXGraphic();
195 m_xImpl->m_xCachedSnapshot = avmedia::MediaWindow::grabFrame(rPlayer, xGraphic);
197 }));
198
199 avmedia::MediaWindow::grabFrame(aRealURL, sReferer, sMimeType, m_xImpl->m_xPlayerListener);
200 }
201#endif
202 return m_xImpl->m_xCachedSnapshot;
203}
204
205void SdrMediaObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool bShrinkOnly /* = false */ )
206{
207 Size aSize( Application::GetDefaultDevice()->PixelToLogic(
208 static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).getPreferredSize(),
209 MapMode(MapUnit::Map100thMM)) );
210 Size aMaxSize( rMaxRect.GetSize() );
211
212 if( aSize.IsEmpty() )
213 return;
214
215 Point aPos( rMaxRect.TopLeft() );
216
217 // if graphic is too large, fit it to the page
218 if ( (!bShrinkOnly ||
219 ( aSize.Height() > aMaxSize.Height() ) ||
220 ( aSize.Width() > aMaxSize.Width() ) )&&
221 aSize.Height() && aMaxSize.Height() )
222 {
223 float fGrfWH = static_cast<float>(aSize.Width()) /
224 static_cast<float>(aSize.Height());
225 float fWinWH = static_cast<float>(aMaxSize.Width()) /
226 static_cast<float>(aMaxSize.Height());
227
228 // scale graphic to page size
229 if ( fGrfWH < fWinWH )
230 {
231 aSize.setWidth( static_cast<tools::Long>(aMaxSize.Height() * fGrfWH) );
232 aSize.setHeight( aMaxSize.Height() );
233 }
234 else if ( fGrfWH > 0.F )
235 {
236 aSize.setWidth( aMaxSize.Width() );
237 aSize.setHeight( static_cast<tools::Long>(aMaxSize.Width() / fGrfWH) );
238 }
239
240 aPos = rMaxRect.Center();
241 }
242
243 if( bShrinkOnly )
244 aPos = maRect.TopLeft();
245
246 aPos.AdjustX( -(aSize.Width() / 2) );
247 aPos.AdjustY( -(aSize.Height() / 2) );
248 SetLogicRect( tools::Rectangle( aPos, aSize ) );
249}
250
251void SdrMediaObj::setURL( const OUString& rURL, const OUString& rReferer, const OUString& rMimeType )
252{
253 ::avmedia::MediaItem aURLItem;
254#if HAVE_FEATURE_AVMEDIA
255 if( !rMimeType.isEmpty() )
256 m_xImpl->m_MediaProperties.setMimeType(rMimeType);
257 aURLItem.setURL( rURL, "", rReferer );
258#else
259 (void) rMimeType;
260 (void) rURL;
261 (void) rReferer;
262#endif
263 setMediaProperties( aURLItem );
264}
265
266const OUString& SdrMediaObj::getURL() const
267{
268#if HAVE_FEATURE_AVMEDIA
269 return m_xImpl->m_MediaProperties.getURL();
270#else
271 static OUString ret;
272 return ret;
273#endif
274}
275
276void SdrMediaObj::setMediaProperties( const ::avmedia::MediaItem& rState )
277{
278 mediaPropertiesChanged( rState );
279 static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).executeMediaItem( getMediaProperties() );
280}
281
282const ::avmedia::MediaItem& SdrMediaObj::getMediaProperties() const
283{
284 return m_xImpl->m_MediaProperties;
285}
286
287uno::Reference<io::XInputStream> SdrMediaObj::GetInputStream() const
288{
289#if HAVE_FEATURE_AVMEDIA
290 if (!m_xImpl->m_pTempFile)
291 {
292 SAL_WARN("svx", "this is only intended for embedded media");
293 return nullptr;
294 }
295 ucbhelper::Content tempFile(m_xImpl->m_pTempFile->m_TempFileURL,
296 uno::Reference<ucb::XCommandEnvironment>(),
298 return tempFile.openStream();
299#else
300 return nullptr;
301#endif
302}
303
304void SdrMediaObj::SetInputStream(uno::Reference<io::XInputStream> const& xStream)
305{
306#if !HAVE_FEATURE_AVMEDIA
307 (void) xStream;
308#else
309 if (m_xImpl->m_pTempFile || m_xImpl->m_LastFailedPkgURL.isEmpty())
310 {
311 SAL_WARN("svx", "this is only intended for embedded media");
312 return;
313 }
314
315 OUString tempFileURL;
316 const bool bSuccess(
317 ::avmedia::CreateMediaTempFile(
318 xStream,
319 tempFileURL,
320 u""));
321
322 if (bSuccess)
323 {
324 m_xImpl->m_pTempFile = std::make_shared<::avmedia::MediaTempFile>(tempFileURL);
325 m_xImpl->m_MediaProperties.setURL(
326 m_xImpl->m_LastFailedPkgURL, tempFileURL, "");
327 }
328 m_xImpl->m_LastFailedPkgURL.clear(); // once only
329#endif
330}
331
333#if HAVE_FEATURE_AVMEDIA
334static bool lcl_HandlePackageURL(
335 OUString const & rURL,
336 const SdrModel& rModel,
337 OUString & o_rTempFileURL)
338{
340 uno::Reference<io::XInputStream> xInStream;
341 try {
342 xInStream = rModel.GetDocumentStream(rURL, sourceProxy);
343 }
344 catch (container::NoSuchElementException const&)
345 {
346 SAL_INFO("svx", "not found: '" << rURL << "'");
347 return false;
348 }
349 catch (uno::Exception const&)
350 {
351 TOOLS_WARN_EXCEPTION("svx", "");
352 return false;
353 }
354 if (!xInStream.is())
355 {
356 SAL_WARN("svx", "no stream?");
357 return false;
358 }
359 // Make sure the temporary copy has the same file name extension as the original media file
360 // (like .mp4). That seems to be important for some AVFoundation APIs. For random extension-less
361 // file names, they don't seem to even bother looking inside the file.
362 sal_Int32 nLastDot = rURL.lastIndexOf('.');
363 sal_Int32 nLastSlash = rURL.lastIndexOf('/');
364 OUString sDesiredExtension;
365 if (nLastDot > nLastSlash && nLastDot+1 < rURL.getLength())
366 sDesiredExtension = rURL.copy(nLastDot);
367 return ::avmedia::CreateMediaTempFile(xInStream, o_rTempFileURL, sDesiredExtension);
368}
369#endif
370
371void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProperties )
372{
373 bool bBroadcastChanged = false;
374#if HAVE_FEATURE_AVMEDIA
375 const AVMediaSetMask nMaskSet = rNewProperties.getMaskSet();
376
377 // use only a subset of MediaItem properties for own properties
378 if( AVMediaSetMask::MIME_TYPE & nMaskSet )
379 m_xImpl->m_MediaProperties.setMimeType( rNewProperties.getMimeType() );
380
381 if (nMaskSet & AVMediaSetMask::GRAPHIC)
382 {
383 m_xImpl->m_MediaProperties.setGraphic(rNewProperties.getGraphic());
384 }
385
386 if (nMaskSet & AVMediaSetMask::CROP)
387 {
388 m_xImpl->m_MediaProperties.setCrop(rNewProperties.getCrop());
389 }
390
391 if( ( AVMediaSetMask::URL & nMaskSet ) &&
392 ( rNewProperties.getURL() != getURL() ))
393 {
394 m_xImpl->m_xCachedSnapshot.clear();
395 m_xImpl->m_xPlayerListener.clear();
396 OUString const& url(rNewProperties.getURL());
397 if (url.startsWithIgnoreAsciiCase("vnd.sun.star.Package:"))
398 {
399 if ( !m_xImpl->m_pTempFile
400 || (m_xImpl->m_pTempFile->m_TempFileURL !=
401 rNewProperties.getTempURL()))
402 {
403 OUString tempFileURL;
404 const bool bSuccess(
405 lcl_HandlePackageURL(
406 url,
408 tempFileURL));
409
410 if (bSuccess)
411 {
412 m_xImpl->m_pTempFile =
413 std::make_shared<::avmedia::MediaTempFile>(tempFileURL);
414 m_xImpl->m_MediaProperties.setURL(url, tempFileURL, "");
415 }
416 else // this case is for Clone via operator=
417 {
418 m_xImpl->m_pTempFile.reset();
419 m_xImpl->m_MediaProperties.setURL("", "", "");
420 // UGLY: oox import also gets here, because unlike ODF
421 // getDocumentStorage() is not the imported file...
422 m_xImpl->m_LastFailedPkgURL = url;
423 }
424 }
425 else
426 {
427 m_xImpl->m_MediaProperties.setURL(url,
428 rNewProperties.getTempURL(), "");
429 }
430 }
431 else
432 {
433 m_xImpl->m_pTempFile.reset();
434 m_xImpl->m_MediaProperties.setURL(url, "", rNewProperties.getReferer());
435 }
436 bBroadcastChanged = true;
437 }
438
439 if( AVMediaSetMask::LOOP & nMaskSet )
440 m_xImpl->m_MediaProperties.setLoop( rNewProperties.isLoop() );
441
442 if( AVMediaSetMask::MUTE & nMaskSet )
443 m_xImpl->m_MediaProperties.setMute( rNewProperties.isMute() );
444
445 if( AVMediaSetMask::VOLUMEDB & nMaskSet )
446 m_xImpl->m_MediaProperties.setVolumeDB( rNewProperties.getVolumeDB() );
447
448 if( AVMediaSetMask::ZOOM & nMaskSet )
449 m_xImpl->m_MediaProperties.setZoom( rNewProperties.getZoom() );
450#else
451 (void) rNewProperties;
452#endif
453
454 if( bBroadcastChanged )
455 {
456 SetChanged();
458 }
459}
460
461/* 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:133
css::uno::Reference< css::io::XInputStream > GetInputStream() const
Definition: svdomedia.cxx:287
virtual void TakeObjInfo(SdrObjTransformInfoRec &rInfo) const override
Definition: svdomedia.cxx:106
void setMediaProperties(const ::avmedia::MediaItem &rState)
Definition: svdomedia.cxx:276
virtual SdrObjKind GetObjIdentifier() const override
Definition: svdomedia.cxx:128
const OUString & getURL() const
Definition: svdomedia.cxx:266
css::uno::Reference< css::graphic::XGraphic > const & getSnapshot() const
Definition: svdomedia.cxx:155
const ::avmedia::MediaItem & getMediaProperties() const
Definition: svdomedia.cxx:282
virtual bool HasTextEdit() const override
Definition: svdomedia.cxx:96
virtual rtl::Reference< SdrObject > CloneSdrObject(SdrModel &rTargetModel) const override
Definition: svdomedia.cxx:150
virtual OUString TakeObjNamePlural() const override
Definition: svdomedia.cxx:145
virtual std::unique_ptr< sdr::contact::ViewContact > CreateObjectSpecificViewContact() override
Definition: svdomedia.cxx:101
void mediaPropertiesChanged(const ::avmedia::MediaItem &rNewState)
copy a stream from XStorage to temp file
Definition: svdomedia.cxx:371
virtual ~SdrMediaObj() override
Definition: svdomedia.cxx:92
void setURL(const OUString &rURL, const OUString &rReferer, const OUString &rMimeType=OUString())
Definition: svdomedia.cxx:251
virtual void AdjustToMaxRect(const tools::Rectangle &rMaxRect, bool bShrinkOnly=false) override
Definition: svdomedia.cxx:205
std::unique_ptr< Impl > m_xImpl
Definition: svdomedia.hxx:79
SdrMediaObj(SdrModel &rSdrModel)
Definition: svdomedia.cxx:59
void SetInputStream(css::uno::Reference< css::io::XInputStream > const &)
Definition: svdomedia.cxx:304
css::uno::Reference< css::io::XInputStream > GetDocumentStream(OUString const &rURL, ::comphelper::LifecycleProxy const &rProxy) const
Definition: svdmodel.cxx:744
void EnableUndo(bool bEnable)
enables (true) or disables (false) recording of undo actions If undo actions are added while undo is ...
Definition: svdmodel.cxx:512
bool IsUndoEnabled() const
returns true if undo is currently enabled This returns false if undo was disabled using EnableUndo( f...
Definition: svdmodel.cxx:524
Provides information about various ZObject properties.
Definition: svdobj.hxx:193
void ActionChanged() const
Definition: svdobj.cxx:268
void MakeNameUnique()
Definition: svdobj.cxx:3093
void BroadcastObjectChange() const
Definition: svdobj.cxx:973
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:284
virtual void SetLogicRect(const tools::Rectangle &rRect)
Definition: svdobj.cxx:1694
const OUString & GetName() const
Definition: svdobj.cxx:764
sdr::contact::ViewContact & GetViewContact() const
Definition: svdobj.cxx:256
virtual void SetChanged()
Definition: svdobj.cxx:997
Rectangle objects (rectangle, circle, ...)
Definition: svdorect.hxx:39
tools::Rectangle maRect
Definition: svdotext.hxx:168
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
constexpr Point TopLeft() const
constexpr Size GetSize() 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()
long Long
rtl::Reference< avmedia::PlayerListener > m_xPlayerListener
Definition: svdomedia.cxx:55
OUString m_LastFailedPkgURL
Definition: svdomedia.cxx:56
uno::Reference< graphic::XGraphic > m_xCachedSnapshot
Definition: svdomedia.cxx:54
::avmedia::MediaItem m_MediaProperties
Definition: svdomedia.cxx:47
SdrObjKind
Definition: svdobjkind.hxx:25
@ Media
custom shape