From d0176d65de40b1ea53b4fcbc0f607911fa64d8e5 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 2 Sep 2022 10:27:05 +0200 Subject: [PATCH] tdf#149969 slideshow: handle loop from the animation of a media shape Impress supported video looping on media shapes, while PowerPoint supports this as part of the animation tree for the slide. To be more specific, it seems in case there is play command, then it looks up if there is a media node of the timing tree that has the current shape as its target, and checks if the looping is enabled for this shape in this media node. The PPTX import already creates an (audio) node for the media shape and we have UNO API to set/get a RepatCount attribute on this. Rather than tweaking the PPTX import to create a different doc model, just extend the rendering so in case the shape doesn't enable looping we can also notice that an animation requested looping. The PPTX export doesn't write a media node for videos at the moment, so that still needs work. Change-Id: Ifc6600be760a954230243fd8151736656958a429 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139253 Reviewed-by: Miklos Vajna Tested-by: Jenkins --- slideshow/CppunitTest_slideshow_engine.mk | 50 +++++++++ slideshow/Library_slideshow.mk | 4 + slideshow/Module_slideshow.mk | 1 + slideshow/qa/engine/data/video-loop.pptx | Bin 0 -> 46545 bytes slideshow/qa/engine/engine.cxx | 102 ++++++++++++++++++ .../animationnodes/animationcommandnode.cxx | 97 +++++++++++++++++ .../animationnodes/animationcommandnode.hxx | 10 +- .../engine/shapes/externalshapebase.cxx | 1 + .../engine/shapes/externalshapebase.hxx | 2 + slideshow/source/engine/shapes/mediashape.cxx | 8 ++ .../source/engine/shapes/viewmediashape.cxx | 8 ++ .../source/engine/shapes/viewmediashape.hxx | 2 + .../source/inc/iexternalmediashapebase.hxx | 2 + slideshow/source/inc/slideshowdllapi.h | 20 ++++ 14 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 slideshow/CppunitTest_slideshow_engine.mk create mode 100644 slideshow/qa/engine/data/video-loop.pptx create mode 100644 slideshow/qa/engine/engine.cxx create mode 100644 slideshow/source/inc/slideshowdllapi.h diff --git a/slideshow/CppunitTest_slideshow_engine.mk b/slideshow/CppunitTest_slideshow_engine.mk new file mode 100644 index 000000000000..a88531df49f7 --- /dev/null +++ b/slideshow/CppunitTest_slideshow_engine.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,slideshow_engine)) + +$(eval $(call gb_CppunitTest_use_externals,slideshow_engine,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,slideshow_engine, \ + slideshow/qa/engine/engine \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,slideshow_engine, \ + comphelper \ + cppu \ + slideshow \ + sal \ + test \ + unotest \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,slideshow_engine)) + +$(eval $(call gb_CppunitTest_set_include,slideshow_engine,\ + -I$(SRCDIR)/slideshow/source/inc \ + -I$(SRCDIR)/slideshow/source/engine/animationnodes \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_ure,slideshow_engine)) +$(eval $(call gb_CppunitTest_use_vcl,slideshow_engine)) + +$(eval $(call gb_CppunitTest_use_rdb,slideshow_engine,services)) + +$(eval $(call gb_CppunitTest_use_custom_headers,slideshow_engine,\ + officecfg/registry \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,slideshow_engine)) + +# vim: set noet sw=4 ts=4: diff --git a/slideshow/Library_slideshow.mk b/slideshow/Library_slideshow.mk index a57717990124..580a7ae60df3 100644 --- a/slideshow/Library_slideshow.mk +++ b/slideshow/Library_slideshow.mk @@ -28,6 +28,10 @@ $(eval $(call gb_Library_use_externals,slideshow,\ epoxy \ )) +$(eval $(call gb_Library_add_defs,slideshow,\ + -DSLIDESHOW_DLLIMPLEMENTATION \ +)) + $(eval $(call gb_Library_use_sdk_api,slideshow)) $(eval $(call gb_Library_use_libraries,slideshow,\ diff --git a/slideshow/Module_slideshow.mk b/slideshow/Module_slideshow.mk index 51b832cfa4f1..9cbaff1eb7e7 100644 --- a/slideshow/Module_slideshow.mk +++ b/slideshow/Module_slideshow.mk @@ -21,6 +21,7 @@ endif $(eval $(call gb_Module_add_check_targets,slideshow,\ CppunitTest_slideshow \ + CppunitTest_slideshow_engine \ )) # vim: set noet sw=4 ts=4: diff --git a/slideshow/qa/engine/data/video-loop.pptx b/slideshow/qa/engine/data/video-loop.pptx new file mode 100644 index 0000000000000000000000000000000000000000..4cb7e20b7428adcd8aea04f136bc046bd92739ef GIT binary patch literal 46545 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 literal 0 HcmV?d00001 diff --git a/slideshow/qa/engine/engine.cxx b/slideshow/qa/engine/engine.cxx new file mode 100644 index 000000000000..09e56f73d3f8 --- /dev/null +++ b/slideshow/qa/engine/engine.cxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +namespace +{ +/// Covers slideshow/source/engine/ fixes. +class Test : public test::BootstrapFixture, public unotest::MacrosTest +{ +private: + uno::Reference mxComponent; + +public: + void setUp() override; + void tearDown() override; + uno::Reference& getComponent() { return mxComponent; } +}; + +void Test::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +void Test::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +/// Get the first command node in the animation tree of the page, assuming that it's the first child +/// (recursively). +uno::Reference +GetFirstCommandNodeOfPage(const uno::Reference& xPage) +{ + uno::Reference xAnimationNodeSupplier(xPage, + uno::UNO_QUERY); + uno::Reference xNode = xAnimationNodeSupplier->getAnimationNode(); + while (true) + { + if (xNode->getType() == animations::AnimationNodeType::COMMAND) + { + break; + } + uno::Reference xEnumAccess(xNode, uno::UNO_QUERY); + uno::Reference xNodes = xEnumAccess->createEnumeration(); + xNode.set(xNodes->nextElement(), uno::UNO_QUERY); + } + uno::Reference xRet(xNode, uno::UNO_QUERY); + return xRet; +} +} + +CPPUNIT_TEST_FIXTURE(Test, testLoopingFromAnimation) +{ + // Given a document with a looping video, the looping is defined as part of its auto-play + // animation (and not on the media shape): + OUString aURL = m_directories.getURLFromSrc(u"slideshow/qa/engine/data/video-loop.pptx"); + getComponent().set(loadFromDesktop(aURL)); + uno::Reference xDoc(getComponent(), uno::UNO_QUERY); + uno::Reference xPage(xDoc->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference xCommandNode = GetFirstCommandNodeOfPage(xPage); + uno::Reference xShape(xPage->getByIndex(0), uno::UNO_QUERY); + + // When determining if the video should be looping or not: + bool bLooping + = slideshow::internal::AnimationCommandNode::GetLoopingFromAnimation(xCommandNode, xShape); + + // Then make sure that we detect the looping is wanted: + CPPUNIT_ASSERT(bLooping); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/slideshow/source/engine/animationnodes/animationcommandnode.cxx b/slideshow/source/engine/animationnodes/animationcommandnode.cxx index 2e8507e3a5f5..df70cb1ab37c 100644 --- a/slideshow/source/engine/animationnodes/animationcommandnode.cxx +++ b/slideshow/source/engine/animationnodes/animationcommandnode.cxx @@ -19,8 +19,14 @@ #include +#include +#include +#include +#include #include +#include + #include "animationcommandnode.hxx" #include #include @@ -28,6 +34,52 @@ using namespace com::sun::star; +namespace +{ +/// Determines if this is the root of the timing node tree. +bool IsTimingRootNode(const uno::Reference& xNode) +{ + uno::Sequence aUserData = xNode->getUserData(); + comphelper::SequenceAsHashMap aMap(aUserData); + auto it = aMap.find("node-type"); + if (it == aMap.end()) + { + return false; + } + + sal_Int16 nNodeType{}; + if (!(it->second >>= nNodeType)) + { + return false; + } + + return nNodeType == css::presentation::EffectNodeType::TIMING_ROOT; +} + +/// Walks the parent chain of xNode and stops at the timing root. +uno::Reference +GetTimingRoot(const uno::Reference& xNode) +{ + uno::Reference xParent(xNode->getParent(), uno::UNO_QUERY); + while (true) + { + if (!xParent.is()) + { + break; + } + + if (IsTimingRootNode(xParent)) + { + return xParent; + } + + xParent.set(xParent->getParent(), uno::UNO_QUERY); + } + + return {}; +} +} + namespace slideshow::internal { namespace EffectCommands = css::presentation::EffectCommands; @@ -43,6 +95,7 @@ AnimationCommandNode::AnimationCommandNode( uno::ReferencelookupShape( xShape ) ); mpShape = ::std::dynamic_pointer_cast< IExternalMediaShapeBase >( pShape ); + mxShape = xShape; } void AnimationCommandNode::dispose() @@ -52,6 +105,42 @@ void AnimationCommandNode::dispose() BaseNode::dispose(); } +bool AnimationCommandNode::GetLoopingFromAnimation( + const uno::Reference& xCommandNode, + const uno::Reference& xShape) +{ + uno::Reference xTimingRoot = GetTimingRoot(xCommandNode); + uno::Reference xEnumAccess(xTimingRoot, uno::UNO_QUERY); + if (!xEnumAccess.is()) + { + return false; + } + + uno::Reference xNodes = xEnumAccess->createEnumeration(); + while (xNodes->hasMoreElements()) + { + uno::Reference xNode(xNodes->nextElement(), uno::UNO_QUERY); + if (xNode->getType() != animations::AnimationNodeType::AUDIO) + { + continue; + } + + uno::Reference xAudio(xNode, uno::UNO_QUERY); + uno::Reference xSource(xAudio->getSource(), uno::UNO_QUERY); + if (xSource != xShape) + { + continue; + } + + animations::Timing eTiming{}; + if ((xAudio->getRepeatCount() >>= eTiming) && eTiming == animations::Timing_INDEFINITE) + { + return true; + } + } + return false; +} + void AnimationCommandNode::activate_st() { switch( mxCommandNode->getCommand() ) { @@ -71,6 +160,14 @@ void AnimationCommandNode::activate_st() if( mpShape ) { mpShape->setMediaTime(fMediaTime/1000.0); + + if (AnimationCommandNode::GetLoopingFromAnimation(mxCommandNode, mxShape)) + { + // If looping is requested from the animation, then that has priority over the + // looping from the shape itself. + mpShape->setLooping(true); + } + mpShape->play(); } break; diff --git a/slideshow/source/engine/animationnodes/animationcommandnode.hxx b/slideshow/source/engine/animationnodes/animationcommandnode.hxx index bcb61f1ddd3f..96ca886f8f2c 100644 --- a/slideshow/source/engine/animationnodes/animationcommandnode.hxx +++ b/slideshow/source/engine/animationnodes/animationcommandnode.hxx @@ -20,6 +20,7 @@ #ifndef INCLUDED_SLIDESHOW_SOURCE_ENGINE_ANIMATIONNODES_ANIMATIONCOMMANDNODE_HXX #define INCLUDED_SLIDESHOW_SOURCE_ENGINE_ANIMATIONNODES_ANIMATIONCOMMANDNODE_HXX +#include #include #include #include @@ -31,7 +32,7 @@ namespace slideshow::internal { This animation node encapsulates a command. Not yet implemented: verb & custom. */ -class AnimationCommandNode : public BaseNode +class SLIDESHOW_DLLPUBLIC AnimationCommandNode : public BaseNode { public: AnimationCommandNode( @@ -39,6 +40,12 @@ public: ::std::shared_ptr const& pParent, NodeContext const& rContext ); + /// Assuming that xCommandNode is a play command, determines if an audio node wants looping when + /// xShape plays. + static bool + GetLoopingFromAnimation(const css::uno::Reference& xCommandNode, + const css::uno::Reference& xShape); + protected: virtual void dispose() override; @@ -49,6 +56,7 @@ private: private: IExternalMediaShapeBaseSharedPtr mpShape; css::uno::Reference mxCommandNode; + css::uno::Reference mxShape; }; } // namespace slideshow::internal diff --git a/slideshow/source/engine/shapes/externalshapebase.cxx b/slideshow/source/engine/shapes/externalshapebase.cxx index 22205186fa7e..8a879db0dae2 100644 --- a/slideshow/source/engine/shapes/externalshapebase.cxx +++ b/slideshow/source/engine/shapes/externalshapebase.cxx @@ -143,6 +143,7 @@ namespace slideshow::internal implSetIntrinsicAnimationTime(fTime); } + void ExternalShapeBase::setLooping(bool bLooping) { implSetLooping(bLooping); } bool ExternalShapeBase::update() const { diff --git a/slideshow/source/engine/shapes/externalshapebase.hxx b/slideshow/source/engine/shapes/externalshapebase.hxx index 260d8630e170..d8c208db2a99 100644 --- a/slideshow/source/engine/shapes/externalshapebase.hxx +++ b/slideshow/source/engine/shapes/externalshapebase.hxx @@ -65,6 +65,7 @@ namespace slideshow::internal virtual void pause() override; virtual bool isPlaying() const override; virtual void setMediaTime(double) override; + void setLooping(bool bLooping) override; // render methods @@ -108,6 +109,7 @@ namespace slideshow::internal virtual bool implIsIntrinsicAnimationPlaying() const = 0; /// override in derived class to set media time virtual void implSetIntrinsicAnimationTime(double) = 0; + virtual void implSetLooping(bool /*bLooping*/) {} /// The associated XShape diff --git a/slideshow/source/engine/shapes/mediashape.cxx b/slideshow/source/engine/shapes/mediashape.cxx index 28d3cee86821..a5cbb926f4f5 100644 --- a/slideshow/source/engine/shapes/mediashape.cxx +++ b/slideshow/source/engine/shapes/mediashape.cxx @@ -82,6 +82,7 @@ namespace slideshow::internal virtual void implPauseIntrinsicAnimation() override; virtual bool implIsIntrinsicAnimationPlaying() const override; virtual void implSetIntrinsicAnimationTime(double) override; + void implSetLooping(bool bLooping) override; /// the list of active view shapes (one for each registered view layer) typedef ::std::vector< ViewMediaShapeSharedPtr > ViewMediaShapeVector; @@ -235,6 +236,13 @@ namespace slideshow::internal pViewMediaShape->setMediaTime( fTime ); } + void MediaShape::implSetLooping(bool bLooping) + { + for (const auto& pViewMediaShape : maViewMediaShapes) + { + pViewMediaShape->setLooping(bLooping); + } + } ShapeSharedPtr createMediaShape( const uno::Reference< drawing::XShape >& xShape, diff --git a/slideshow/source/engine/shapes/viewmediashape.cxx b/slideshow/source/engine/shapes/viewmediashape.cxx index 4c5b9f51f8f6..f91972f8fe40 100644 --- a/slideshow/source/engine/shapes/viewmediashape.cxx +++ b/slideshow/source/engine/shapes/viewmediashape.cxx @@ -144,6 +144,14 @@ namespace slideshow::internal mxPlayer->setMediaTime(fTime); } + void ViewMediaShape::setLooping(bool bLooping) + { + if (mxPlayer.is()) + { + mxPlayer->setPlaybackLoop(bLooping); + } + } + bool ViewMediaShape::render( const ::basegfx::B2DRectangle& rBounds ) const { #if !HAVE_FEATURE_AVMEDIA diff --git a/slideshow/source/engine/shapes/viewmediashape.hxx b/slideshow/source/engine/shapes/viewmediashape.hxx index 32515a47d864..fc37a3add8ce 100644 --- a/slideshow/source/engine/shapes/viewmediashape.hxx +++ b/slideshow/source/engine/shapes/viewmediashape.hxx @@ -112,6 +112,8 @@ namespace slideshow::internal */ void setMediaTime(double fTime); + void setLooping(bool bLooping); + // render methods diff --git a/slideshow/source/inc/iexternalmediashapebase.hxx b/slideshow/source/inc/iexternalmediashapebase.hxx index 156b0b2dd7ce..1a70ae093652 100644 --- a/slideshow/source/inc/iexternalmediashapebase.hxx +++ b/slideshow/source/inc/iexternalmediashapebase.hxx @@ -72,6 +72,8 @@ namespace slideshow::internal presented */ virtual void setMediaTime(double fTime) = 0; + + virtual void setLooping(bool /*bLooping*/){}; }; typedef ::std::shared_ptr< IExternalMediaShapeBase > IExternalMediaShapeBaseSharedPtr; diff --git a/slideshow/source/inc/slideshowdllapi.h b/slideshow/source/inc/slideshowdllapi.h new file mode 100644 index 000000000000..048a83dd271a --- /dev/null +++ b/slideshow/source/inc/slideshowdllapi.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +#if defined(SLIDESHOW_DLLIMPLEMENTATION) +#define SLIDESHOW_DLLPUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define SLIDESHOW_DLLPUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */