Kaydet (Commit) 612db687 authored tarafından Mark Hung's avatar Mark Hung

tdf#99213: don't export invalid child nodes.

Create NodeContext for all child nodes at beginning and
check if they are valid, either it has a valid target or
it contains valid nodes, so that we only export valid
node later.

Change-Id: I660d99011eb57ddc79f727455fce0be8876e8b17
Reviewed-on: https://gerrit.libreoffice.org/59892
Tested-by: Jenkins
Reviewed-by: 's avatarMark Hung <marklh9@gmail.com>
üst c3c43c79
...@@ -193,6 +193,7 @@ public: ...@@ -193,6 +193,7 @@ public:
void testTdf116350TextEffects(); void testTdf116350TextEffects();
void testTdf118825(); void testTdf118825();
void testTdf119118(); void testTdf119118();
void testTdf99213();
CPPUNIT_TEST_SUITE(SdOOXMLExportTest2); CPPUNIT_TEST_SUITE(SdOOXMLExportTest2);
...@@ -269,6 +270,7 @@ public: ...@@ -269,6 +270,7 @@ public:
CPPUNIT_TEST(testTdf116350TextEffects); CPPUNIT_TEST(testTdf116350TextEffects);
CPPUNIT_TEST(testTdf118825); CPPUNIT_TEST(testTdf118825);
CPPUNIT_TEST(testTdf119118); CPPUNIT_TEST(testTdf119118);
CPPUNIT_TEST(testTdf99213);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
...@@ -1987,6 +1989,19 @@ void SdOOXMLExportTest2::testTdf119118() ...@@ -1987,6 +1989,19 @@ void SdOOXMLExportTest2::testTdf119118()
xDocShRef->DoClose(); xDocShRef->DoClose();
} }
void SdOOXMLExportTest2::testTdf99213()
{
::sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc( "sd/qa/unit/data/odp/tdf99213-target-missing.odp" ), ODP);
utl::TempFile tempFile;
xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
xmlDocPtr pXmlDocContent = parseExport(tempFile, "ppt/slides/slide1.xml");
// Number of nodes with p:attrNameLst was 3, including one that missed tgtEl
assertXPath(pXmlDocContent, "//p:attrNameLst", 2);
// Timenode that miss its target element should be filtered.
assertXPath(pXmlDocContent, "//p:attrNameLst/preceding-sibling::p:tgtEl", 2);
xDocShRef->DoClose();
}
CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest2); CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest2);
CPPUNIT_PLUGIN_IMPLEMENT(); CPPUNIT_PLUGIN_IMPLEMENT();
......
...@@ -410,6 +410,21 @@ void WriteAnimationAttributeName(const FSHelperPtr& pFS, const OUString& rAttrib ...@@ -410,6 +410,21 @@ void WriteAnimationAttributeName(const FSHelperPtr& pFS, const OUString& rAttrib
pFS->endElementNS(XML_p, XML_attrNameLst); pFS->endElementNS(XML_p, XML_attrNameLst);
} }
bool isValidTarget(const Any& rTarget)
{
Reference<XShape> xShape;
if ((rTarget >>= xShape) && xShape.is())
return true;
ParagraphTarget aParagraphTarget;
if ((rTarget >>= aParagraphTarget) && aParagraphTarget.Shape.is())
return true;
return false;
}
/// convert animation node type to corresponding ooxml element. /// convert animation node type to corresponding ooxml element.
sal_Int32 convertNodeType(sal_Int16 nType) sal_Int32 convertNodeType(sal_Int16 nType)
{ {
...@@ -575,9 +590,13 @@ typedef std::unique_ptr<NodeContext> NodeContextPtr; ...@@ -575,9 +590,13 @@ typedef std::unique_ptr<NodeContext> NodeContextPtr;
class NodeContext class NodeContext
{ {
const Reference<XAnimationNode>& mxNode; const Reference<XAnimationNode> mxNode;
const bool mbMainSeqChild; const bool mbMainSeqChild;
std::vector<NodeContextPtr> maChildNodes;
// if the node has valid target or contains at least one valid target.
bool mbValid;
// Attributes initialized from mxNode->getUserData(). // Attributes initialized from mxNode->getUserData().
sal_Int16 mnEffectNodeType; sal_Int16 mnEffectNodeType;
sal_Int16 mnEffectPresetClass; sal_Int16 mnEffectPresetClass;
...@@ -587,14 +606,23 @@ class NodeContext ...@@ -587,14 +606,23 @@ class NodeContext
/// constructor helper for initializing user datas. /// constructor helper for initializing user datas.
void initUserData(); void initUserData();
/// constructor helper to initialize maChildNodes.
/// return true if at least one childnode is valid.
bool initChildNodes();
/// constructor helper to initialize mbValid
void initValid(bool bHasValidChild, bool bIsIterateChild);
public: public:
NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild); NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild, bool bIsIterateChild);
const Reference<XAnimationNode>& getNode() const { return mxNode; } const Reference<XAnimationNode>& getNode() const { return mxNode; }
bool isMainSeqChild() const { return mbMainSeqChild; } bool isMainSeqChild() const { return mbMainSeqChild; }
sal_Int16 getEffectNodeType() const { return mnEffectNodeType; } sal_Int16 getEffectNodeType() const { return mnEffectNodeType; }
sal_Int16 getEffectPresetClass() const { return mnEffectPresetClass; } sal_Int16 getEffectPresetClass() const { return mnEffectPresetClass; }
const OUString& getEffectPresetId() const { return msEffectPresetId; } const OUString& getEffectPresetId() const { return msEffectPresetId; }
const OUString& getEffectPresetSubType() const { return msEffectPresetSubType; } const OUString& getEffectPresetSubType() const { return msEffectPresetSubType; }
bool isValid() const { return mbValid; }
const std::vector<NodeContextPtr>& getChildNodes() const { return maChildNodes; };
}; };
class PPTXAnimationExport class PPTXAnimationExport
...@@ -1014,34 +1042,17 @@ void PPTXAnimationExport::WriteAnimationNodeCommonPropsStart() ...@@ -1014,34 +1042,17 @@ void PPTXAnimationExport::WriteAnimationNodeCommonPropsStart()
} }
} }
Reference<XEnumerationAccess> xEnumerationAccess(rXNode, UNO_QUERY); const std::vector<NodeContextPtr>& aChildNodes = mpContext->getChildNodes();
if (xEnumerationAccess.is()) if (!aChildNodes.empty())
{ {
Reference<XEnumeration> xEnumeration(xEnumerationAccess->createEnumeration(), UNO_QUERY); mpFS->startElementNS(XML_p, XML_childTnLst, FSEND);
if (xEnumeration.is()) for (const NodeContextPtr& pChildContext : aChildNodes)
{ {
SAL_INFO("sd.eppt", "-----"); if (pChildContext->isValid())
WriteAnimationNode(pChildContext);
if (xEnumeration->hasMoreElements())
{
mpFS->startElementNS(XML_p, XML_childTnLst, FSEND);
do
{
Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
if (xChildNode.is())
{
WriteAnimationNode(o3tl::make_unique<NodeContext>(
xChildNode, nType == EffectNodeType::MAIN_SEQUENCE));
}
} while (xEnumeration->hasMoreElements());
mpFS->endElementNS(XML_p, XML_childTnLst);
}
SAL_INFO("sd.eppt", "-----");
} }
mpFS->endElementNS(XML_p, XML_childTnLst);
} }
mpFS->endElementNS(XML_p, XML_cTn); mpFS->endElementNS(XML_p, XML_cTn);
} }
...@@ -1190,26 +1201,36 @@ void PPTXAnimationExport::WriteAnimations(const Reference<XDrawPage>& rXDrawPage ...@@ -1190,26 +1201,36 @@ void PPTXAnimationExport::WriteAnimations(const Reference<XDrawPage>& rXDrawPage
UNO_QUERY); UNO_QUERY);
if (xEnumeration.is() && xEnumeration->hasMoreElements()) if (xEnumeration.is() && xEnumeration->hasMoreElements())
{ {
mpFS->startElementNS(XML_p, XML_timing, FSEND); auto pNodeContext = o3tl::make_unique<NodeContext>(xNode, false, false);
mpFS->startElementNS(XML_p, XML_tnLst, FSEND); if (pNodeContext->isValid())
{
mpFS->startElementNS(XML_p, XML_timing, FSEND);
mpFS->startElementNS(XML_p, XML_tnLst, FSEND);
WriteAnimationNode(o3tl::make_unique<NodeContext>(xNode, false)); WriteAnimationNode(pNodeContext);
mpFS->endElementNS(XML_p, XML_tnLst); mpFS->endElementNS(XML_p, XML_tnLst);
mpFS->endElementNS(XML_p, XML_timing); mpFS->endElementNS(XML_p, XML_timing);
}
} }
} }
} }
} }
} }
NodeContext::NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild) NodeContext::NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild,
bool bIsIterateChild)
: mxNode(xNode) : mxNode(xNode)
, mbMainSeqChild(bMainSeqChild) , mbMainSeqChild(bMainSeqChild)
, mbValid(true)
, mnEffectNodeType(-1) , mnEffectNodeType(-1)
, mnEffectPresetClass(DFF_ANIM_PRESS_CLASS_USER_DEFINED) , mnEffectPresetClass(DFF_ANIM_PRESS_CLASS_USER_DEFINED)
{ {
assert(xNode.is());
initUserData(); initUserData();
initValid(initChildNodes(), bIsIterateChild);
} }
void NodeContext::initUserData() void NodeContext::initUserData()
...@@ -1237,4 +1258,62 @@ void NodeContext::initUserData() ...@@ -1237,4 +1258,62 @@ void NodeContext::initUserData()
*pAny >>= msEffectPresetSubType; *pAny >>= msEffectPresetSubType;
} }
void NodeContext::initValid(bool bHasValidChild, bool bIsIterateChild)
{
sal_Int16 nType = mxNode->getType();
if (nType == AnimationNodeType::ITERATE)
{
Reference<XIterateContainer> xIterate(mxNode, UNO_QUERY);
mbValid = xIterate.is() && (bIsIterateChild || isValidTarget(xIterate->getTarget()))
&& maChildNodes.size();
}
else if (nType == AnimationNodeType::COMMAND)
{
Reference<XCommand> xCommand(mxNode, UNO_QUERY);
mbValid = xCommand.is() && (bIsIterateChild || isValidTarget(xCommand->getTarget()));
}
else if (nType == AnimationNodeType::PAR || nType == AnimationNodeType::SEQ)
{
mbValid = bHasValidChild;
}
else if (nType == AnimationNodeType::AUDIO)
{
SAL_WARN("sd.eppt", "Export AUDIO node is not supported yet.");
mbValid = false;
}
else
{
Reference<XAnimate> xAnimate(mxNode, UNO_QUERY);
mbValid = xAnimate.is() && (bIsIterateChild || isValidTarget(xAnimate->getTarget()));
}
}
bool NodeContext::initChildNodes()
{
bool bValid = false;
Reference<XEnumerationAccess> xEnumerationAccess(mxNode, UNO_QUERY);
if (xEnumerationAccess.is())
{
Reference<XEnumeration> xEnumeration(xEnumerationAccess->createEnumeration(), UNO_QUERY);
bool bIsMainSeq = mnEffectNodeType == EffectNodeType::MAIN_SEQUENCE;
bool bIsIterateChild = mxNode->getType() == AnimationNodeType::ITERATE;
if (xEnumeration.is())
{
while (xEnumeration->hasMoreElements())
{
Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
if (xChildNode.is())
{
auto pChildContext
= o3tl::make_unique<NodeContext>(xChildNode, bIsMainSeq, bIsIterateChild);
if (pChildContext->isValid())
bValid = true;
maChildNodes.push_back(std::move(pChildContext));
}
}
}
}
return bValid;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment