sw/source/core/unocore/unoframe.cxx | 7 +++++++ xmloff/source/text/txtparae.cxx | 31 ++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-)
New commits: commit 801debfc365b4c5e6bf63324aaef82f449ddb443 Author: Mike Kaganski <[email protected]> AuthorDate: Mon Jun 16 12:37:30 2025 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Jun 16 13:36:41 2025 +0200 tdf#167033: allow double processing of Writer shapes' text frame nodes It turns out, that these are naturally processed twice. When enumerating paragraph's content, CollectFrameAtNode would find both the shape and the shape's text frame anchored to the paragraph node. Then, XMLTextParagraphExport::exportTextContentEnumeration will process the shape; and in XMLShapeExport::collectShapeAutoStyles, the shape will be queried for XText, which will return the text frame, which will then be processed. And finally, XMLTextParagraphExport::exportTextContentEnumeration will process the text frame, for the second time - at which point, the frame's paragraphs will be processed again. I don't know if it's possible to avoid the repeated processing; here I only add a debug check for this, and skip adding duplicate node index. Change-Id: I84275f233554a6b4923ddaabc336bec7a94ec2fa Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186546 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/sw/source/core/unocore/unoframe.cxx b/sw/source/core/unocore/unoframe.cxx index a5c4fb9cf86b..32651e47bf08 100644 --- a/sw/source/core/unocore/unoframe.cxx +++ b/sw/source/core/unocore/unoframe.cxx @@ -3339,6 +3339,13 @@ uno::Reference<container::XNameReplace > SAL_CALL SwXTextFrame::getEvents() if(!IsDescriptor()) aRet = SwXText::getPropertyValue(rPropertyName); } +#ifndef NDEBUG + else if (rPropertyName == "DbgIsShapesTextFrame") + { + aRet <<= SwTextBoxHelper::isTextBox(GetFrameFormat(), RES_FLYFRMFMT) + || SwTextBoxHelper::isTextBox(GetFrameFormat(), RES_DRAWFRMFMT); + } +#endif else aRet = SwXFrame::getPropertyValue(rPropertyName); return aRet; diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx index 1d02d84964d2..3ac362785ad5 100644 --- a/xmloff/source/text/txtparae.cxx +++ b/xmloff/source/text/txtparae.cxx @@ -1772,6 +1772,30 @@ bool XMLTextParagraphExport::ExportListId() const && GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012; } +#ifndef NDEBUG +static bool isInShapesTextFrame(const css::uno::Reference<css::text::XTextContent>& xTextContent) +{ + auto xTextRange = xTextContent.query<css::text::XTextRange>(); + if (!xTextRange) + return false; + auto xParentTextProps = xTextRange->getText().query<css::beans::XPropertySet>(); + if (!xParentTextProps) + return false; + try + { + // see SwXTextFrame::getEvents + css::uno::Any ret = xParentTextProps->getPropertyValue(u"DbgIsShapesTextFrame"_ustr); + if (bool result; ret >>= result) + return result; + return false; + } + catch (css::beans::UnknownPropertyException&) + { + return false; + } +} +#endif + void XMLTextParagraphExport::RecordNodeIndex(const css::uno::Reference<css::text::XTextContent>& xTextContent) { if (!bInDocumentNodeOrderCollection) @@ -1783,9 +1807,10 @@ void XMLTextParagraphExport::RecordNodeIndex(const css::uno::Reference<css::text sal_Int32 index = 0; // See SwXParagraph::Impl::GetPropertyValues_Impl xPropSet->getPropertyValue(u"ODFExport_NodeIndex"_ustr) >>= index; - assert(std::find(maDocumentNodeOrder.begin(), maDocumentNodeOrder.end(), index) - == maDocumentNodeOrder.end()); - maDocumentNodeOrder.push_back(index); + auto it = std::find(maDocumentNodeOrder.begin(), maDocumentNodeOrder.end(), index); + assert(it == maDocumentNodeOrder.end() || isInShapesTextFrame(xTextContent)); + if (it == maDocumentNodeOrder.end()) + maDocumentNodeOrder.push_back(index); } catch (css::beans::UnknownPropertyException&) {
