[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - sw/qa sw/source

Serge Krot Serge.Krot at cib.de
Mon Nov 6 12:59:15 UTC 2017


 sw/qa/extras/ooxmlexport/data/tdf38778_properties_in_run_for_field.doc |binary
 sw/qa/extras/ooxmlexport/ooxmlexport4.cxx                              |   67 +++
 sw/qa/extras/ww8export/data/tdf38778_properties_in_run_for_field.doc   |binary
 sw/qa/extras/ww8export/ww8export.cxx                                   |    6 
 sw/source/filter/ww8/attributeoutputbase.hxx                           |    4 
 sw/source/filter/ww8/docxattributeoutput.cxx                           |  209 +++++++---
 sw/source/filter/ww8/docxattributeoutput.hxx                           |   12 
 sw/source/filter/ww8/docxexport.cxx                                    |    4 
 sw/source/filter/ww8/rtfattributeoutput.cxx                            |   10 
 sw/source/filter/ww8/rtfattributeoutput.hxx                            |    4 
 sw/source/filter/ww8/wrtw8nds.cxx                                      |   37 +
 sw/source/filter/ww8/wrtww8.hxx                                        |    4 
 sw/source/filter/ww8/ww8atr.cxx                                        |   14 
 sw/source/filter/ww8/ww8attributeoutput.hxx                            |    4 
 14 files changed, 295 insertions(+), 80 deletions(-)

New commits:
commit 37f9b0f50c82b985c7b1713240b628fa51cb7d02
Author: Serge Krot <Serge.Krot at cib.de>
Date:   Tue Oct 17 19:03:14 2017 +0200

    tdf#38778 fix missing run properties export for fields in docx
    
    Not all runs got their text properties written during field export -
    previously only the first run had them. Adds SwTextNode param to EndRun
    and EndRuby methods, implementation empty for rtf and doc though.
    
    Change-Id: I77f39b40689feb9664044e61824ad3bb97776638
    Reviewed-on: https://gerrit.libreoffice.org/43465
    Reviewed-by: Serge Krot (CIB) <Serge.Krot at cib.de>
    Tested-by: Serge Krot (CIB) <Serge.Krot at cib.de>
    
    tdf#38778 Added colors into run properties of field run
    
    During export into DOCX all runs inside fields should
    contain all character properties including character color.
    
    Change-Id: I2a7d4fc26f1e1de1080f51de84180a19794709a9
    Reviewed-on: https://gerrit.libreoffice.org/43723
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Serge Krot (CIB) <Serge.Krot at cib.de>
    
    related tdf#38778 Speed-up: Do not traverse the whole array
    
    It is known that text attributes are sorted inside SwpHints.
    No need to check all entries if special position is provided.
    
    Change-Id: Iac92cd40cd6d094d158f3b50fd768f47029ccdce
    Reviewed-on: https://gerrit.libreoffice.org/43911
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    
    tdf#38778 Fix output of the font in DOC run
    
    The font information should be output before field declaration.
    Added unit test.
    
    tdf#38778 DOCX output: no double output of the font info
    
    Change-Id: I147dd8956fbd8e69c3a2e86aff01dc249f4fa815
    a080f742cde88b914e146fe7a95b90bf1952c96a
    Reviewed-on: https://gerrit.libreoffice.org/44160
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Reviewed-on: https://gerrit.libreoffice.org/44359
    Tested-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf38778_properties_in_run_for_field.doc b/sw/qa/extras/ooxmlexport/data/tdf38778_properties_in_run_for_field.doc
new file mode 100644
index 000000000000..5f0f7238a153
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf38778_properties_in_run_for_field.doc differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
index 699cc0386f10..0fdfe003e161 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
@@ -671,6 +671,73 @@ DECLARE_OOXMLEXPORT_TEST(test_OpeningBrace, "2120112713_OpenBrace.docx")
     assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/m:oMath[1]/m:d[1]/m:dPr[1]/m:begChr[1]","val","");
 }
 
