sw/qa/filter/ww8/ww8.cxx                     |   31 +++++++++++++++++++++++++
 sw/source/filter/ww8/attributeoutputbase.hxx |    2 -
 sw/source/filter/ww8/docxattributeoutput.cxx |   33 ++++++++++++++++++---------
 sw/source/filter/ww8/docxattributeoutput.hxx |    2 -
 sw/source/filter/ww8/rtfattributeoutput.cxx  |    3 +-
 sw/source/filter/ww8/rtfattributeoutput.hxx  |    3 +-
 sw/source/filter/ww8/wrtw8nds.cxx            |   31 ++++++++++++++++++++++---
 sw/source/filter/ww8/ww8atr.cxx              |    2 -
 sw/source/filter/ww8/ww8attributeoutput.hxx  |    2 -
 9 files changed, 89 insertions(+), 20 deletions(-)

New commits:
commit 59d35122eea485b56fb1f89625fffd85bac741a0
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Tue Nov 29 10:09:10 2022 +0100
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Sun Dec 4 09:30:19 2022 +0000

    docx: export symbol characters correctly
    
    Previously we had:
    after save: <w:t></w:t>
    original content: <w:sym w:font="Wingdings" w:char="F0E0"/>
    
    This patch checks if paragraph has symbol font used and exports
    content using w:sym mark in that case
    
    Change-Id: I74f4bb0d249cbf5dfc930e931f7d91bd0d2e9821
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143455
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx
index 44ef994bf412..7dcb337cd413 100644
--- a/sw/qa/filter/ww8/ww8.cxx
+++ b/sw/qa/filter/ww8/ww8.cxx
@@ -9,6 +9,7 @@
 
 #include <swmodeltestbase.hxx>
 
+#include <com/sun/star/awt/CharSet.hpp>
 #include <com/sun/star/text/XTextDocument.hpp>
 
 #include <docsh.hxx>
@@ -114,6 +115,36 @@ CPPUNIT_TEST_FIXTURE(Test, testDocxHyperlinkShape)
     // assertion failure for not-well-formed XML output):
     save("Office Open XML Text", maTempFile);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testDocxSymbolFontExport)
+{
+    // Create document with symbol character and font Wingdings
+    mxComponent = loadFromDesktop("private:factory/swriter");
+    uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+    uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+
+    xText->insertString(xCursor, u"", true);
+
+    uno::Reference<text::XTextRange> xRange = xCursor;
+    uno::Reference<beans::XPropertySet> xTextProps(xRange, uno::UNO_QUERY);
+    xTextProps->setPropertyValue("CharFontName", 
uno::Any(OUString("Wingdings")));
+    xTextProps->setPropertyValue("CharFontNameAsian", 
uno::Any(OUString("Wingdings")));
+    xTextProps->setPropertyValue("CharFontNameComplex", 
uno::Any(OUString("Wingdings")));
+    xTextProps->setPropertyValue("CharFontCharSet", 
uno::Any(awt::CharSet::SYMBOL));
+
+    // When exporting to DOCX:
+    save("Office Open XML Text", maTempFile);
+    mbExported = true;
+
+    // Then make sure the expected markup is used:
+    xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+
+    assertXPath(pXmlDoc, "//w:p/w:r/w:sym", 1);
+    assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "font", "Wingdings");
+    assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "char", "f0e0");
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx 
b/sw/source/filter/ww8/attributeoutputbase.hxx
index ffa81eb161fd..7e415a50a118 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -190,7 +190,7 @@ public:
     virtual void WritePostitFieldReference() {};
 
     /// Output text (inside a run).
