Kaydet (Commit) d195a3e5 authored tarafından Michael Stahl's avatar Michael Stahl

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
üst 151b80ab
...@@ -345,6 +345,7 @@ namespace sw ...@@ -345,6 +345,7 @@ namespace sw
public: public:
explicit RedlineStack(SwDoc &rDoc) : mrDoc(rDoc) {} explicit RedlineStack(SwDoc &rDoc) : mrDoc(rDoc) {}
void MoveAttrs(const SwPosition& rPos);
void open(const SwPosition& rPos, const SfxPoolItem& rAttr); void open(const SwPosition& rPos, const SfxPoolItem& rAttr);
bool close(const SwPosition& rPos, RedlineType_t eType); bool close(const SwPosition& rPos, RedlineType_t eType);
void close(const SwPosition& rPos, RedlineType_t eType, void close(const SwPosition& rPos, RedlineType_t eType,
......
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
#include <IDocumentDrawModelAccess.hxx> #include <IDocumentDrawModelAccess.hxx>
#include <IDocumentLayoutAccess.hxx> #include <IDocumentLayoutAccess.hxx>
#include <IDocumentStylePoolAccess.hxx> #include <IDocumentStylePoolAccess.hxx>
#include <IDocumentMarkAccess.hxx>
#include <IMark.hxx>
using namespace com::sun::star; using namespace com::sun::star;
...@@ -739,6 +741,26 @@ namespace sw ...@@ -739,6 +741,26 @@ namespace sw
SameOpenRedlineType(eType)); SameOpenRedlineType(eType));
if (aResult != maStack.rend()) 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); (*aResult)->SetEndPos(rPos);
return true; return true;
} }
...@@ -750,6 +772,40 @@ namespace sw ...@@ -750,6 +772,40 @@ namespace sw
std::for_each(maStack.begin(), maStack.end(), SetEndIfOpen(rPos)); 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) void SetInDocAndDelete::operator()(SwFltStackEntry *pEntry)
{ {
SwPaM aRegion(pEntry->m_aMkPos.m_nNode); SwPaM aRegion(pEntry->m_aMkPos.m_nNode);
......
...@@ -609,6 +609,9 @@ sal_uInt16 SwWW8ImplReader::End_Field() ...@@ -609,6 +609,9 @@ sal_uInt16 SwWW8ImplReader::End_Field()
ODF_UNHANDLED ); ODF_UNHANDLED );
if ( pFieldmark ) 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(); const IFieldmark::parameter_map_t& rParametersToAdd = m_aFieldStack.back().getParameters();
pFieldmark->GetParameters()->insert(rParametersToAdd.begin(), rParametersToAdd.end()); pFieldmark->GetParameters()->insert(rParametersToAdd.begin(), rParametersToAdd.end());
OUString sFieldId = OUString::number( m_aFieldStack.back().mnFieldId ); OUString sFieldId = OUString::number( m_aFieldStack.back().mnFieldId );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment