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;

Reply via email to