+// Checks that all runs of the field have text properties.
+// Old behaviour: only first run has text properties of the field
+//
+// There are several runs are used in fields:
+//     <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::StartRunProperties() / DocxAttributeOutput::EndRunProperties().
+//         </w:rPr>
+//         <w:fldChar w:fldCharType="begin" />
+//     </w:r>
+//         <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::DoWriteFieldRunProperties()
+//         </w:rPr>
+//         <w:instrText>TIME \@"HH:mm:ss"</w:instrText>
+//     </w:r>
+//     <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::DoWriteFieldRunProperties()
+//         </w:rPr>
+//         <w:fldChar w:fldCharType="separate" />
+//     </w:r>
+//     <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::DoWriteFieldRunProperties()
+//         </w:rPr>
+//         <w:t>14:01:13</w:t>
+//         </w:r>
+//     <w:r>
+//         <w:rPr>
+//             <!-- properties written with DocxAttributeOutput::DoWriteFieldRunProperties()
+//         </w:rPr>
+//         <w:fldChar w:fldCharType="end" />
+//     </w:r>
+// See, tdf#38778
+DECLARE_OOXMLEXPORT_TEST(testTdf38778, "tdf38778_properties_in_run_for_field.doc")
+{
+    xmlDocPtr pXmlDoc = parseExport("word/document.xml");
+    if (!pXmlDoc)
+        return;
+
+    const OUString psz("20");
+    const OUString pszCs("20");
+
+    // w:fldCharType="begin"
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[3]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[3]/w:rPr/w:szCs", "val", pszCs);
+
+    // PAGE
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[4]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[4]/w:rPr/w:szCs", "val", pszCs);
+    assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[4]/w:instrText",  " PAGE ");
+
+    // w:fldCharType="separate"
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[5]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[5]/w:rPr/w:szCs", "val", pszCs);
+
+    // field result: 1
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[6]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[6]/w:rPr/w:szCs", "val", pszCs);
+    assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[6]/w:t",          "1"); // field result
+
+    // w:fldCharType="end"
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[7]/w:rPr/w:sz",   "val", psz);
+    assertXPath(pXmlDoc,        "/w:document/w:body/w:p[1]/w:r[7]/w:rPr/w:szCs", "val", pszCs);
+}
+
 DECLARE_OOXMLEXPORT_TEST(testFDO76312, "FDO76312.docx")
 {
     xmlDocPtr pXmlDoc = parseExport("word/document.xml");
diff --git a/sw/qa/extras/ww8export/data/tdf38778_properties_in_run_for_field.doc b/sw/qa/extras/ww8export/data/tdf38778_properties_in_run_for_field.doc
new file mode 100644
index 000000000000..960fe50dae35
Binary files /dev/null and b/sw/qa/extras/ww8export/data/tdf38778_properties_in_run_for_field.doc differ
diff --git a/sw/qa/extras/ww8export/ww8export.cxx b/sw/qa/extras/ww8export/ww8export.cxx
index 24023a46f2cf..f31bbda02a06 100644
--- a/sw/qa/extras/ww8export/ww8export.cxx
+++ b/sw/qa/extras/ww8export/ww8export.cxx
@@ -88,6 +88,12 @@ protected:
     }
 };
 
+DECLARE_WW8EXPORT_TEST(testTdf38778, "tdf38778_properties_in_run_for_field.doc")
+{
+    CPPUNIT_ASSERT_EQUAL(10.0f, getProperty<float>(getRun(getParagraph(1), 1), "CharHeight"));
+    CPPUNIT_ASSERT_EQUAL(OUString("Courier New"), getProperty<OUString>(getRun(getParagraph(1), 1), "CharFontName"));
+}
+
 DECLARE_WW8EXPORT_TEST(testN325936, "n325936.doc")
 {
     /*
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx
index 092153ad0cbf..6e8c0ca0bb26 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -172,7 +172,7 @@ public:
     virtual void StartRun( const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false ) = 0;
 
     /// End of the text run.
-    virtual void EndRun() = 0;
+    virtual void EndRun( const SwTextNode* pNode, sal_Int32 nPos ) = 0;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() = 0;
@@ -199,7 +199,7 @@ public:
     virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) = 0;
 
     /// Output ruby end.
-    virtual void EndRuby() = 0;
+    virtual void EndRuby( const SwTextNode& rNode, sal_Int32 nPos ) = 0;
 
     /// Output URL start.
     virtual bool StartURL( const OUString& rUrl, const OUString& rTarget ) = 0;
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 2b245545583c..45c5ed84cbd3 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1116,7 +1116,7 @@ void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, bool /*bS
     m_pSerializer->mark(Tag_StartRun_3); // let's call it "postponed text"
 }
 
-void DocxAttributeOutput::EndRun()
+void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
 {
     int nFieldsInPrevHyperlink = m_nFieldsInHyperlink;
     // Reset m_nFieldsInHyperlink if a new hyperlink is about to start
@@ -1131,7 +1131,7 @@ void DocxAttributeOutput::EndRun()
         // Add the fields starts for all but hyperlinks and TOCs
         if ( pIt->bOpen && pIt->pField )
         {
-            StartField_Impl( *pIt );
+            StartField_Impl( pNode, nPos, *pIt );
 
             // Remove the field from the stack if only the start has to be written
             // Unknown fields should be removed too
@@ -1179,7 +1179,7 @@ void DocxAttributeOutput::EndRun()
             {
                 // If fields begin before hyperlink then
                 // it should end before hyperlink close
-                EndField_Impl( m_Fields.back( ) );
+                EndField_Impl( pNode, nPos, m_Fields.back( ) );
                 m_Fields.pop_back();
             }
             m_pSerializer->endElementNS( XML_w, XML_hyperlink );
@@ -1196,7 +1196,7 @@ void DocxAttributeOutput::EndRun()
         // Add the fields starts for hyperlinks, TOCs and index marks
         if ( pIt->bOpen && !pIt->pField )
         {
-            StartField_Impl( *pIt, true );
+            StartField_Impl( pNode, nPos, *pIt, true );
 
             if (m_startedHyperlink)
                 ++m_nFieldsInHyperlink;
@@ -1343,7 +1343,7 @@ void DocxAttributeOutput::EndRun()
             {
                 // If fields begin after hyperlink start then
                 // it should end before hyperlink close
-                EndField_Impl( m_Fields.back( ) );
+                EndField_Impl( pNode, nPos, m_Fields.back( ) );
                 m_Fields.pop_back();
             }
             m_nFieldsInHyperlink = 0;
@@ -1359,7 +1359,7 @@ void DocxAttributeOutput::EndRun()
     {
         while ( m_Fields.begin() != m_Fields.end() )
         {
-            EndField_Impl( m_Fields.front( ) );
+            EndField_Impl( pNode, nPos, m_Fields.front( ) );
             m_Fields.erase( m_Fields.begin( ) );
         }
         m_nFieldsInHyperlink = 0;
@@ -1615,7 +1615,7 @@ void DocxAttributeOutput::WriteFFData(  const FieldInfos& rInfos )
     }
 }
 
-void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun )
+void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun )
 {
     if ( rInfos.pField && rInfos.eType == ww::eUNKNOWN )
     {
@@ -1648,9 +1648,9 @@ void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun )
 
                 if ( bWriteRun )
                     m_pSerializer->endElementNS( XML_w, XML_r );
-                if ( !rInfos.pField )
-                    CmdField_Impl( rInfos );
 
+                if ( !rInfos.pField )
+                    CmdField_Impl( pNode, nPos, rInfos, bWriteRun );
         }
         else
         {
@@ -1680,7 +1680,7 @@ void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun )
             // The hyperlinks fields can't be expanded: the value is
             // normally in the text run
             if ( !rInfos.pField )
-                CmdField_Impl( rInfos );
+                CmdField_Impl( pNode, nPos, rInfos, bWriteRun );
         }
     }
 }
@@ -1700,48 +1700,146 @@ void DocxAttributeOutput::DoWriteCmd( const OUString& rCmd )
 
 }
 
-void DocxAttributeOutput::CmdField_Impl( FieldInfos& rInfos )
+void DocxAttributeOutput::CmdField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun )
 {
-    m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
-    sal_Int32 nNbToken = comphelper::string::getTokenCount(rInfos.sCmd, '\t');
+    // Write the Field instruction
+    {
+        if ( bWriteRun )
+        {
+            m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+            DoWriteFieldRunProperties( pNode, nPos );
+        }
+
+        sal_Int32 nNbToken = comphelper::string::getTokenCount(rInfos.sCmd, '\t');
+
+        for ( sal_Int32 i = 0; i < nNbToken; i++ )
+        {
+            OUString sToken = rInfos.sCmd.getToken( i, '\t' );
+            if ( rInfos.eType ==  ww::eCREATEDATE
+              || rInfos.eType ==  ww::eSAVEDATE
+              || rInfos.eType ==  ww::ePRINTDATE
+              || rInfos.eType ==  ww::eDATE
+              || rInfos.eType ==  ww::eTIME )
+            {
+               sToken = sToken.replaceAll("NNNN", "dddd");
+               sToken = sToken.replaceAll("NN", "ddd");
+            }
+
+            // Write the Field command
+            DoWriteCmd( sToken );
+
+            // Replace tabs by </instrText><tab/><instrText>
+            if ( i < ( nNbToken - 1 ) )
+                RunText( "\t" );
+        }
+
+        if ( bWriteRun )
+        {
+            m_pSerializer->endElementNS( XML_w, XML_r );
+        }
+    }
 
-    for ( sal_Int32 i = 0; i < nNbToken; i++ )
+    // Write the Field separator
     {
-        OUString sToken = rInfos.sCmd.getToken( i, '\t' );
-        if ( rInfos.eType ==  ww::eCREATEDATE
-          || rInfos.eType ==  ww::eSAVEDATE
-          || rInfos.eType ==  ww::ePRINTDATE
-          || rInfos.eType ==  ww::eDATE
-          || rInfos.eType ==  ww::eTIME )
+        if ( bWriteRun )
         {
-           sToken = sToken.replaceAll("NNNN", "dddd");
-           sToken = sToken.replaceAll("NN", "ddd");
+            m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+            DoWriteFieldRunProperties( pNode, nPos );
         }
 
-        // Write the Field command
-        DoWriteCmd( sToken );
+        m_pSerializer->singleElementNS( XML_w, XML_fldChar,
+              FSNS( XML_w, XML_fldCharType ), "separate",
+              FSEND );
 
-        // Replace tabs by </instrText><tab/><instrText>
-        if ( i < ( nNbToken - 1 ) )
-            RunText( "\t" );
+        if ( bWriteRun )
+        {
+            m_pSerializer->endElementNS( XML_w, XML_r );
+        }
     }
+}
 
-    m_pSerializer->endElementNS( XML_w, XML_r );
+/// Writes properties for run that is used to separate field implementation.
+/// There are several runs are used:
+///     <w:r>
+///         <w:rPr>
+///             <!-- properties written with StartRunProperties() / EndRunProperties().
+///         </w:rPr>
+///         <w:fldChar w:fldCharType="begin" />
+///     </w:r>
+///         <w:r>
+///         <w:rPr>
+///             <!-- properties written with DoWriteFieldRunProperties()
+///         </w:rPr>
+///         <w:instrText>TIME \@"HH:mm:ss"</w:instrText>
+///     </w:r>
+///     <w:r>
+///         <w:rPr>
+///             <!-- properties written with DoWriteFieldRunProperties()
+///         </w:rPr>
+///         <w:fldChar w:fldCharType="separate" />
+///     </w:r>
+///     <w:r>
+///         <w:rPr>
+///             <!-- properties written with DoWriteFieldRunProperties()
+///         </w:rPr>
+///         <w:t>14:01:13</w:t>
+///         </w:r>
+///     <w:r>
+///         <w:rPr>
+///             <!-- properties written with DoWriteFieldRunProperties()
+///         </w:rPr>
+///         <w:fldChar w:fldCharType="end" />
+///     </w:r>
+/// See, tdf#38778
+void DocxAttributeOutput::DoWriteFieldRunProperties( const SwTextNode * pNode, sal_Int32 nPos )
+{
+    if (! pNode)
+    {
+        // nothing to do
+        return;
+    }
 
-    // Write the Field separator
-    m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
-    m_pSerializer->singleElementNS( XML_w, XML_fldChar,
-          FSNS( XML_w, XML_fldCharType ), "separate",
-          FSEND );
-    m_pSerializer->endElementNS( XML_w, XML_r );
+    m_bPreventDoubleFieldsHandling = true;
+
+    {
+        m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND );
+
+        // 1. output webHidden flag
+        if(GetExport().m_bHideTabLeaderAndPageNumbers && m_pHyperlinkAttrList.is() )
+        {
+            m_pSerializer->singleElementNS( XML_w, XML_webHidden, FSEND );
+        }
+
+        // 2. output color
+        if ( m_pColorAttrList.is() )
+        {
+            XFastAttributeListRef xAttrList( m_pColorAttrList.get() );
+            m_pColorAttrList.clear();
+
+            m_pSerializer->singleElementNS( XML_w, XML_color, xAttrList );
+        }
+
+        // 3. output all other character properties
+        SwWW8AttrIter aAttrIt( m_rExport, *pNode );
+        aAttrIt.OutAttr( nPos, false );
+
+        m_pSerializer->endElementNS( XML_w, XML_rPr );
+
+        // During SwWW8AttrIter::OutAttr() call the new value of the text color could be set into [m_pColorAttrList].
+        // But we do not need to keep it any more and should clean up,
+        // While the next run could define a new color that is different to current one.
+        m_pColorAttrList.clear();
+    }
+
+    m_bPreventDoubleFieldsHandling = false;
 }
 
-void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
+void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos& rInfos )
 {
     // The command has to be written before for the hyperlinks
     if ( rInfos.pField )
     {
-        CmdField_Impl( rInfos );
+        CmdField_Impl( pNode, nPos, rInfos, true );
     }
 
     // Write the bookmark start if any
@@ -1754,6 +1852,8 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
     {
         // Write the Field latest value
         m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+        DoWriteFieldRunProperties( pNode, nPos );
+
         OUString sExpand;
         if(rInfos.eType == ww::eCITATION)
         {
@@ -1782,6 +1882,7 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
     if ( rInfos.bClose  )
     {
         m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
+        DoWriteFieldRunProperties( pNode, nPos );
         m_pSerializer->singleElementNS( XML_w, XML_fldChar,
               FSNS( XML_w, XML_fldCharType ), "end",
               FSEND );
@@ -1813,7 +1914,7 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
             m_sFieldBkm = OUString( );
 
             // Write the end of the field
-            EndField_Impl( rInfos );
+            EndField_Impl( pNode, nPos, rInfos );
         }
     }
 }
@@ -2326,8 +2427,8 @@ void DocxAttributeOutput::RawText(const OUString& /*rText*/, rtl_TextEncoding /*
 
 void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby )
 {
-    OSL_TRACE("TODO DocxAttributeOutput::StartRuby( const SwTextNode& rNode, const SwFormatRuby& rRuby )" );
-    EndRun(); // end run before starting ruby to avoid nested runs, and overlap
+    SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::StartRuby( const SwTextNode& rNode, const SwFormatRuby& rRuby )" );
+    EndRun( &rNode, nPos ); // end run before starting ruby to avoid nested runs, and overlap
     assert(!m_closeHyperlinkInThisRun); // check that no hyperlink overlaps ruby
     assert(!m_closeHyperlinkInPreviousRun);
     m_pSerializer->startElementNS( XML_w, XML_ruby, FSEND );
@@ -2381,17 +2482,17 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, co
 
     EndRunProperties( nullptr );
     RunText( rRuby.GetText( ) );
-    EndRun( );
+    EndRun( &rNode, nPos );
     m_pSerializer->endElementNS( XML_w, XML_rt );
 
     m_pSerializer->startElementNS( XML_w, XML_rubyBase, FSEND );
     StartRun( nullptr );
 }
 
-void DocxAttributeOutput::EndRuby()
+void DocxAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
 {
-    OSL_TRACE( "TODO DocxAttributeOutput::EndRuby()" );
-    EndRun( );
+    SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::EndRuby()" );
+    EndRun( &rNode, nPos );
     m_pSerializer->endElementNS( XML_w, XML_rubyBase );
     m_pSerializer->endElementNS( XML_w, XML_ruby );
     StartRun(nullptr); // open Run again so OutputTextNode loop can close it
@@ -6405,11 +6506,24 @@ void DocxAttributeOutput::CharFont( const SvxFontItem& rFont)
 {
     GetExport().GetId( rFont ); // ensure font info is written to fontTable.xml
     const OUString& sFontName(rFont.GetFamilyName());
-    OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8);
+    const OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8);
     if (!sFontNameUtf8.isEmpty())
+    {
+        if (m_pFontsAttrList &&
+            (   m_pFontsAttrList->hasAttribute(FSNS( XML_w, XML_ascii )) ||
+                m_pFontsAttrList->hasAttribute(FSNS( XML_w, XML_hAnsi ))    )
+            )
+        {
+            // tdf#38778: do to fields output into DOC the font could be added before and after field declaration
+            // that all sub runs of the field will have correct font inside.
+            // For DOCX we should do not add the same font information twice in the same node
+            return;
+        }
+
         AddToAttrList( m_pFontsAttrList, 2,
             FSNS( XML_w, XML_ascii ), sFontNameUtf8.getStr(),
             FSNS( XML_w, XML_hAnsi ), sFontNameUtf8.getStr() );
+    }
 }
 
 void DocxAttributeOutput::CharFontSize( const SvxFontHeightItem& rFontSize)
@@ -6858,6 +6972,9 @@ void DocxAttributeOutput::WriteExpand( const SwField* pField )
 
 void DocxAttributeOutput::WriteField_Impl( const SwField* pField, ww::eField eType, const OUString& rFieldCmd, sal_uInt8 nMode )
 {
+    if (m_bPreventDoubleFieldsHandling)
+        return;
+
     struct FieldInfos infos;
     if (pField)
         infos.pField.reset(pField->CopyField());
@@ -8397,6 +8514,9 @@ void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem)
 
 void DocxAttributeOutput::CharGrabBag( const SfxGrabBagItem& rItem )
 {
+    if (m_bPreventDoubleFieldsHandling)
+        return;
+
     const std::map< OUString, css::uno::Any >& rMap = rItem.GetGrabBag();
 
     // get original values of theme-derived properties to check if they have changed during the edition
@@ -8598,6 +8718,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSeri
       m_bRunTextIsOn( false ),
       m_bWritingHeaderFooter( false ),
       m_bAnchorLinkedToNode(false),
+      m_bPreventDoubleFieldsHandling( false ),
       m_sFieldBkm( ),
       m_nNextBookmarkId( 0 ),
       m_nNextAnnotationMarkId( 0 ),
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 8413b487d0b4..2456fffac0a6 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -166,7 +166,7 @@ public:
     virtual void StartRun( const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false ) override;
 
     /// End of the text run.
-    virtual void EndRun() override;
+    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos) override;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -190,7 +190,7 @@ public:
     virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) override;
 
     /// Output ruby end.
-    virtual void EndRuby() override;
+    virtual void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override;
 
     /// Output URL start.
     virtual bool StartURL( const OUString& rUrl, const OUString& rTarget ) override;
@@ -722,10 +722,11 @@ private:
     /// Closes a currently open SDT block.
     void EndSdtBlock();
 
-    void StartField_Impl( FieldInfos& rInfos, bool bWriteRun = false );
+    void StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun = false );
     void DoWriteCmd( const OUString& rCmd );
-    void CmdField_Impl( FieldInfos& rInfos );
-    void EndField_Impl( FieldInfos& rInfos );
+    void CmdField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun );
+    void EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos& rInfos );
+    void DoWriteFieldRunProperties( const SwTextNode* pNode, sal_Int32 nPos );
 
     static void AddToAttrList( css::uno::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrName, const sal_Char* sAttrValue );
     static void AddToAttrList( css::uno::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nArgs, ... );
@@ -773,6 +774,7 @@ private:
     bool m_bAnchorLinkedToNode;
 
     /// Field data to remember in the text run
+    bool m_bPreventDoubleFieldsHandling;
     std::vector< FieldInfos > m_Fields;
     OUString m_sFieldBkm;
     sal_Int32 m_nNextBookmarkId;
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index e8e738377f25..3f62a6c56310 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1464,7 +1464,9 @@ void DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTy
             nAktPos = nNextAttr;
             eChrSet = eNextChrSet;
             aAttrIter.NextPos();
-            AttrOutput().EndRun();
+
+            AttrOutput().EndRun( nullptr, 0 );
+
         } while( nAktPos < nEnd );
 //        aAttrIter.OutParaAttr(false);
         AttrOutput().EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t());
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index de38628bb4d5..ee3ff68665e7 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -391,7 +391,7 @@ void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, bool bSingl
     OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty");
 }
 
-void RtfAttributeOutput::EndRun()
+void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/)
 {
     m_aRun->append(SAL_NEWLINE_STRING);
     m_aRun.appendAndClear(m_aRunText);
@@ -432,7 +432,7 @@ void RtfAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding eCharSe
     m_aRunText->append(msfilter::rtfutil::OutString(rText, eCharSet));
 }
 
-void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/, const SwFormatRuby& rRuby)
+void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby)
 {
     OUString aStr(FieldString(ww::eEQ));
     aStr += "\\* jc";
@@ -533,7 +533,7 @@ void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/,
     nHeight = (rHeightItem.GetHeight() + 10)/20-1;
     aStr += OUString::number(nHeight);
     aStr += "(";
-    EndRun();
+    EndRun(&rNode, nPos);
     m_rExport.OutputField(nullptr, ww::eEQ, aStr, WRITEFIELD_START | WRITEFIELD_CMD_START);
     aStr  = rRuby.GetText();
     aStr += ")";
@@ -541,10 +541,10 @@ void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/,
     m_rExport.OutputField(nullptr, ww::eEQ, aStr, 0);
 }
 
-void RtfAttributeOutput::EndRuby()
+void RtfAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
 {
     m_rExport.OutputField(nullptr, ww::eEQ, ")", WRITEFIELD_END | WRITEFIELD_CLOSE);
-    EndRun();
+    EndRun(&rNode, nPos);
 }
 
 bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget)
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index 1c3e32ed9445..e465dbbe8a8f 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -65,7 +65,7 @@ public:
     virtual void StartRun(const SwRedlineData* pRedlineData, bool bSingleEmptyRun = false) override;
 
     /// End of the text run.
-    virtual void EndRun() override;
+    void EndRun(const SwTextNode* pNode, sal_Int32 nPos) override;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -91,7 +91,7 @@ public:
     virtual void StartRuby(const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby) override;
 
     /// Output ruby end.
-    virtual void EndRuby() override;
+    void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override;
 
     /// Output URL start.
     virtual bool StartURL(const OUString& rUrl, const OUString& rTarget) override;
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index 6792fea1ef79..d04facf6af8c 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -485,7 +485,10 @@ void SwWW8AttrIter::OutAttr( sal_Int32 nSwPos, bool bRuby )
         m_rExport.m_pOutFormatNode = &rNd;
         m_rExport.m_aCurrentCharPropStarts.push( nSwPos );
 
-        m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript() );
+        // tdf#38778 Fix output of the font in DOC run for fields
+        const SvxFontItem * pFontToOutput = ( rParentFont != *pFont )? pFont : nullptr;
+
+        m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript(), pFontToOutput );
 
         // HasTextItem only allowed in the above range
         m_rExport.m_aCurrentCharPropStarts.pop();
@@ -667,10 +670,16 @@ bool SwWW8AttrIter::IsTextAttr( sal_Int32 nSwPos )
         for (size_t i = 0; i < pTextAttrs->Count(); ++i)
         {
             const SwTextAttr* pHt = pTextAttrs->Get(i);
-            if ( ( pHt->HasDummyChar() || pHt->HasContent() )
-                 && (pHt->GetStart() == nSwPos) )
+            if (nSwPos == pHt->GetStart())
             {
-                return true;
+                if (pHt->HasDummyChar() || pHt->HasContent() )
+                {
+                    return true;
+                }
+            }
+            else if (nSwPos < pHt->GetStart())
+            {
+                break; // sorted by start
             }
         }
     }
@@ -880,7 +889,7 @@ void WW8AttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 /*nPos*/,
             WRITEFIELD_START | WRITEFIELD_CMD_START );
 }
 
-void WW8AttributeOutput::EndRuby()
+void WW8AttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/)
 {
     m_rWW8Export.WriteChar( ')' );
     m_rWW8Export.OutputField( nullptr, ww::eEQ, OUString(), WRITEFIELD_END | WRITEFIELD_CLOSE );
@@ -1228,7 +1237,7 @@ void AttributeOutputBase::TOXMark( const SwTextNode& rNode, const SwTOXMark& rAt
         FieldVanish( sText, eType );
 }
 
-int SwWW8AttrIter::OutAttrWithRange(sal_Int32 nPos)
+int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos)
 {
     int nRet = 0;
     if ( const SwpHints* pTextAttrs = rNd.GetpSwpHints() )
@@ -1262,7 +1271,7 @@ int SwWW8AttrIter::OutAttrWithRange(sal_Int32 nPos)
                     pEnd = pHt->End();
                     if (nPos == *pEnd && nPos != pHt->GetStart())
                     {
-                        m_rExport.AttrOutput().EndRuby();
+                        m_rExport.AttrOutput().EndRuby(rNode, nPos);
                         --nRet;
                     }
                     break;
@@ -1316,7 +1325,7 @@ int SwWW8AttrIter::OutAttrWithRange(sal_Int32 nPos)
                     pEnd = pHt->End();
                     if (nPos == *pEnd && nPos == pHt->GetStart())
                     {   // special case: empty must be handled here
-                        m_rExport.AttrOutput().EndRuby();
+                        m_rExport.AttrOutput().EndRuby( rNd, nPos );
                         --nRet;
                     }
                     break;
@@ -2192,7 +2201,7 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
             AppendSmartTags(rNode);
 
         bool bTextAtr = aAttrIter.IsTextAttr( nAktPos );
-        nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nAktPos);
+        nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nAktPos );
 
         sal_Int32 nLen = nNextAttr - nAktPos;
         if ( !bTextAtr && nLen )
