tdf#44223: Export the audio of effects and transitions.
This will allow to round trip the test case for the slide
transition and the animation effect audio.
Change-Id: Iac524e6bbcdb0a29491cfeba63121c845685fd11
Reviewed-on: https://gerrit.libreoffice.org/68540
Tested-by: Jenkins
Reviewed-by: Mark Hung <marklh9@gmail.com>
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index ae60952..eda6827 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -198,6 +198,7 @@
void testTdf119118();
void testTdf99213();
void testPotxExport();
void testTdf44223();
CPPUNIT_TEST_SUITE(SdOOXMLExportTest2);
@@ -278,6 +279,7 @@
CPPUNIT_TEST(testTdf119118);
CPPUNIT_TEST(testTdf99213);
CPPUNIT_TEST(testPotxExport);
CPPUNIT_TEST(testTdf44223);
CPPUNIT_TEST_SUITE_END();
@@ -297,6 +299,7 @@
{ "wp", "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" },
{ "p", "http://schemas.openxmlformats.org/presentationml/2006/main" },
{ "p14", "http://schemas.microsoft.com/office/powerpoint/2010/main" },
{ "r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships" },
{ "w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main" },
{ "a14", "http://schemas.microsoft.com/office/drawing/2010/main" },
{ "wps", "http://schemas.microsoft.com/office/word/2010/wordprocessingShape" },
@@ -2066,6 +2069,40 @@
assertXPath(pContentTypes, "/ContentType:Types/ContentType:Override[@PartName='/ppt/presentation.xml']",
"ContentType", "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml");
}
void SdOOXMLExportTest2::testTdf44223()
{
utl::TempFile tempFile;
::sd::DrawDocShellRef xDocShRef
= loadURL(m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/tdf44223.pptx"), PPTX);
xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
std::shared_ptr<SvStream> const pStream1(parseExportStream(tempFile, "media/audio1.wav"));
CPPUNIT_ASSERT_EQUAL(sal_uInt64(11140), pStream1->remainingSize());
std::shared_ptr<SvStream> const pStream2(parseExportStream(tempFile, "media/audio2.wav"));
CPPUNIT_ASSERT_EQUAL(sal_uInt64(28074), pStream2->remainingSize());
xmlDocPtr pXmlContentType = parseExport(tempFile, "[Content_Types].xml");
assertXPath(pXmlContentType,
"/ContentType:Types/ContentType:Override[@PartName='/media/audio1.wav']",
"ContentType",
"audio/x-wav");
assertXPath(pXmlContentType,
"/ContentType:Types/ContentType:Override[@PartName='/media/audio2.wav']",
"ContentType",
"audio/x-wav");
xmlDocPtr pDoc1 = parseExport(tempFile, "ppt/slides/slide1.xml");
assertXPath(pDoc1 , "//p:audio/p:cMediaNode/p:tgtEl/p:sndTgt[@r:embed]", 1);
xmlDocPtr pDoc2 = parseExport(tempFile, "ppt/slides/slide2.xml");
assertXPath(pDoc2 , "//p:transition/p:sndAc/p:stSnd/p:snd[@r:embed]", 2);
xDocShRef->DoClose();
}
CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest2);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index 684dacb..44464e2 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -44,8 +44,6 @@
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/document/XEventsSupplier.hpp>
#include <com/sun/star/document/XStorageBasedDocument.hpp>
#include <com/sun/star/embed/XStorage.hpp>
#include <com/sun/star/presentation/ClickAction.hpp>
#include <com/sun/star/presentation/XPresentationPage.hpp>
#include <com/sun/star/presentation/XPresentationSupplier.hpp>
@@ -194,7 +192,6 @@
void testTdf123090();
void testTdf120028();
void testTdf120028b();
void testTdf44223();
void testDescriptionImport();
void testTdf83247();
void testTdf47365();
@@ -282,7 +279,6 @@
CPPUNIT_TEST(testTdf123090);
CPPUNIT_TEST(testTdf120028);
CPPUNIT_TEST(testTdf120028b);
CPPUNIT_TEST(testTdf44223);
CPPUNIT_TEST(testDescriptionImport);
CPPUNIT_TEST(testTdf83247);
CPPUNIT_TEST(testTdf47365);
@@ -2632,29 +2628,6 @@
xDocShRef->DoClose();
}
void SdImportTest::testTdf44223()
{
::sd::DrawDocShellRef xDocShRef
= loadURL(m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/tdf44223.pptx"), PPTX);
uno::Reference<document::XStorageBasedDocument> xSBD(xDocShRef->GetDoc()->getUnoModel(), uno::UNO_QUERY);
CPPUNIT_ASSERT(xSBD.is());
uno::Reference<embed::XStorage> xStorage = xSBD->getDocumentStorage();
CPPUNIT_ASSERT(xStorage.is());
uno::Reference<container::XNameAccess> xNameAccess(xStorage, uno::UNO_QUERY);
CPPUNIT_ASSERT(xNameAccess.is());
uno::Reference<embed::XStorage> xStorage_2(xNameAccess->getByName("Media"), uno::UNO_QUERY);
CPPUNIT_ASSERT(xStorage_2.is());
uno::Reference< container::XNameAccess > xNameAccess_2(xStorage_2, uno::UNO_QUERY);
CPPUNIT_ASSERT(xNameAccess_2->hasByName("audio1.wav"));
CPPUNIT_ASSERT(xNameAccess_2->hasByName("audio2.wav"));
xDocShRef->DoClose();
}
void SdImportTest::testDescriptionImport()
{
sd::DrawDocShellRef xDocShRef
diff --git a/sd/source/filter/eppt/epptooxml.hxx b/sd/source/filter/eppt/epptooxml.hxx
index 5d6be22..5791c02 100644
--- a/sd/source/filter/eppt/epptooxml.hxx
+++ b/sd/source/filter/eppt/epptooxml.hxx
@@ -76,6 +76,9 @@
sal_Int32 GetShapeID(const css::uno::Reference<css::drawing::XShape>& rXShape);
sal_Int32 GetNextAnimationNodeID();
void embedEffectAudio(const FSHelperPtr& pFS, const OUString& sUrl, OUString& sRelId, OUString& sName);
private:
virtual void ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 nMode,
diff --git a/sd/source/filter/eppt/pptx-animations.cxx b/sd/source/filter/eppt/pptx-animations.cxx
index 7e0967d..d484fcc 100644
--- a/sd/source/filter/eppt/pptx-animations.cxx
+++ b/sd/source/filter/eppt/pptx-animations.cxx
@@ -41,6 +41,7 @@
#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
#include <com/sun/star/animations/XAnimateColor.hpp>
#include <com/sun/star/animations/XCommand.hpp>
#include <com/sun/star/animations/XAudio.hpp>
#include <com/sun/star/animations/XTransitionFilter.hpp>
#include <com/sun/star/animations/XIterateContainer.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
@@ -393,6 +394,9 @@
case AnimationNodeType::COMMAND:
xmlNodeType = XML_cmd;
break;
case AnimationNodeType::AUDIO:
xmlNodeType = XML_audio;
break;
default:
SAL_WARN("sd.eppt", "unhandled animation node: " << nType);
break;
@@ -615,6 +619,7 @@
void WriteAnimationNodeSeq();
void WriteAnimationNodeEffect();
void WriteAnimationNodeCommand();
void WriteAnimationNodeAudio();
void WriteAnimationNodeCommonPropsStart();
void WriteAnimationTarget(const Any& rTarget);
void WriteAnimationCondList(const Any& rAny, sal_Int32 nToken);
@@ -1144,6 +1149,39 @@
mpFS->endElementNS(XML_p, XML_cmd);
}
void PPTXAnimationExport::WriteAnimationNodeAudio()
{
SAL_INFO("sd.eppt", "write animation node audio");
Reference<XAudio> xAudio(getCurrentNode(), UNO_QUERY);
OUString sUrl;
OUString sRelId;
OUString sName;
if (!(xAudio.is() && (xAudio->getSource() >>= sUrl) && !sUrl.isEmpty()
&& sUrl.endsWithIgnoreAsciiCase(".wav")))
return;
mrPowerPointExport.embedEffectAudio(mpFS, sUrl, sRelId, sName);
mpFS->startElementNS(XML_p, XML_audio, FSEND);
mpFS->startElementNS(XML_p, XML_cMediaNode, FSEND);
mpFS->startElementNS(XML_p, XML_cTn, FSEND);
WriteAnimationCondList(mpContext->getCondition(true), XML_stCondLst);
WriteAnimationCondList(mpContext->getCondition(false), XML_endCondLst);
mpFS->endElementNS(XML_p, XML_cTn);
mpFS->startElementNS(XML_p, XML_tgtEl, FSEND);
mpFS->singleElementNS(XML_p, XML_sndTgt, FSNS(XML_r, XML_embed),
sRelId.isEmpty() ? nullptr : USS(sRelId), XML_name,
sUrl.isEmpty() ? nullptr : USS(sName), FSEND);
mpFS->endElementNS(XML_p, XML_tgtEl);
mpFS->endElementNS(XML_p, XML_cMediaNode);
mpFS->endElementNS(XML_p, XML_audio);
}
void PPTXAnimationExport::WriteAnimationNode(const NodeContextPtr& pContext)
{
const NodeContext* pSavedContext = mpContext;
@@ -1178,6 +1216,9 @@
case XML_cmd:
WriteAnimationNodeCommand();
break;
case XML_audio:
WriteAnimationNodeAudio();
break;
default:
SAL_WARN("sd.eppt", "export ooxml node type: " << xmlNodeType);
break;
@@ -1278,8 +1319,10 @@
}
else if (nType == AnimationNodeType::AUDIO)
{
SAL_WARN("sd.eppt", "Export AUDIO node is not supported yet.");
mbValid = false;
Reference<XAudio> xAudio(mxNode, UNO_QUERY);
OUString sURL;
mbValid
= xAudio.is() && (xAudio->getSource() >>= sURL) && sURL.endsWithIgnoreAsciiCase(".wav");
}
else
{
diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx
index b91c265..2d244f2 100644
--- a/sd/source/filter/eppt/pptx-epptooxml.cxx
+++ b/sd/source/filter/eppt/pptx-epptooxml.cxx
@@ -115,6 +115,21 @@
bool WritePlaceholder(const Reference< XShape >& xShape, PlaceholderType ePlaceholder, bool bMaster);
};
namespace
{
void WriteSndAc(const FSHelperPtr& pFS, const OUString& sSoundRelId, const OUString& sSoundName)
{
pFS->startElementNS(XML_p, XML_sndAc, FSEND);
pFS->startElementNS(XML_p, XML_stSnd, FSEND);
pFS->singleElementNS(XML_p, XML_snd,
FSNS(XML_r, XML_embed), sSoundRelId.isEmpty() ? nullptr : USS(sSoundRelId),
XML_name, sSoundName.isEmpty() ? nullptr : USS(sSoundName), FSEND);
pFS->endElement(FSNS(XML_p, XML_stSnd));
pFS->endElement(FSNS(XML_p, XML_sndAc));
}
}
}
}
@@ -546,6 +561,10 @@
sal_Int8 nPPTTransitionType = 0;
sal_uInt8 nDirection = 0;
OUString sSoundUrl;
OUString sSoundRelId;
OUString sSoundName;
if (ImplGetPropertyValue(mXPagePropSet, "TransitionType") && (mAny >>= nTransitionType) &&
ImplGetPropertyValue(mXPagePropSet, "TransitionSubtype") && (mAny >>= nTransitionSubtype))
nPPTTransitionType = GetTransition(nTransitionType, nTransitionSubtype, eFadeEffect, nDirection);
@@ -553,6 +572,9 @@
if (!nPPTTransitionType && eFadeEffect != FadeEffect_NONE)
nPPTTransitionType = GetTransition(eFadeEffect, nDirection);
if (ImplGetPropertyValue(mXPagePropSet, "Sound") && (mAny >>= sSoundUrl))
embedEffectAudio(pFS, sSoundUrl, sSoundRelId, sSoundName);
bool bOOXmlSpecificTransition = false;
sal_Int32 nTransition = 0;
@@ -866,6 +888,9 @@
FSEND);
}
if (!sSoundRelId.isEmpty())
WriteSndAc(pFS, sSoundRelId, sSoundName);
pFS->endElement(FSNS(XML_p, XML_transition));
pFS->endElement(FSNS(XML_mc, XML_Choice));
@@ -887,6 +912,9 @@
FSEND);
}
if (!sSoundRelId.isEmpty())
WriteSndAc(pFS, sSoundRelId, sSoundName);
pFS->endElementNS(XML_p, XML_transition);
if (nTransition14 || pPresetTransition || isTransitionDurationSet)
@@ -1935,6 +1963,51 @@
SAL_INFO("sd.eppt", "----------------");
}
void PowerPointExport::embedEffectAudio(const FSHelperPtr& pFS, const OUString& sUrl, OUString& sRelId, OUString& sName)
{
comphelper::LifecycleProxy aProxy;
if (!sUrl.endsWithIgnoreAsciiCase(".wav"))
return;
uno::Reference<io::XInputStream> xAudioStream;
if (sUrl.startsWith("vnd.sun.star.Package:"))
{
uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(getModel(), uno::UNO_QUERY);
if (!xStorageBasedDocument.is())
return;
uno::Reference<embed::XStorage> xDocumentStorage(xStorageBasedDocument->getDocumentStorage(), uno::UNO_QUERY);
if (!xDocumentStorage.is())
return;
uno::Reference<io::XStream> xStream = comphelper::OStorageHelper::GetStreamAtPackageURL(xDocumentStorage, sUrl,
css::embed::ElementModes::READ, aProxy);
if (xStream.is())
xAudioStream = xStream->getInputStream();
}
else
xAudioStream = comphelper::OStorageHelper::GetInputStreamFromURL(sUrl, getComponentContext());
if (!xAudioStream.is())
return;
int nLastSlash = sUrl.lastIndexOf('/');
sName = sUrl.copy(nLastSlash >= 0 ? nLastSlash + 1 : 0);
OUString sPath = OUStringBuffer().append("/media/")
.append(sName)
.makeStringAndClear();
sRelId = addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::AUDIO), sPath);
uno::Reference<io::XOutputStream> xOutputStream = openFragmentStream(sPath, "audio/x-wav");
comphelper::OStorageHelper::CopyInputToOutput(xAudioStream, xOutputStream);
}
sal_Int32 PowerPointExport::GetShapeID(const Reference<XShape>& rXShape)
{
return ShapeExport::GetShapeID(rXShape, &maShapeMap);