sd/qa/unit/export-tests-ooxml3.cxx                |   10 +++++++---
 sd/source/filter/eppt/pptx-animations-nodectx.cxx |   20 +++++++++++++++++---
 sd/source/filter/eppt/pptx-animations-nodectx.hxx |    4 ++++
 sd/source/filter/eppt/pptx-animations.cxx         |   19 ++++++++++++++++++-
 4 files changed, 46 insertions(+), 7 deletions(-)

New commits:
commit 4e6601cf1b99c1aa52934388e9cefd527389cf80
Author:     Mark Hung <mark...@gmail.com>
AuthorDate: Sat Jan 28 18:39:49 2023 +0800
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Sun Jan 29 06:01:05 2023 +0000

    tdf#124230 export subTnLst for event triggered nodes.
    
    LibreOffice export all the child nodes of a timenode
    to childTnLst. It seems that PowerPoint anticipate there
    being fixed starting-time timenodes on childTnLst.
    This patch export event-triggered audio time nodes to
    subTnLst to make audio playback work. Other node types can
    be added in the future once more test cases are found.
    
    Change-Id: Ic96ec50876f568145bdde122d01dec10c1ac7c50
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146295
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/sd/qa/unit/export-tests-ooxml3.cxx 
b/sd/qa/unit/export-tests-ooxml3.cxx
index db023bef2592..7753abe651ee 100644
--- a/sd/qa/unit/export-tests-ooxml3.cxx
+++ b/sd/qa/unit/export-tests-ooxml3.cxx
@@ -1113,10 +1113,14 @@ void SdOOXMLExportTest3::testTdf44223()
 
     xmlDocUniquePtr pDoc1 = parseExport("ppt/slides/slide1.xml");
 
+    // tdf#124230 all nodes were under p:childTnLst, but event triggered nodes 
need
+    // to be under p:subTnLst, especially for audio to work correctly.
     // Start condition: 0s after timenode id 5 begins.
-    assertXPath(pDoc1, "//p:audio/p:cMediaNode/p:cTn/p:stCondLst/p:cond", 
"evt", "begin");
-    assertXPath(pDoc1, "//p:audio/p:cMediaNode/p:cTn/p:stCondLst/p:cond", 
"delay", "0");
-    assertXPath(pDoc1, "//p:audio/p:cMediaNode/p:cTn/p:stCondLst/p:cond/p:tn", 
"val", "5");
+    assertXPath(pDoc1, 
"//p:subTnLst/p:audio/p:cMediaNode/p:cTn/p:stCondLst/p:cond", "evt",
+                "begin");
+    assertXPath(pDoc1, 
"//p:subTnLst/p:audio/p:cMediaNode/p:cTn/p:stCondLst/p:cond", "delay", "0");
+    assertXPath(pDoc1, 
"//p:subTnLst/p:audio/p:cMediaNode/p:cTn/p:stCondLst/p:cond/p:tn", "val",
+                "5");
 
     xmlDocUniquePtr pDoc2 = parseExport("ppt/slides/slide2.xml");
     assertXPath(pDoc2, "//p:transition/p:sndAc/p:stSnd/p:snd[@r:embed]", 2);
diff --git a/sd/source/filter/eppt/pptx-animations-nodectx.cxx 
b/sd/source/filter/eppt/pptx-animations-nodectx.cxx
index 957301a5afd8..e538a0ca4e99 100644
--- a/sd/source/filter/eppt/pptx-animations-nodectx.cxx
+++ b/sd/source/filter/eppt/pptx-animations-nodectx.cxx
@@ -57,10 +57,11 @@ bool IsAudioURL(const OUString& rURL)
 /// Returns if rURL has an extension which is a video format.
 bool IsVideoURL(const OUString& rURL) { return 
rURL.endsWithIgnoreAsciiCase(".mp4"); }
 
-void initCondList(const Any& rAny, std::vector<Cond>& rList, bool 
bIsMainSeqChild)
+bool initCondList(const Any& rAny, std::vector<Cond>& rList, bool 
bIsMainSeqChild)
 {
+    bool bEventTrigger = false;
     if (!rAny.hasValue())
-        return;
+        return false;
 
     Sequence<Any> aCondSeq;
     if (rAny >>= aCondSeq)
@@ -69,15 +70,24 @@ void initCondList(const Any& rAny, std::vector<Cond>& 
rList, bool bIsMainSeqChil
         {
             Cond aCond(rCond, bIsMainSeqChild);
             if (aCond.isValid())
+            {
                 rList.push_back(aCond);
+                if (aCond.mpEvent)
+                    bEventTrigger = true;
+            }
         }
     }
     else
     {
         Cond aCond(rAny, bIsMainSeqChild);
         if (aCond.isValid())
+        {
             rList.push_back(aCond);
+            if (aCond.mpEvent)
+                bEventTrigger = true;
+        }
     }
+    return bEventTrigger;
 }
 }
 
@@ -86,6 +96,7 @@ NodeContext::NodeContext(const Reference<XAnimationNode>& 
xNode, bool bMainSeqCh
     : mxNode(xNode)
     , mbMainSeqChild(bMainSeqChild)
     , mbValid(true)
+    , mbOnSubTnLst(false)
     , mnEffectNodeType(-1)
     , mnEffectPresetClass(css::presentation::EffectPresetClass::CUSTOM)
 {
@@ -95,7 +106,10 @@ NodeContext::NodeContext(const Reference<XAnimationNode>& 
xNode, bool bMainSeqCh
 
     initValid(initChildNodes(), bIsIterateChild);
 
-    initCondList(getNodeForCondition()->getBegin(), maBeginCondList, 
mbMainSeqChild);
+    // Put event triggered Audio time nodes to SubTnLst.
+    // Add other types of nodes once we find more test cases.
+    mbOnSubTnLst = initCondList(getNodeForCondition()->getBegin(), 
maBeginCondList, mbMainSeqChild)
+                   && mxNode->getType() == AnimationNodeType::AUDIO;
 
     initCondList(getNodeForCondition()->getEnd(), maEndCondList, 
mbMainSeqChild);
 }
diff --git a/sd/source/filter/eppt/pptx-animations-nodectx.hxx 
b/sd/source/filter/eppt/pptx-animations-nodectx.hxx
index e9f884063c2e..5e3ac0010602 100644
--- a/sd/source/filter/eppt/pptx-animations-nodectx.hxx
+++ b/sd/source/filter/eppt/pptx-animations-nodectx.hxx
@@ -30,6 +30,9 @@ class NodeContext
     // if the node has valid target or contains at least one valid target.
     bool mbValid;
 
+    // if the node should be on SubTnLst or ChildTnLst
+    bool mbOnSubTnLst;
+
     // Attributes initialized from mxNode->getUserData().
     sal_Int16 mnEffectNodeType;
     sal_Int16 mnEffectPresetClass;
@@ -56,6 +59,7 @@ public:
     const OUString& getEffectPresetId() const { return msEffectPresetId; }
     const OUString& getEffectPresetSubType() const { return 
msEffectPresetSubType; }
     bool isValid() const { return mbValid; }
+    bool isOnSubTnLst() const { return mbOnSubTnLst; }
     const std::vector<NodeContextPtr>& getChildNodes() const { return 
maChildNodes; };
     const css::uno::Reference<css::animations::XAnimationNode>& 
getNodeForCondition() const;
     const std::vector<Cond>& getBeginCondList() const { return 
maBeginCondList; }
diff --git a/sd/source/filter/eppt/pptx-animations.cxx 
b/sd/source/filter/eppt/pptx-animations.cxx
index 0cb6a5c72319..1effa82a9ab8 100644
--- a/sd/source/filter/eppt/pptx-animations.cxx
+++ b/sd/source/filter/eppt/pptx-animations.cxx
@@ -943,13 +943,30 @@ void 
PPTXAnimationExport::WriteAnimationNodeCommonPropsStart()
     const std::vector<NodeContextPtr>& aChildNodes = 
mpContext->getChildNodes();
     if (!aChildNodes.empty())
     {
+        bool bSubTnLst = false;
         mpFS->startElementNS(XML_p, XML_childTnLst);
         for (const NodeContextPtr& pChildContext : aChildNodes)
         {
             if (pChildContext->isValid())
-                WriteAnimationNode(pChildContext);
+            {
+                if (pChildContext->isOnSubTnLst())
+                    bSubTnLst = true;
+                else
+                    WriteAnimationNode(pChildContext);
+            }
         }
         mpFS->endElementNS(XML_p, XML_childTnLst);
+
+        if (bSubTnLst)
+        {
+            mpFS->startElementNS(XML_p, XML_subTnLst);
+            for (const NodeContextPtr& pChildContext : aChildNodes)
+            {
+                if (pChildContext->isValid() && pChildContext->isOnSubTnLst())
+                    WriteAnimationNode(pChildContext);
+            }
+            mpFS->endElementNS(XML_p, XML_subTnLst);
+        }
     }
     mpFS->endElementNS(XML_p, XML_cTn);
 }

Reply via email to