@@ -2380,7 +2389,7 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
             bool bAttrWithRange = (nOpenAttrWithRange > 0);
             if ( nAktPos != nEnd )
             {
-                nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nEnd);
+                nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nEnd );
                 OSL_ENSURE(nOpenAttrWithRange == 0,
                     "odd to see this happening, expected 0");
             }
@@ -2429,7 +2438,7 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
 
         if( bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame )
         {
-            AttrOutput().EndRun();
+            AttrOutput().EndRun(&rNode, nAktPos);
             //write the postponed text run
             AttrOutput().StartRun( pRedlineData, bSingleEmptyRun );
             AttrOutput().SetAnchorIsLinkedToNode( false );
@@ -2441,16 +2450,16 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode )
                 AttrOutput().EndRunProperties( pRedlineData );
             }
             AttrOutput().RunText( aSavedSnippet, eChrSet );
-            AttrOutput().EndRun();
+            AttrOutput().EndRun(&rNode, nAktPos);
         }
         else if( bPostponeWritingText && !aSavedSnippet.isEmpty() )
         {
             //write the postponed text run
             AttrOutput().RunText( aSavedSnippet, eChrSet );
-            AttrOutput().EndRun();
+            AttrOutput().EndRun(&rNode, nAktPos);
         }
         else
