sw/qa/extras/ooxmlexport/ooxmlexport12.cxx | 2 sw/qa/extras/ooxmlexport/ooxmlexport9.cxx | 2 sw/source/filter/ww8/wrtw8nds.cxx | 39 +++++----- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 79 +++++++++++++--------- 4 files changed, 68 insertions(+), 54 deletions(-)
New commits: commit 35b93ab6be79e5506248aea2f5b618db54e93c0f Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Mon Oct 14 18:17:24 2019 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Wed Oct 23 13:06:56 2019 +0200 sw: remove checks for invalid document model wrt fieldmarks... ... in MSWordExportBase::OutputTextNode() - better crash so we can fix the bugs. Change-Id: I0d7b58bffa261c9c0c88b4245fcde38c776931f9 Reviewed-on: https://gerrit.libreoffice.org/80919 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 4ad6d3a721ec..aa70daf65738 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -118,10 +118,8 @@ using namespace ::oox::vml; static OUString lcl_getFieldCode( const IFieldmark* pFieldmark ) { - OSL_ENSURE(pFieldmark!=nullptr, "where is my fieldmark???"); + assert(pFieldmark); - if ( !pFieldmark) - return OUString(); if ( pFieldmark->GetFieldname( ) == ODF_FORMTEXT ) return " FORMTEXT "; if ( pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN ) @@ -139,10 +137,10 @@ static OUString lcl_getFieldCode( const IFieldmark* pFieldmark ) return pFieldmark->GetFieldname(); } -static ww::eField lcl_getFieldId( const IFieldmark* pFieldmark ) { - OSL_ENSURE(pFieldmark!=nullptr, "where is my fieldmark???"); - if ( !pFieldmark ) - return ww::eUNKNOWN; +static ww::eField lcl_getFieldId(const IFieldmark*const pFieldmark) +{ + assert(pFieldmark); + if ( pFieldmark->GetFieldname( ) == ODF_FORMTEXT ) return ww::eFORMTEXT; if ( pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN ) @@ -2335,10 +2333,10 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) { SwPosition aPosition( rNode, SwIndex( &rNode, nCurrentPos ) ); ::sw::mark::IFieldmark const*const pFieldmark = pMarkAccess->getFieldmarkAt(aPosition); - OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" ); + assert(pFieldmark); // Date field is exported as content control, not as a simple field - if(pFieldmark && pFieldmark->GetFieldname( ) == ODF_FORMDATE) + if (pFieldmark->GetFieldname() == ODF_FORMDATE) { if(GetExportFormat() == MSWordExportBase::ExportFormat::DOCX) // supported by DOCX only { @@ -2351,14 +2349,14 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) else { - if ( pFieldmark && pFieldmark->GetFieldname() == ODF_FORMTEXT + if (pFieldmark->GetFieldname() == ODF_FORMTEXT && GetExportFormat() != MSWordExportBase::ExportFormat::DOCX ) { AppendBookmark( pFieldmark->GetName() ); } ww::eField eFieldId = lcl_getFieldId( pFieldmark ); OUString sCode = lcl_getFieldCode( pFieldmark ); - if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED ) + if (pFieldmark->GetFieldname() == ODF_UNHANDLED ) { IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_ID_PARAM ); if ( it != pFieldmark->GetParameters()->end() ) @@ -2377,13 +2375,13 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) OutputField( nullptr, eFieldId, sCode, FieldFlags::Start | FieldFlags::CmdStart ); - if ( pFieldmark && pFieldmark->GetFieldname( ) == ODF_FORMTEXT) + if (pFieldmark->GetFieldname() == ODF_FORMTEXT) WriteFormData( *pFieldmark ); - else if ( pFieldmark && pFieldmark->GetFieldname( ) == ODF_HYPERLINK ) + else if (pFieldmark->GetFieldname() == ODF_HYPERLINK) WriteHyperlinkData( *pFieldmark ); OutputField( nullptr, lcl_getFieldId( pFieldmark ), OUString(), FieldFlags::CmdEnd ); - if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED ) + if (pFieldmark->GetFieldname() == ODF_UNHANDLED) { // Check for the presence of a linked OLE object IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_OLE_PARAM ); @@ -2403,9 +2401,9 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) SwPosition aPosition( rNode, SwIndex( &rNode, nCurrentPos ) ); ::sw::mark::IFieldmark const*const pFieldmark = pMarkAccess->getFieldmarkAt(aPosition); - OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDEND??" ); + assert(pFieldmark); - if(pFieldmark && pFieldmark->GetFieldname( ) == ODF_FORMDATE) + if (pFieldmark->GetFieldname() == ODF_FORMDATE) { if(GetExportFormat() == MSWordExportBase::ExportFormat::DOCX) // supported by DOCX only { @@ -2415,7 +2413,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) else { ww::eField eFieldId = lcl_getFieldId( pFieldmark ); - if ( pFieldmark && pFieldmark->GetFieldname() == ODF_UNHANDLED ) + if (pFieldmark->GetFieldname() == ODF_UNHANDLED) { IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( ODF_ID_PARAM ); if ( it != pFieldmark->GetParameters()->end() ) @@ -2428,7 +2426,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) OutputField( nullptr, eFieldId, OUString(), FieldFlags::Close ); - if ( pFieldmark && pFieldmark->GetFieldname() == ODF_FORMTEXT + if (pFieldmark->GetFieldname() == ODF_FORMTEXT && GetExportFormat() != MSWordExportBase::ExportFormat::DOCX ) { AppendBookmark( pFieldmark->GetName() ); @@ -2439,9 +2437,10 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) { SwPosition aPosition( rNode, SwIndex( &rNode, nCurrentPos ) ); ::sw::mark::IFieldmark const*const pFieldmark = pMarkAccess->getFieldmarkAt(aPosition); + assert(pFieldmark); - bool isDropdownOrCheckbox = pFieldmark && (pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN || - pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX ); + bool const isDropdownOrCheckbox(pFieldmark->GetFieldname() == ODF_FORMDROPDOWN || + pFieldmark->GetFieldname() == ODF_FORMCHECKBOX); if ( isDropdownOrCheckbox ) AppendBookmark( pFieldmark->GetName() ); OutputField( nullptr, lcl_getFieldId( pFieldmark ), commit e47615f1c1b17f66e5b30275e666bc7a7bf43d1c Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Tue Oct 15 18:17:00 2019 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Wed Oct 23 13:06:34 2019 +0200 writerfilter: adapt the "real" fieldmark path in CloseFieldCommand() ... and PopFieldContext() to work the same as the generic fallback path, so that the CH_TXT_FIELDSEP is in the proper position, before the imported field result. Change-Id: Ic9b24dce43e7809a183b91cdc97c037f410cbaa8 Reviewed-on: https://gerrit.libreoffice.org/80918 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx index c48efcb95cc0..b60c6cd571e6 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx @@ -678,7 +678,7 @@ DECLARE_OOXMLEXPORT_TEST(testTdf79435_legacyInputFields, "tdf79435_legacyInputFi { //using .doc input file to verify cross-format compatibility. uno::Reference<text::XFormField> xFormField - = getProperty<uno::Reference<text::XFormField>>(getRun(getParagraph(5), 3), "Bookmark"); + = getProperty<uno::Reference<text::XFormField>>(getRun(getParagraph(5), 2), "Bookmark"); uno::Reference<container::XNameContainer> xParameters(xFormField->getParameters()); OUString sTmp; diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx index 529932ade5f7..2dda95ca0bce 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx @@ -1142,7 +1142,7 @@ DECLARE_OOXMLEXPORT_TEST(testTdf111964, "tdf111964.docx") return; // Unicode spaces that are not XML whitespace must not be trimmed const sal_Unicode sWSReference [] { 0x2002, 0x2002, 0x2002, 0x2002, 0x2002, 0 }; - assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[4]/w:t", sWSReference); + assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[5]/w:t", sWSReference); } DECLARE_OOXMLEXPORT_TEST(testWatermark, "watermark-shapetype.docx") diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index b87e9af77970..f23775bc8731 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -4284,6 +4284,46 @@ void DomainMapper_Impl::handleIndex } } +static auto InsertFieldmark(std::stack<TextAppendContext> & rTextAppendStack, + uno::Reference<text::XFormField> const& xFormField, + uno::Reference<text::XTextRange> const& xStartRange) -> void +{ + uno::Reference<text::XTextContent> const xTextContent(xFormField, uno::UNO_QUERY_THROW); + uno::Reference<text::XTextAppend> const& xTextAppend(rTextAppendStack.top().xTextAppend); + uno::Reference<text::XTextCursor> const xCursor = + xTextAppend->createTextCursorByRange(xStartRange); + if (rTextAppendStack.top().xInsertPosition.is()) + { + xCursor->gotoRange(rTextAppendStack.top().xInsertPosition, true); + } + else + { + xCursor->gotoEnd(true); + } + xTextAppend->insertTextContent(xCursor, xTextContent, true); + // problem: the fieldmark must be inserted in CloseFieldCommand(), because + // attach() takes 2 positions, not 3! + // FAIL: AppendTextNode() ignores the content index! + // plan B: insert a spurious paragraph break now and join + // it in PopFieldContext()! + xCursor->gotoRange(xTextContent->getAnchor()->getEnd(), false); + xCursor->goLeft(1, false); // skip CH_TXT_ATR_FIELDEND + xTextAppend->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false); + xCursor->goLeft(1, false); // back to previous paragraph + rTextAppendStack.push(TextAppendContext(xTextAppend, xCursor)); +} + +static auto PopFieldmark(std::stack<TextAppendContext> & rTextAppendStack, + uno::Reference<text::XTextCursor> const& xCursor) -> void +{ + xCursor->gotoRange(rTextAppendStack.top().xInsertPosition, false); + xCursor->goRight(1, true); + xCursor->setString(OUString()); // undo SplitNode from CloseFieldCommand() + // note: paragraph properties will be overwritten + // by finishParagraph() anyway so ignore here + rTextAppendStack.pop(); +} + void DomainMapper_Impl::CloseFieldCommand() { if(m_bDiscardHeaderFooter) @@ -4562,6 +4602,8 @@ void DomainMapper_Impl::CloseFieldCommand() xNamed->setName( pFFDataHandler->getName() ); pContext->SetFormField( xFormField ); } + InsertFieldmark(m_aTextAppendStack, + xFormField, pContext->GetStartRange()); } else { @@ -5029,30 +5071,9 @@ void DomainMapper_Impl::CloseFieldCommand() if (std::get<0>(field) != "SHAPE" && m_xTextFactory.is() && !m_aTextAppendStack.empty()) { xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.Fieldmark"); - const uno::Reference<text::XTextContent> xTextContent(xFieldInterface, uno::UNO_QUERY_THROW); - uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend; - uno::Reference< text::XTextCursor > xCrsr = xTextAppend->createTextCursorByRange(pContext->GetStartRange()); - if (m_aTextAppendStack.top().xInsertPosition.is()) - { - xCrsr->gotoRange(m_aTextAppendStack.top().xInsertPosition, true); - } - else - { - xCrsr->gotoEnd(true); - } - xTextAppend->insertTextContent(xCrsr, xTextContent, true); - // problem: the fieldmark must be inserted here, because - // attach() takes 2 positions, not 3! - // FAIL: AppendTextNode() ignores the content index! - // plan B: insert a spurious paragraph break now and join - // it in PopFieldContext()! - xCrsr->gotoRange(xTextContent->getAnchor()->getEnd(), false); - xCrsr->goLeft(1, false); // skip CH_TXT_ATR_FIELDEND - xTextAppend->insertControlCharacter(xCrsr, text::ControlCharacter::PARAGRAPH_BREAK, false); - xCrsr->goLeft(1, false); // back to previous paragraph - m_aTextAppendStack.push(TextAppendContext(xTextAppend, xCrsr)); - - uno::Reference<text::XFormField> xFormField(xTextContent, uno::UNO_QUERY); + + uno::Reference<text::XFormField> const xFormField(xFieldInterface, uno::UNO_QUERY); + InsertFieldmark(m_aTextAppendStack, xFormField, pContext->GetStartRange()); xFormField->setFieldType(aCode); m_bStartGenericField = true; pContext->SetFormField( xFormField ); @@ -5361,8 +5382,7 @@ void DomainMapper_Impl::PopFieldContext() xToInsert.set(xFormField, uno::UNO_QUERY); if ( xFormField.is() && xToInsert.is() ) { - xCrsr->gotoEnd( true ); - xToInsert->attach( uno::Reference< text::XTextRange >( xCrsr, uno::UNO_QUERY_THROW )); + PopFieldmark(m_aTextAppendStack, xCrsr); pFormControlHelper->processField( xFormField ); } else @@ -5414,12 +5434,7 @@ void DomainMapper_Impl::PopFieldContext() else if(m_bStartGenericField) { m_bStartGenericField = false; - xCrsr->gotoRange(m_aTextAppendStack.top().xInsertPosition, false); - xCrsr->goRight(1, true); - xCrsr->setString(OUString()); // undo SplitNode from CloseFieldCommand() - // note: paragraph properties will be overwritten - // by finishParagraph() anyway so ignore here - m_aTextAppendStack.pop(); + PopFieldmark(m_aTextAppendStack, xCrsr); if(m_bTextInserted) { m_bTextInserted = false; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits