sw/source/filter/inc/msfilter.hxx | 1 sw/source/filter/ww8/writerhelper.cxx | 56 ++++++++++++++++++++++++++++++++++ sw/source/filter/ww8/ww8par5.cxx | 3 + 3 files changed, 60 insertions(+)
New commits: commit 4a5ee9a074c94f2a0cc9733e12d5e412926633d1 Author: Michael Stahl <[email protected]> Date: Wed Dec 14 23:02:07 2016 +0100 sw: WW8 import: try to prevent overlapping field-marks and redlines As one knows, the features of Writer's document model that most impress by their sheer quality of implementation are redlines and field marks. Unsurprisingly, if the two meet in the context of the WW8 import, epic disasters are imminent; ooo83574-1.doc is one such train wreck that asserts with: sw/source/core/crsr/bookmrk.cxx:111: void {anonymous}::lcl_RemoveFieldMarks(sw::mark::Fieldmark*, SwDoc*, sal_Unicode, sal_Unicode): Assertion `pStartTextNode->GetText()[rStart.nContent.GetIndex()] == aStartMark' failed. This happens when, at the end of the import, the redlines are hidden by moving them into their special SwNodes section. The reason why this one asserts is that a previous SwRedline erroneously deleted the start dummy char of this field mark, because that SwRedline had the wrong start/end positions. In Word the problematic paragraph is shown like this, where \a\b mark fields and I D F redlines: "Coming out of the work of Rummler and Bracheâs \a(Rummler & Brache, 1995)(1995)\b work is the is the notion IIIIIIIIIIIIDDDDDDDDDDDDDDDDDDDDD IIIIIIIIIIIIIIIIIIIIIIIIDDDDDD DDDDDDDDDDDDIIIIIII anotherâ \a(p. 9)\b\a(Rummler & Brache, 1995, p. 9)\b.. ( italics in the original)" IIIIII DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD IDDDIDDDDDDDDDDDDDDDDDDDDDDDD FFFFFFFFFFFFFFFFFFFFFFFFFF The first mis-positioned redline here ranges from 71 to 79, ")(1995)\b", so it deletes the end dummy char of the field mark. It should range from 72 to 78. This commit adds some rather crude hacks which appear to work to avoid the problem: 1. when a field mark is inserted, the start positions of the redlines may need to be moved 2. when the end position of a redline is set, it may need adjustment to exclude a field-mark that ends at the same position Change-Id: I723f1858c84def2c063e2cb126317d06e8ac98b5 (cherry picked from commit d195a3e5f4ec5c616ae83f99d48f5d4eefe5f22e) Reviewed-on: https://gerrit.libreoffice.org/32191 Tested-by: Jenkins <[email protected]> Reviewed-by: Michael Stahl <[email protected]> diff --git a/sw/source/filter/inc/msfilter.hxx b/sw/source/filter/inc/msfilter.hxx index 66771cf..3710424 100644 --- a/sw/source/filter/inc/msfilter.hxx +++ b/sw/source/filter/inc/msfilter.hxx @@ -345,6 +345,7 @@ namespace sw public: explicit RedlineStack(SwDoc &rDoc) : mrDoc(rDoc) {} + void MoveAttrs(const SwPosition& rPos); void open(const SwPosition& rPos, const SfxPoolItem& rAttr); bool close(const SwPosition& rPos, RedlineType_t eType); void close(const SwPosition& rPos, RedlineType_t eType, diff --git a/sw/source/filter/ww8/writerhelper.cxx b/sw/source/filter/ww8/writerhelper.cxx index 4c1ef18..65b6775 100644 --- a/sw/source/filter/ww8/writerhelper.cxx +++ b/sw/source/filter/ww8/writerhelper.cxx @@ -52,6 +52,8 @@ #include <IDocumentDrawModelAccess.hxx> #include <IDocumentLayoutAccess.hxx> #include <IDocumentStylePoolAccess.hxx> +#include <IDocumentMarkAccess.hxx> +#include <IMark.hxx> using namespace com::sun::star; @@ -740,6 +742,26 @@ namespace sw SameOpenRedlineType(eType)); if (aResult != maStack.rend()) { + SwTextNode *const pNode(rPos.nNode.GetNode().GetTextNode()); + sal_Int32 const nIndex(rPos.nContent.GetIndex()); + // HACK to prevent overlap of field-mark and redline, + // which would destroy field-mark invariants when the redline + // is hidden: move the redline end one to the left + if (pNode && nIndex > 0 + && pNode->GetText()[nIndex - 1] == CH_TXT_ATR_FIELDEND) + { + SwPosition const end(*rPos.nNode.GetNode().GetTextNode(), + nIndex - 1); + sw::mark::IFieldmark *const pFieldMark( + rPos.GetDoc()->getIDocumentMarkAccess()->getFieldmarkFor(end)); + assert(pFieldMark); + if (pFieldMark->GetMarkPos().nNode.GetIndex() == (*aResult)->m_aMkPos.m_nNode.GetIndex()+1 + && pFieldMark->GetMarkPos().nContent.GetIndex() < (*aResult)->m_aMkPos.m_nContent) + { + (*aResult)->SetEndPos(end); + return true; + } + } (*aResult)->SetEndPos(rPos); return true; } @@ -751,6 +773,40 @@ namespace sw std::for_each(maStack.begin(), maStack.end(), SetEndIfOpen(rPos)); } + void RedlineStack::MoveAttrs( const SwPosition& rPos ) + { + size_t nCnt = maStack.size(); + sal_uLong nPosNd = rPos.nNode.GetIndex(); + sal_Int32 nPosCt = rPos.nContent.GetIndex() - 1; + + for (size_t i=0; i < nCnt; ++i) + { + SwFltStackEntry& rEntry = *maStack[i]; + bool const isPoint(rEntry.m_aMkPos == rEntry.m_aPtPos); + if ((rEntry.m_aMkPos.m_nNode.GetIndex()+1 == nPosNd) && + (nPosCt <= rEntry.m_aMkPos.m_nContent)) + { + rEntry.m_aMkPos.m_nContent++; + SAL_WARN_IF(rEntry.m_aMkPos.m_nContent > rPos.nNode.GetNodes()[nPosNd]->GetContentNode()->Len(), + "sw.ww8", "redline ends after end of line"); + if (isPoint) // sigh ... important special case... + { + rEntry.m_aPtPos.m_nContent++; + continue; + } + } + // for the end position, leave it alone if it's *on* the dummy + // char position, that should remain *before* + if ((rEntry.m_aPtPos.m_nNode.GetIndex()+1 == nPosNd) && + (nPosCt < rEntry.m_aPtPos.m_nContent)) + { + rEntry.m_aPtPos.m_nContent++; + SAL_WARN_IF(rEntry.m_aPtPos.m_nContent > rPos.nNode.GetNodes()[nPosNd]->GetContentNode()->Len(), + "sw.ww8", "redline ends after end of line"); + } + } + } + void SetInDocAndDelete::operator()(SwFltStackEntry *pEntry) { SwPaM aRegion(pEntry->m_aMkPos.m_nNode); diff --git a/sw/source/filter/ww8/ww8par5.cxx b/sw/source/filter/ww8/ww8par5.cxx index 327368f..c9a0dc5 100644 --- a/sw/source/filter/ww8/ww8par5.cxx +++ b/sw/source/filter/ww8/ww8par5.cxx @@ -610,6 +610,9 @@ sal_uInt16 SwWW8ImplReader::End_Field() ODF_UNHANDLED ); if ( pFieldmark ) { + // adapt redline positions to inserted field mark start + // dummy char (assume not necessary for end dummy char) + m_pRedlineStack->MoveAttrs(*aFieldPam.Start()); const IFieldmark::parameter_map_t& rParametersToAdd = m_aFieldStack.back().getParameters(); pFieldmark->GetParameters()->insert(rParametersToAdd.begin(), rParametersToAdd.end()); OUString sFieldId = OUString::number( m_aFieldStack.back().mnFieldId );
_______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