-            AttrOutput().EndRun();
+            AttrOutput().EndRun(&rNode, nAktPos);
 
         nAktPos = nNextAttr;
         UpdatePosition( &aAttrIter, nAktPos, nEnd );
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 683076061470..9ee2645f2d38 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -584,7 +584,7 @@ public:
     void WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_uInt8 nTTyp );
 
     /// Export the pool items to attributes (through an attribute output class).
-    void ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript );
+    void ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont );
 
     /// Return the numeric id of the numbering rule
     sal_uInt16 GetId( const SwNumRule& rNumRule );
@@ -1488,7 +1488,7 @@ public:
     void OutAttr( sal_Int32 nSwPos, bool bRuby = false );
     virtual const SfxPoolItem* HasTextItem( sal_uInt16 nWhich ) const override;
     virtual const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const override;
-    int OutAttrWithRange(sal_Int32 nPos);
+    int OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos);
     const SwRedlineData* GetParagraphLevelRedline( );
     const SwRedlineData* GetRunLevelRedline( sal_Int32 nPos );
     FlyProcessingState OutFlys(sal_Int32 nSwPos);
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 9df4a6a7bf13..db888c475a20 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -204,7 +204,7 @@ bool WW8Export::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich
 
 //  Hilfsroutinen fuer Styles
 
