sw/source/filter/ww8/attributeoutputbase.hxx | 2 +- sw/source/filter/ww8/docxattributeoutput.cxx | 2 +- sw/source/filter/ww8/docxattributeoutput.hxx | 2 +- sw/source/filter/ww8/rtfattributeoutput.cxx | 22 +++++++++++++++++----- sw/source/filter/ww8/rtfattributeoutput.hxx | 4 +++- sw/source/filter/ww8/wrtw8nds.cxx | 6 +++--- sw/source/filter/ww8/ww8attributeoutput.hxx | 2 +- 7 files changed, 27 insertions(+), 13 deletions(-)
New commits: commit de18b0a49df79ac0f03abd7a953eae850fa58b3a Author: Caolán McNamara <caolan.mcnam...@collabora.com> AuthorDate: Sun Apr 13 17:30:42 2025 +0100 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Sun Apr 13 22:37:50 2025 +0200 crashtesting: tdf107209-1.odt exported to rtf cannot be loaded probably since: commit 326388da4e40c85f8a1af40264aaf56c7845e224 CommitDate: Tue Dec 29 13:55:41 2020 +0100 tdf#138779 do not call EndRun() in StartRuby() There is ruby text in this doc which doesn't span any base text so there isn't a run to close it. If there are two of these empty rubys in a paragraph the tags get noticibly mangled. <text:p text:style-name="Text_20_body"> て栄繁あとうも陸爛誇え大て折ほつころ<text:ruby text:style-name="Ru1"> <text:ruby-base/> <text:ruby-text> けんらん</text:ruby-text> </text:ruby> なも大草みよだ生舗よぬ雑うば物ばほ路っ作あ足通法し相いしこら様がつば有が<text:ruby text:style-name="Ru1"> <text:ruby-base/> <text:ruby-text> ふさわ</text:ruby-text> </text:ruby> </text:p> Change-Id: I4befe041e778c67f7f9fc7f1510b0a73a8b35d2d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184122 Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx index fa679b05b835..36027ee65ef7 100644 --- a/sw/source/filter/ww8/attributeoutputbase.hxx +++ b/sw/source/filter/ww8/attributeoutputbase.hxx @@ -200,7 +200,7 @@ public: virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) = 0; /// Output ruby end. - virtual void EndRuby( const SwTextNode& rNode, sal_Int32 nPos ) = 0; + virtual void EndRuby( const SwTextNode& rNode, sal_Int32 nPos, bool bEmptyBaseText ) = 0; /// Output URL start. virtual bool StartURL(const OUString& rUrl, const OUString& rTarget, const OUString& rName = OUString()) = 0; diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index dbe130232192..c9f14ef59c82 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -3994,7 +3994,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, co StartRun( nullptr, nPos ); } -void DocxAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos) +void DocxAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos, bool /*bEmptyBaseText*/) { SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::EndRuby()" ); EndRun( &rNode, nPos, -1 ); diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 3bd1544003a1..690900b8962f 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -250,7 +250,7 @@ public: virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) override; /// Output ruby end. - virtual void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override; + virtual void EndRuby(const SwTextNode& rNode, sal_Int32 nPos, bool bEmptyBaseText) override; /// Output URL start. virtual bool StartURL( const OUString& rUrl, const OUString& rTarget, const OUString& rName = OUString() ) override; diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index 2116951c5a2e..944be6f7a531 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -420,6 +420,13 @@ void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, sal_Int32 / OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty"); } +void RtfAttributeOutput::EndRubyField() +{ + assert(m_bInRuby); + m_aRun->append(")}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {}}}"); + m_bInRuby = false; +} + void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, sal_Int32 /*nLen*/, bool /*bLastRun*/) { @@ -427,10 +434,7 @@ void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, m_aRun.appendAndClear(m_aRunText); if (m_bInRuby) - { - m_aRun->append(")}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {}}}"); - m_bInRuby = false; - } + EndRubyField(); if (!m_bSingleEmptyRun && m_bInRun) m_aRun->append('}'); @@ -533,6 +537,7 @@ void RtfAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding eCharSe void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/, const SwFormatRuby& rRuby) { + assert(!m_bInRuby); WW8Ruby aWW8Ruby(rNode, rRuby, GetExport()); OUString aStr = FieldString(ww::eEQ) + "\* jc" + OUString::number(aWW8Ruby.GetJC()) + " \* \"Font:" + aWW8Ruby.GetFontFamily() + "\" \* hps" @@ -548,7 +553,14 @@ void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/, m_bInRuby = true; } -void RtfAttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/) {} +void RtfAttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/, + bool bEmptyBaseText) +{ + // If there is no base text that the Ruby spans then just end this now and don't attempt to postpone + // until the output of the non-existent run + if (bEmptyBaseText) + EndRubyField(); +} bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget, const OUString& /*rName*/) diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx index 3fa9e2dbb8e1..8ecb8d3e6a14 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.hxx +++ b/sw/source/filter/ww8/rtfattributeoutput.hxx @@ -100,7 +100,7 @@ public: void StartRuby(const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby) override; /// Output ruby end. - void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override; + void EndRuby(const SwTextNode& rNode, sal_Int32 nPos, bool bEmptyBaseText) override; /// Output URL start. bool StartURL(const OUString& rUrl, const OUString& rTarget, @@ -524,6 +524,8 @@ private: void WriteTextFootnoteNumStr(const SwFormatFootnote& rFootnote); + void EndRubyField(); + /* * Current style name and its ID. */ diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 646ed67a955f..bd400581e25d 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -1031,7 +1031,7 @@ void WW8AttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 /*nPos*/, FieldFlags::Start | FieldFlags::CmdStart ); } -void WW8AttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/) +void WW8AttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/, bool /*bEmptyBaseText*/) { m_rWW8Export.WriteChar( ')' ); m_rWW8Export.OutputField( nullptr, ww::eEQ, OUString(), FieldFlags::End | FieldFlags::Close ); @@ -1478,7 +1478,7 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos) pEnd = pHt->End(); if (nPos == *pEnd && nPos != pHt->GetStart()) { - m_rExport.AttrOutput().EndRuby(rNode, nPos); + m_rExport.AttrOutput().EndRuby(rNode, nPos, false); --nRet; } break; @@ -1532,7 +1532,7 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos) pEnd = pHt->End(); if (nPos == *pEnd && nPos == pHt->GetStart()) { // special case: empty must be handled here - m_rExport.AttrOutput().EndRuby( m_rNode, nPos ); + m_rExport.AttrOutput().EndRuby(m_rNode, nPos, true); --nRet; } break; diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx index 2464402676f3..cad132763226 100644 --- a/sw/source/filter/ww8/ww8attributeoutput.hxx +++ b/sw/source/filter/ww8/ww8attributeoutput.hxx @@ -76,7 +76,7 @@ public: virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) override; /// Output ruby end. - virtual void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override; + virtual void EndRuby(const SwTextNode& rNode, sal_Int32 nPos, bool bEmptyBaseText) override; /// Output URL start. virtual bool StartURL(const OUString& rUrl, const OUString& rTarget, const OUString& rName = OUString()) override;