-    virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = 
RTL_TEXTENCODING_UTF8 ) = 0;
+    virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = 
RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) = 0;
 
     /// Output text (without markup).
     virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) = 0;
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 506f62328947..9c8bd63a945f 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -3397,7 +3397,8 @@ bool DocxAttributeOutput::FootnoteEndnoteRefTag()
     the switch in DocxAttributeOutput::RunText() nicer ;-)
  */
 static bool impl_WriteRunText( FSHelperPtr const & pSerializer, sal_Int32 
nTextToken,
-        const sal_Unicode* &rBegin, const sal_Unicode* pEnd, bool bMove = true 
)
+        const sal_Unicode* &rBegin, const sal_Unicode* pEnd, bool bMove = true,
+        const OUString& rSymbolFont = OUString() )
 {
     const sal_Unicode *pBegin = rBegin;
 
@@ -3408,22 +3409,34 @@ static bool impl_WriteRunText( FSHelperPtr const & 
pSerializer, sal_Int32 nTextT
     if ( pBegin >= pEnd )
         return false; // we want to write at least one character
 
-    // we have to add 'preserve' when starting/ending with space
-    if ( *pBegin == ' ' || *( pEnd - 1 ) == ' ' )
+    bool bIsSymbol = !rSymbolFont.isEmpty();
+
+    std::u16string_view aView( pBegin, pEnd - pBegin );
+    if (bIsSymbol)
     {
-        pSerializer->startElementNS(XML_w, nTextToken, FSNS(XML_xml, 
XML_space), "preserve");
+        for (char16_t aChar : aView)
+        {
+            pSerializer->singleElementNS(XML_w, XML_sym,
+                FSNS(XML_w, XML_font), rSymbolFont,
+                FSNS(XML_w, XML_char), OString::number(aChar, 16));
+        }
     }
     else
-        pSerializer->startElementNS(XML_w, nTextToken);
-
-    pSerializer->writeEscaped( std::u16string_view( pBegin, pEnd - pBegin ) );
+    {
+        // we have to add 'preserve' when starting/ending with space
+        if ( *pBegin == ' ' || *( pEnd - 1 ) == ' ' )
+            pSerializer->startElementNS(XML_w, nTextToken, FSNS(XML_xml, 
XML_space), "preserve");
+        else
+            pSerializer->startElementNS(XML_w, nTextToken);
 
-    pSerializer->endElementNS( XML_w, nTextToken );
+        pSerializer->writeEscaped( aView );
+        pSerializer->endElementNS( XML_w, nTextToken );
+    }
 
     return true;
 }
 
-void DocxAttributeOutput::RunText( const OUString& rText, rtl_TextEncoding 
/*eCharSet*/ )
+void DocxAttributeOutput::RunText( const OUString& rText, rtl_TextEncoding 
/*eCharSet*/, const OUString& rSymbolFont )
 {
     if( m_closeHyperlinkInThisRun )
     {
@@ -3483,7 +3496,7 @@ void DocxAttributeOutput::RunText( const OUString& rText, 
rtl_TextEncoding /*eCh
         }
     }
 
-    impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pEnd, false );
+    impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pEnd, false, 
rSymbolFont );
 }
 
 void DocxAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding 
/*eCharSet*/)
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx 
b/sw/source/filter/ww8/docxattributeoutput.hxx
index 05762793a3fc..262da0cc0051 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -200,7 +200,7 @@ public:
     virtual void WritePostitFieldReference() override;
 
     /// Output text (inside a run).
-    virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = 
RTL_TEXTENCODING_UTF8 ) override;
+    virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = 
RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) override;
 
     /// Output text (without markup).
     virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) 
override;
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 6a859f4f0b87..814f7c949a22 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -502,7 +502,8 @@ OString RtfAttributeOutput::MoveCharacterProperties(bool 
aAutoWriteRtlLtr)
     return aBuf.makeStringAndClear();
 }
 
