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 <[email protected]> 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) <[email protected]> Tested-by: Serge Krot (CIB) <[email protected]> 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 <[email protected]> Reviewed-by: Serge Krot (CIB) <[email protected]> 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 <[email protected]> Reviewed-by: Thorsten Behrens <[email protected]> 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 <[email protected]> Reviewed-by: Thorsten Behrens <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/44359 Tested-by: Thorsten Behrens <[email protected]> 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; _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