-void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript )
+void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont )
 {
     ww8::cPoolItemIter aEnd = rItems.end();
     for ( ww8::cPoolItemIter aI = rItems.begin(); aI != aEnd; ++aI )
@@ -220,7 +220,15 @@ void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16
              //add the second judgement for #i24291# definition.
              if ( nWhich == RES_TXTATR_INETFMT && ( rItems.begin()->second->Which() == RES_TXTATR_CHARFMT ) )
                  continue;
-            AttrOutput().OutputItem( *pItem );
+
+             // tdf#38778 Fix output of the font in DOC run for fields
+             if (pFont &&
+                 nWhich == RES_TXTATR_FIELD)
+             {
+                 AttrOutput().OutputItem( *pFont );
+             }
+
+             AttrOutput().OutputItem( *pItem );
         }
     }
 }
@@ -269,7 +277,7 @@ void MSWordExportBase::OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, b
         ww8::PoolItems aItems;
         GetPoolItems( rSet, aItems, bExportParentItemSet );
         if ( bChpFormat )
-            ExportPoolItemsToCHP(aItems, nScript);
+            ExportPoolItemsToCHP(aItems, nScript, nullptr);
         if ( bPapFormat )
         {
             ww8::cPoolItemIter aEnd = aItems.end();
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx
index f48eb3816b51..0d41f0e33fb4 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -56,7 +56,7 @@ public:
     /// End of the text run.
     ///
     /// No-op for binary filters.
-    virtual void EndRun() override {}
+    virtual void EndRun(const SwTextNode* , sal_Int32 ) override {}
 
     /// Before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -74,7 +74,7 @@ public:
     virtual void StartRuby( const SwTextNode& rNode, sal_Int32 nPos, const SwFormatRuby& rRuby ) override;
 
     /// Output ruby end.
-    virtual void EndRuby() override;
+    virtual void EndRuby(const SwTextNode& rNode, sal_Int32 nPos) override;
 
     /// Output URL start.
     virtual bool StartURL( const OUString &rUrl, const OUString &rTarget ) override;


More information about the Libreoffice-commits mailing list