-void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding 
/*eCharSet*/)
+void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding 
/*eCharSet*/,
+                                 const OUString& /*rSymbolFont*/)
 {
     SAL_INFO("sw.rtf", __func__ << ", rText: " << rText);
     RawText(rText, m_rExport.GetCurrentEncoding());
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx 
b/sw/source/filter/ww8/rtfattributeoutput.hxx
index e5f53fa4d355..d7956ed3a1e2 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -84,7 +84,8 @@ public:
     void EndRunProperties(const SwRedlineData* pRedlineData) override;
 
     /// Output text (inside a run).
-    void RunText(const OUString& rText, rtl_TextEncoding eCharSet = 
RTL_TEXTENCODING_UTF8) override;
+    void RunText(const OUString& rText, rtl_TextEncoding eCharSet = 
RTL_TEXTENCODING_UTF8,
+                 const OUString& rSymbolFont = OUString()) override;
 
     // Access to (anyway) private buffers, used by the sdr exporter
     OStringBuffer& RunText();
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx 
b/sw/source/filter/ww8/wrtw8nds.cxx
index 423b8dc3ee81..89fe95801f85 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -2241,6 +2241,23 @@ bool MSWordExportBase::NeedTextNodeSplit( const 
SwTextNode& rNd, SwSoftPageBreak
     return pList.size() > 2 && NeedSectionBreak( rNd );
 }
 
+OUString lcl_GetSymbolFont(SwAttrPool& rPool, const SwTextNode* pTextNode, int 
nStart, int nEnd)
+{
+    SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONT> aSet( rPool );
+    if ( pTextNode && pTextNode->GetParaAttr(aSet, nStart, nEnd) )
+    {
+        SfxPoolItem const* pPoolItem = aSet.GetItem(RES_CHRATR_FONT);
+        if (pPoolItem)
+        {
+            const SvxFontItem* pFontItem = static_cast<const 
SvxFontItem*>(pPoolItem);
+            if (pFontItem->GetCharSet() == RTL_TEXTENCODING_SYMBOL)
+                return pFontItem->GetFamilyName();
+        }
+    }
+
+    return OUString();
+}
+
 void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
 {
     SAL_INFO( "sw.ww8", "<OutWW8_SwTextNode>" );
@@ -2460,6 +2477,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
             bool bTextAtr = aAttrIter.IsTextAttr( nCurrentPos );
             nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, 
nCurrentPos );
 
+            OUString aSymbolFont;
             sal_Int32 nLen = nNextAttr - nCurrentPos;
             if ( !bTextAtr && nLen )
             {
@@ -2626,12 +2644,13 @@ void MSWordExportBase::OutputTextNode( SwTextNode& 
rNode )
                 assert(0 <= nLen);
 
                 OUString aSnippet( aAttrIter.GetSnippet( aStr, nCurrentPos + 
ofs, nLen ) );
+                const SwTextNode* pTextNode( rNode.GetTextNode() );
                 if ( ( m_nTextTyp == TXT_EDN || m_nTextTyp == TXT_FTN ) && 
nCurrentPos == 0 && nLen > 0 )
                 {
                     // Allow MSO to emulate LO footnote text starting at left 
margin - only meaningful with hanging indent
                     sal_Int32 nFirstLineIndent=0;
                     SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE> aSet( 
m_rDoc.GetAttrPool() );
-                    const SwTextNode* pTextNode( rNode.GetTextNode() );
+
                     if ( pTextNode && pTextNode->GetAttr(aSet) )
                     {
                         const SvxLRSpaceItem* pLRSpace = 
aSet.GetItem<SvxLRSpaceItem>(RES_LR_SPACE);
@@ -2645,6 +2664,8 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
                     m_bAddFootnoteTab = false;
                 }
 
+                aSymbolFont = lcl_GetSymbolFont(m_rDoc.GetAttrPool(), 
pTextNode, nCurrentPos + ofs, nCurrentPos + ofs + nLen);
+
                 if ( bPostponeWritingText && ( FLY_POSTPONED != 
nStateOfFlyFrame ) )
                 {
                     aSavedSnippet = aSnippet ;
@@ -2652,7 +2673,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
                 else
                 {
                     bPostponeWritingText = false ;
-                    AttrOutput().RunText( aSnippet, eChrSet );
+                    AttrOutput().RunText( aSnippet, eChrSet, aSymbolFont );
                 }
 
                 if (ofs == 1 && nNextAttr == nEnd)
@@ -2776,6 +2797,8 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
 
             AttrOutput().WritePostitFieldReference();
 
+            aSymbolFont = lcl_GetSymbolFont(m_rDoc.GetAttrPool(), &rNode, 
nCurrentPos, nCurrentPos + nLen);
+
             if (bPostponeWritingText
                 && (FLY_PROCESSED == nStateOfFlyFrame || FLY_NONE == 
nStateOfFlyFrame))
             {
@@ -2790,13 +2813,13 @@ void MSWordExportBase::OutputTextNode( SwTextNode& 
rNode )
                     aAttrIter.OutAttr( nCurrentPos, false );
                     AttrOutput().EndRunProperties( pRedlineData );
                 }
-                AttrOutput().RunText( aSavedSnippet, eChrSet );
+                AttrOutput().RunText( aSavedSnippet, eChrSet, aSymbolFont );
                 AttrOutput().EndRun(&rNode, nCurrentPos, nLen, nNextAttr == 
nEnd);
             }
             else if( bPostponeWritingText && !aSavedSnippet.isEmpty() )
             {
                 //write the postponed text run
-                AttrOutput().RunText( aSavedSnippet, eChrSet );
+                AttrOutput().RunText( aSavedSnippet, eChrSet, aSymbolFont );
                 AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
             }
             else
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index ed1da4c90f4a..b406a1149150 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -1121,7 +1121,7 @@ void WW8AttributeOutput::EndRunProperties( const 
SwRedlineData* pRedlineData )
     m_rWW8Export.pO->clear();
 }
 
-void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding 
eCharSet )
+void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding 
eCharSet, const OUString& /*rSymbolFont*/ )
 {
     RawText(rText, eCharSet);
 }
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx 
b/sw/source/filter/ww8/ww8attributeoutput.hxx
index f15bfe07aa52..496245663b92 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -67,7 +67,7 @@ public:
     virtual void EndRunProperties( const SwRedlineData* pRedlineData ) 
override;
 
     /// Output text.
-    virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = 
RTL_TEXTENCODING_UTF8 ) override;
+    virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = 
RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) override;
 
     /// Output text (without markup).
     virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) 
override;

Reply via email to