[Libreoffice-commits] core.git: Branch 'libreoffice-4-1' - 4 commits - editeng/source libmwaw/libmwaw-infinite-loop.patch.1 libmwaw/UnpackedTarball_libmwaw.mk sw/inc sw/source
Michael Stahl
mstahl at redhat.com
Wed Jun 19 15:56:50 PDT 2013
editeng/source/misc/svxacorr.cxx | 13 +-
libmwaw/UnpackedTarball_libmwaw.mk | 1
libmwaw/libmwaw-infinite-loop.patch.1 | 32 +++++
sw/inc/doc.hxx | 1
sw/inc/ndhints.hxx | 2
sw/inc/swtypes.hxx | 4
sw/inc/txatbase.hxx | 6
sw/source/core/doc/doc.cxx | 35 -----
sw/source/core/doc/docfmt.cxx | 68 ++++++++++
sw/source/core/edit/editsh.cxx | 15 +-
sw/source/core/inc/UndoInsert.hxx | 3
sw/source/core/inc/rolbck.hxx | 2
sw/source/core/layout/frmtool.cxx | 3
sw/source/core/layout/laycache.cxx | 5
sw/source/core/text/itratr.cxx | 24 +++
sw/source/core/txtnode/ndhints.cxx | 88 +++++++++++++-
sw/source/core/txtnode/ndtxt.cxx | 44 ++++++-
sw/source/core/txtnode/thints.cxx | 213 ++++++++++++++++++++++++++++++----
sw/source/core/txtnode/txatbase.cxx | 2
sw/source/core/txtnode/txtedt.cxx | 4
sw/source/core/undo/rolbck.cxx | 14 ++
sw/source/core/undo/unins.cxx | 22 +++
22 files changed, 513 insertions(+), 88 deletions(-)
New commits:
commit c5423c79efc8f225d63419ebe71da5a4a009bc64
Author: Michael Stahl <mstahl at redhat.com>
Date: Thu Jun 20 00:20:52 2013 +0200
fdo#62536: sw: fix AutoCorrect bold/underline on existing AUTOFMT
With the native AUTOFMT in Writer the SETATTR_DONTEXPAND does no longer
work reliably: if there is an existing AUTOFMT at the position then it
will be modified and no new hint with DontExpand will be inserted.
Work around this deficiency by inserting a no-length hint with the
preivous formatting at the end of the range.
(similar fix to the i#75891 problem in SwTextShell::InsertSymbol)
(commit 062eaeffe7cb986255063bb9b0a5f3fb3fc8e34c did not
introduce the problem but made it far more annoying)
Change-Id: I58ece7f5bd5a786b22a066e5902f1784dafa5dce
(cherry picked from commit fe444d1f74abe417962be0bcd3340f40f2446b58)
diff --git a/editeng/source/misc/svxacorr.cxx b/editeng/source/misc/svxacorr.cxx
index 335a14f..e7a3d31 100644
--- a/editeng/source/misc/svxacorr.cxx
+++ b/editeng/source/misc/svxacorr.cxx
@@ -763,24 +763,27 @@ sal_Bool SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc& rDoc, const String&
if( STRING_NOTFOUND != nFndPos )
{
- // Span the Attribute over the area and delete the Character found at
+ // first delete the Character at the end - this allows insertion
+ // of an empty hint in SetAttr which would be removed by Delete
+ // (fdo#62536, AUTOFMT in Writer)
+ rDoc.Delete( nEndPos, nEndPos + 1 );
+ rDoc.Delete( nFndPos, nFndPos + 1 );
+ // Span the Attribute over the area
// the end.
if( '*' == cInsChar ) // Bold
{
SvxWeightItem aSvxWeightItem( WEIGHT_BOLD, SID_ATTR_CHAR_WEIGHT );
- rDoc.SetAttr( nFndPos + 1, nEndPos,
+ rDoc.SetAttr( nFndPos, nEndPos - 1,
SID_ATTR_CHAR_WEIGHT,
aSvxWeightItem);
}
else // underline
{
SvxUnderlineItem aSvxUnderlineItem( UNDERLINE_SINGLE, SID_ATTR_CHAR_UNDERLINE );
- rDoc.SetAttr( nFndPos + 1, nEndPos,
+ rDoc.SetAttr( nFndPos, nEndPos - 1,
SID_ATTR_CHAR_UNDERLINE,
aSvxUnderlineItem);
}
- rDoc.Delete( nEndPos, nEndPos + 1 );
- rDoc.Delete( nFndPos, nFndPos + 1 );
}
return STRING_NOTFOUND != nFndPos;
diff --git a/sw/inc/swtypes.hxx b/sw/inc/swtypes.hxx
index f5ba633..d3c6688 100644
--- a/sw/inc/swtypes.hxx
+++ b/sw/inc/swtypes.hxx
@@ -188,6 +188,8 @@ typedef sal_uInt16 SetAttrMode;
namespace nsSetAttrMode
{
const SetAttrMode SETATTR_DEFAULT = 0x0000; // Default.
+ /// @attention: DONTEXPAND does not work very well for CHARATR
+ /// because it can expand only the whole AUTOFMT or nothing
const SetAttrMode SETATTR_DONTEXPAND = 0x0001; // Don't expand text attribute any further.
const SetAttrMode SETATTR_DONTREPLACE = 0x0002; // Don't replace another text attribute.
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 748b5b2..c94b913 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -2475,7 +2475,31 @@ void SwDoc::SetFmtItemByAutoFmt( const SwPaM& rPam, const SfxItemSet& rSet )
SetRedlineMode_intern( (RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
}
+ xub_StrLen const nEnd(rPam.End()->nContent.GetIndex());
+ std::vector<sal_uInt16> whichIds;
+ SfxItemIter iter(rSet);
+ for (SfxPoolItem const* pItem = iter.FirstItem();
+ pItem; pItem = iter.NextItem())
+ {
+ whichIds.push_back(pItem->Which());
+ whichIds.push_back(pItem->Which());
+ }
+ whichIds.push_back(0);
+ SfxItemSet currentSet(GetAttrPool(), &whichIds[0]);
+ pTNd->GetAttr(currentSet, nEnd, nEnd, false, true, false);
+ for (size_t i = 0; whichIds[i]; i += 2)
+ { // yuk - want to explicitly set the pool defaults too :-/
+ currentSet.Put(currentSet.Get(whichIds[i], true));
+ }
+
InsertItemSet( rPam, rSet, nsSetAttrMode::SETATTR_DONTEXPAND );
+
+ // fdo#62536: DONTEXPAND does not work when there is already an AUTOFMT
+ // here, so insert the old attributes as an empty hint to stop expand
+ SwPaM endPam(*pTNd, nEnd);
+ endPam.SetMark();
+ InsertItemSet(endPam, currentSet, nsSetAttrMode::SETATTR_DEFAULT);
+
SetRedlineMode_intern( eOld );
}
commit d526b76c1dc0b3de564bc083821d512d41d5ab06
Author: Michael Stahl <mstahl at redhat.com>
Date: Sat Jun 15 21:25:27 2013 +0200
fdo#52028: sw: let text formatting ignore RSID in automatic styles
A suprising regression from 062eaeffe7cb986255063bb9b0a5f3fb3fc8e34c:
The RSID text attributes that are inserted for every user-inserted text
cause the text formatting (SwAttrIter) to create a lot more text portions,
and the portion breaks make font kerning impossible.
This is the only way i can think of to fix this problem; alternatives that
don't work are splitting the RSID out of the AUTOFMT hint into a separate
one and combining them in the sw UNO wrappers (fails because
SwXAutoStylesEnumerator actually does need to enumerate every AUTOFMT
including RSID), trying to detect and ignore them just in the text
formatting (the SwAttrIter cannot easily/cheaply detect when it's allowed
to skip), and having an internal subdivision inside the AUTOFMT hint (one
subsection for every RSID change) (which does not work because it cannot
ignore RSID-only AUTOFMTs completely).
Solve the problem with 2 additional flags on AUTOFMT and CHARFMT
attributes: FormatIgnoreStart and FormatIgnoreEnd, which indicate to
SwAttrIter::GetNextAttr() that the start or end of the hint should be
ignored, so that effectively it is merged with the preceding/subsequent
hint. Of course the UNO API does not respect the flags so we can store
the RSIDs in automatic styles.
The flags are maintained in SwpHints::MergePortions, which detects both
RSID-only AUTOFMT hints (which can be ignored completely), and the
situation of N CHARFMT hints + AUTOFMT hint vs. N CHARFMT hints +
AUTOFMT hint where the AUTOFMT hints differ only in their RSID attribute.
This means that MergePortions needs to be called more often now, in cases
where the ignore flags may have been invalidated, such as:
- insertion of text with possible DontExpand flag set on hints
- deletion of hints
- SETATTR_NOHINTADJUST mode
Change-Id: I1fb95a87c654c67d114f6f7f2c43b847c50b0ffa
(cherry picked from commit 6db39dbd7378351f6476f6db25eb7110c9cfb291)
diff --git a/sw/inc/ndhints.hxx b/sw/inc/ndhints.hxx
index 0d7a158..d8b6115 100644
--- a/sw/inc/ndhints.hxx
+++ b/sw/inc/ndhints.hxx
@@ -116,7 +116,7 @@ public:
inline sal_uInt16 Count() const { return m_HintStarts.size(); }
#ifdef DBG_UTIL
- bool Check() const;
+ bool Check(bool) const;
#endif
};
diff --git a/sw/inc/swtypes.hxx b/sw/inc/swtypes.hxx
index 187e070..f5ba633 100644
--- a/sw/inc/swtypes.hxx
+++ b/sw/inc/swtypes.hxx
@@ -192,6 +192,8 @@ namespace nsSetAttrMode
const SetAttrMode SETATTR_DONTREPLACE = 0x0002; // Don't replace another text attribute.
const SetAttrMode SETATTR_NOTXTATRCHR = 0x0004; // Don't insert 0xFF at attributes with no end.
+ /// attention: NOHINTADJUST prevents MergePortions!
+ /// when using this need to pay attention to ignore start/end flags of hint
const SetAttrMode SETATTR_NOHINTADJUST = 0x0008; // No merging of ranges.
const SetAttrMode SETATTR_NOFORMATATTR = 0x0010; // Do not change into format attribute.
const SetAttrMode SETATTR_DONTCHGNUMRULE = 0x0020; // Do not change NumRule.
diff --git a/sw/inc/txatbase.hxx b/sw/inc/txatbase.hxx
index 3a250f0..e69b088 100644
--- a/sw/inc/txatbase.hxx
+++ b/sw/inc/txatbase.hxx
@@ -55,6 +55,8 @@ private:
bool m_bDontExpandStart : 1; // don't expand start at paragraph start (ruby)
bool m_bNesting : 1; // SwTxtAttrNesting
bool m_bHasDummyChar : 1; // without end + meta
+ bool m_bFormatIgnoreStart : 1; ///< text formatting should ignore start
+ bool m_bFormatIgnoreEnd : 1; ///< text formatting should ignore end
protected:
SwTxtAttr( SfxPoolItem& rAttr, xub_StrLen nStart );
@@ -94,6 +96,10 @@ public:
bool IsDontExpandStartAttr() const { return m_bDontExpandStart; }
bool IsNesting() const { return m_bNesting; }
bool HasDummyChar() const { return m_bHasDummyChar; }
+ bool IsFormatIgnoreStart() const { return m_bFormatIgnoreStart; }
+ bool IsFormatIgnoreEnd () const { return m_bFormatIgnoreEnd ; }
+ void SetFormatIgnoreStart(bool bFlag) { m_bFormatIgnoreStart = bFlag; }
+ void SetFormatIgnoreEnd (bool bFlag) { m_bFormatIgnoreEnd = bFlag; }
inline const SfxPoolItem& GetAttr() const;
inline SfxPoolItem& GetAttr();
diff --git a/sw/source/core/inc/rolbck.hxx b/sw/source/core/inc/rolbck.hxx
index 62b0184..ddff2a2 100644
--- a/sw/source/core/inc/rolbck.hxx
+++ b/sw/source/core/inc/rolbck.hxx
@@ -122,6 +122,8 @@ class SwHistorySetTxt : public SwHistoryHint
const sal_uLong m_nNodeIndex;
const xub_StrLen m_nStart;
const xub_StrLen m_nEnd;
+ bool m_bFormatIgnoreStart : 1;
+ bool m_bFormatIgnoreEnd : 1;
public:
SwHistorySetTxt( SwTxtAttr* pTxtHt, sal_uLong nNode );
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index f9337b1..9123987 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1277,8 +1277,7 @@ void _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc,
if ( pNd->IsCntntNode() )
{
SwCntntNode* pNode = (SwCntntNode*)pNd;
- pFrm = pNode->IsTxtNode() ? new SwTxtFrm( (SwTxtNode*)pNode, pLay ) :
- pNode->MakeFrm( pLay );
+ pFrm = pNode->MakeFrm(pLay);
if( pPageMaker )
pPageMaker->CheckInsert( nIndex );
diff --git a/sw/source/core/layout/laycache.cxx b/sw/source/core/layout/laycache.cxx
index 1753d85..ebd9e72 100644
--- a/sw/source/core/layout/laycache.cxx
+++ b/sw/source/core/layout/laycache.cxx
@@ -843,8 +843,9 @@ bool SwLayHelper::CheckInsert( sal_uLong nNodeIndex )
}
else
{
- SwTxtFrm *pNew = new SwTxtFrm( ((SwTxtFrm*)rpFrm)->
- GetTxtNode(), rpFrm );
+ SwTxtFrm *const pNew = static_cast<SwTxtFrm*>(
+ static_cast<SwTxtFrm*>(rpFrm)
+ ->GetTxtNode()->MakeFrm(rpFrm));
pNew->ManipOfst( nOfst );
pNew->SetFollow( ((SwTxtFrm*)rpFrm)->GetFollow() );
((SwTxtFrm*)rpFrm)->SetFollow( pNew );
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index d95ee55..fba4898 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -311,12 +311,26 @@ xub_StrLen SwAttrIter::GetNextAttr( ) const
xub_StrLen nNext = STRING_LEN;
if( pHints )
{
- if (pHints->GetStartCount() > nStartIndex) // Gibt es noch Starts?
- nNext = (*pHints->GetStart(nStartIndex)->GetStart());
- if (pHints->GetEndCount() > nEndIndex) // Gibt es noch Enden?
+ // are there attribute starts left?
+ for (sal_uInt16 i = nStartIndex; i < pHints->GetStartCount(); ++i)
{
- xub_StrLen nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd());
- if ( nNextEnd<nNext ) nNext = nNextEnd; // Wer ist naeher?
+ SwTxtAttr *const pAttr(pHints->GetStart(i));
+ if (!pAttr->IsFormatIgnoreStart())
+ {
+ nNext = *pAttr->GetStart();
+ break;
+ }
+ }
+ // are there attribute ends left?
+ for (sal_uInt16 i = nEndIndex; i < pHints->GetEndCount(); ++i)
+ {
+ SwTxtAttr *const pAttr(pHints->GetEnd(i));
+ if (!pAttr->IsFormatIgnoreEnd())
+ {
+ xub_StrLen const nNextEnd = *pAttr->GetAnyEnd();
+ nNext = std::min(nNext, nNextEnd); // pick nearest one
+ break;
+ }
}
}
if (m_pTxtNode!=NULL) {
diff --git a/sw/source/core/txtnode/ndhints.cxx b/sw/source/core/txtnode/ndhints.cxx
index 2ebdef8..3537209 100644
--- a/sw/source/core/txtnode/ndhints.cxx
+++ b/sw/source/core/txtnode/ndhints.cxx
@@ -24,6 +24,8 @@
#ifdef DBG_UTIL
#include <pam.hxx>
+#include <fmtautofmt.hxx>
+#include <set>
#endif
@@ -171,7 +173,7 @@ sal_uInt16 SwpHintsArray::GetPos( const SwTxtAttr *pHt ) const
return false; \
}
-bool SwpHintsArray::Check() const
+bool SwpHintsArray::Check(bool bPortionsMerged) const
{
// 1) gleiche Anzahl in beiden Arrays
CHECK_ERR( m_HintStarts.size() == m_HintEnds.size(),
@@ -181,6 +183,23 @@ bool SwpHintsArray::Check() const
const SwTxtAttr *pLastStart = 0;
const SwTxtAttr *pLastEnd = 0;
+ std::set<SwTxtAttr const*> RsidOnlyAutoFmts;
+ if (bPortionsMerged)
+ {
+ for (sal_uInt16 i = 0; i < Count(); ++i)
+ {
+ SwTxtAttr const*const pHint(m_HintStarts[i]);
+ if (RES_TXTATR_AUTOFMT == pHint->Which())
+ {
+ boost::shared_ptr<SfxItemSet> const pSet(
+ pHint->GetAutoFmt().GetStyleHandle());
+ if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
+ {
+ RsidOnlyAutoFmts.insert(pHint);
+ }
+ }
+ }
+ }
for( sal_uInt16 i = 0; i < Count(); ++i )
{
@@ -270,6 +289,73 @@ bool SwpHintsArray::Check() const
"HintsCheck: Portion inconsistency. "
"This can be temporarily ok during undo operations" );
+ // 8 1/2) format ignore start/end flag check
+ // (problems because MergePortions buggy or not called)
+ if (bPortionsMerged)
+ {
+ if (RES_TXTATR_AUTOFMT == pHt->Which() ||
+ RES_TXTATR_CHARFMT == pHt->Which())
+ {
+ // mostly ignore the annoying no-length hints
+ // BuildPortions inserts these in the middle of an exsiting one
+ bool const bNoLength(*pHt->GetStart() == *pHt->GetEnd());
+ bool bNeedContinuation(!bNoLength && pHt->IsFormatIgnoreEnd());
+ bool bForbidContinuation(!bNoLength && !bNeedContinuation);
+ if (RES_TXTATR_AUTOFMT == pHt->Which())
+ {
+ if (RsidOnlyAutoFmts.find(pHt) != RsidOnlyAutoFmts.end())
+ {
+ assert(pHt->IsFormatIgnoreStart());
+ bNeedContinuation = false;
+ // don't forbid continuation - may be other hint here!
+ }
+ }
+ if (bNeedContinuation || bForbidContinuation)
+ {
+ bool bFound(false);
+ for (sal_uInt16 j = i + 1; j < Count(); ++j)
+ {
+ SwTxtAttr *const pOther(m_HintStarts[j]);
+ if (*pOther->GetStart() > *pHt->GetEnd())
+ {
+ break; // done
+ }
+ else if (*pOther->GetStart() == *pOther->GetAnyEnd())
+ {
+ continue; // empty hint: ignore
+ }
+ else if (*pOther->GetStart() == *pHt->GetEnd())
+ {
+ if (RES_TXTATR_AUTOFMT == pOther->Which() ||
+ RES_TXTATR_CHARFMT == pOther->Which())
+ { // multiple charfmt on same range must all match
+ if (bNeedContinuation)
+ {
+ assert(pOther->IsFormatIgnoreStart());
+ bFound = true;
+ }
+ else if (bForbidContinuation &&
+ (RsidOnlyAutoFmts.find(pOther) ==
+ RsidOnlyAutoFmts.end()))
+ {
+ assert(!pOther->IsFormatIgnoreStart());
+ }
+ }
+ }
+ }
+ if (bNeedContinuation)
+ {
+ assert(bFound); // ? can this happen temp. during undo?
+ }
+ }
+ }
+ else
+ {
+ assert(!pHt->IsFormatIgnoreStart());
+ assert(!pHt->IsFormatIgnoreEnd());
+ }
+ }
+
// 9) nesting portion check
if (pHtThis->IsNesting())
{
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 07f36ef..5c2326c 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -95,7 +95,7 @@ TYPEINIT1( SwTxtNode, SwCntntNode )
#ifdef DBG_UTIL
#define CHECK_SWPHINTS(pNd) { if( pNd->GetpSwpHints() && \
!pNd->GetDoc()->IsInReading() ) \
- pNd->GetpSwpHints()->Check(); }
+ pNd->GetpSwpHints()->Check(true); }
#else
#define CHECK_SWPHINTS(pNd)
#endif
@@ -263,6 +263,12 @@ SwTxtNode::~SwTxtNode()
SwCntntFrm *SwTxtNode::MakeFrm( SwFrm* pSib )
{
+ // fdo#52028: ODF file import does not result in MergePortions being called
+ // for every attribute, since that would be inefficient. So call it here.
+ if (m_pSwpHints)
+ {
+ m_pSwpHints->MergePortions(*this);
+ }
SwCntntFrm *pFrm = new SwTxtFrm( this, pSib );
return pFrm;
}
@@ -883,6 +889,7 @@ void SwTxtNode::Update( SwIndex const & rPos, const xub_StrLen nChangeLen,
{
bool bNoExp = false;
bool bResort = false;
+ bool bMergePortionsNeeded = false;
const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
@@ -929,6 +936,11 @@ void SwTxtNode::Update( SwIndex const & rPos, const xub_StrLen nChangeLen,
{
pHint->SetDontExpand( false );
bResort = true;
+ // could have a continuation with IgnoreStart()...
+ if (pHint->IsFormatIgnoreEnd())
+ {
+ bMergePortionsNeeded = true;
+ }
if ( pHint->IsCharFmtAttr() )
{
bNoExp = true;
@@ -969,7 +981,11 @@ void SwTxtNode::Update( SwIndex const & rPos, const xub_StrLen nChangeLen,
}
}
}
- if ( bResort )
+ if (bMergePortionsNeeded)
+ {
+ m_pSwpHints->MergePortions(*this); // does Resort too
+ }
+ else if (bResort)
{
m_pSwpHints->Resort();
}
@@ -1745,6 +1761,7 @@ OUString SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx,
if ( HasHints() )
{
+ bool bMergePortionsNeeded(false);
for ( sal_uInt16 i = 0; i < m_pSwpHints->Count() &&
rIdx >= *(*m_pSwpHints)[i]->GetStart(); ++i )
{
@@ -1764,6 +1781,14 @@ OUString SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx,
*pHt->GetStart() = *pHt->GetStart() - nLen;
*pEndIdx = *pEndIdx - nLen;
m_pSwpHints->DeleteAtPos(i);
+ // could be that pHt has IsFormatIgnoreEnd set, and it's
+ // not a RSID-only hint - now we have the inserted text
+ // between pHt and its continuation... which we don't know.
+ // punt the job to MergePortions below.
+ if (pHt->IsFormatIgnoreEnd())
+ {
+ bMergePortionsNeeded = true;
+ }
InsertHint( pHt, nsSetAttrMode::SETATTR_NOHINTADJUST );
}
// empty hints at insert position?
@@ -1792,9 +1817,14 @@ OUString SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx,
// Kein Feld, am Absatzanfang, HintExpand
m_pSwpHints->DeleteAtPos(i);
*pHt->GetStart() = *pHt->GetStart() - nLen;
+ // no effect on format ignore flags here (para start)
InsertHint( pHt, nsSetAttrMode::SETATTR_NOHINTADJUST );
}
}
+ if (bMergePortionsNeeded)
+ {
+ m_pSwpHints->MergePortions(*this);
+ }
TryDeleteSwpHints();
}
@@ -2042,6 +2072,7 @@ void SwTxtNode::CutImpl( SwTxtNode * const pDest, const SwIndex & rDestStart,
// 2. Attribute verschieben
// durch das Attribute-Array, bis der Anfang des Geltungsbereiches
// des Attributs hinter dem zu verschiebenden Bereich liegt
+ bool bMergePortionsNeeded(false);
sal_uInt16 nAttrCnt = 0;
while ( m_pSwpHints && (nAttrCnt < m_pSwpHints->Count()) )
{
@@ -2085,6 +2116,10 @@ void SwTxtNode::CutImpl( SwTxtNode * const pDest, const SwIndex & rDestStart,
// Attribut verschieben
m_pSwpHints->Delete( pHt );
// die Start/End Indicies neu setzen
+ if (pHt->IsFormatIgnoreStart() || pHt->IsFormatIgnoreEnd())
+ {
+ bMergePortionsNeeded = true;
+ }
*pHt->GetStart() =
nDestStart + (nAttrStartIdx - nTxtStartIdx);
if( pEndIdx )
@@ -2164,6 +2199,11 @@ void SwTxtNode::CutImpl( SwTxtNode * const pDest, const SwIndex & rDestStart,
Update( rStart, nLen, sal_True, sal_True );
}
+ if (bMergePortionsNeeded)
+ {
+ m_pSwpHints->MergePortions(*this);
+ }
+
CHECK_SWPHINTS(this);
}
diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx
index 71da72e..9bcfcf4 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -72,9 +72,11 @@
#include <map>
#ifdef DBG_UTIL
-#define CHECK Check();
+#define CHECK Check(true);
+#define CHECK_NOTMERGED Check(false);
#else
#define CHECK
+#define CHECK_NOTMERGED
#endif
using namespace ::com::sun::star::i18n;
@@ -649,7 +651,7 @@ void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint,
#ifdef DBG_UTIL
if( !rNode.GetDoc()->IsInReading() )
- CHECK;
+ CHECK_NOTMERGED; // ignore flags not set properly yet, don't check them
#endif
//
@@ -1563,6 +1565,8 @@ void SwTxtNode::DeleteAttributes( const sal_uInt16 nWhich,
const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
if ( pHiddenItem )
SetCalcHiddenCharFlags();
+ // for auto styles DeleteAttributes is only called from Undo
+ // so it shouldn't need to care about ignore start/end flags
}
xub_StrLen const * const pEndIdx = pTxtHt->GetEnd();
@@ -2306,6 +2310,9 @@ SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
aCurRange = aRange.second;
}
+ // hints were directly inserted, so need to fix the Ignore flags now
+ m_pSwpHints->MergePortions(*this);
+
// 3. Clear items from the node
std::vector<sal_uInt16> aClearedIds;
lcl_FillWhichIds(i_rAttrSet, aClearedIds);
@@ -2497,8 +2504,9 @@ bool SwpHints::MergePortions( SwTxtNode& rNode )
SwpHintsArray::Resort();
bool bRet = false;
- typedef std::multimap< int, SwTxtAttr* > PortionMap;
+ typedef std::multimap< int, std::pair<SwTxtAttr*, bool> > PortionMap;
PortionMap aPortionMap;
+ std::map<int, bool> RsidOnlyAutoFmtFlagMap;
xub_StrLen nLastPorStart = STRING_LEN;
sal_uInt16 i = 0;
int nKey = 0;
@@ -2513,14 +2521,45 @@ bool SwpHints::MergePortions( SwTxtNode& rNode )
//RES_TXTATR_INETFMT != pHt->Which() )
continue;
+ bool isRsidOnlyAutoFmt(false);
+ // check for RSID-only AUTOFMT
+ if (RES_TXTATR_AUTOFMT == pHt->Which())
+ {
+ boost::shared_ptr<SfxItemSet> const pSet(
+ pHt->GetAutoFmt().GetStyleHandle());
+ if ((pSet->Count() == 1) && pSet->GetItem(RES_CHRATR_RSID, false))
+ {
+ // fdo#52028: this one has _only_ RSID => ignore it completely
+ if (!pHt->IsFormatIgnoreStart() || !pHt->IsFormatIgnoreEnd())
+ {
+ NoteInHistory(pHt);
+ pHt->SetFormatIgnoreStart(true);
+ pHt->SetFormatIgnoreEnd (true);
+ NoteInHistory(pHt, true);
+ }
+ isRsidOnlyAutoFmt = true;
+ }
+ }
+
+ if (*pHt->GetStart() == *pHt->GetEnd())
+ {
+ // no-length hints are a disease. ignore them here.
+ // the SwAttrIter::SeekFwd will not call Rst/Chg for them.
+ continue;
+ }
+
const xub_StrLen nPorStart = *pHt->GetStart();
- if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
+ if (nPorStart != nLastPorStart)
++nKey;
nLastPorStart = nPorStart;
- aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
+ aPortionMap.insert(std::make_pair(nKey,
+ std::make_pair(pHt, isRsidOnlyAutoFmt)));
+ RsidOnlyAutoFmtFlagMap[nKey] = isRsidOnlyAutoFmt;
}
// check if portion i can be merged with portion i+1:
+ // note: need to include i=0 to set IgnoreStart and j=nKey+1 to reset
+ // IgnoreEnd at first / last portion
i = 0;
int j = i + 1;
while ( i <= nKey )
@@ -2530,37 +2569,128 @@ bool SwpHints::MergePortions( SwTxtNode& rNode )
PortionMap::iterator aIter1 = aRange1.first;
PortionMap::iterator aIter2 = aRange2.first;
- bool bMerge = true;
- const sal_uInt16 nAttributesInPor1 = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
- const sal_uInt16 nAttributesInPor2 = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
-
- if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
+ enum { MATCH, DIFFER_ONLY_RSID, DIFFER } eMerge(MATCH);
+ size_t const nAttributesInPor1 = std::distance(aRange1.first, aRange1.second);
+ size_t const nAttributesInPor2 = std::distance(aRange2.first, aRange2.second);
+ bool const isRsidOnlyAutoFmt1(RsidOnlyAutoFmtFlagMap[i]);
+ bool const isRsidOnlyAutoFmt2(RsidOnlyAutoFmtFlagMap[j]);
+
+ // if both have one they could be equal, but not if only one has it
+ bool const bSkipRsidOnlyAutoFmt(nAttributesInPor1 != nAttributesInPor2);
+
+ // this loop needs to handle the case where one has a CHARFMT and the
+ // other CHARFMT + RSID-only AUTOFMT, so...
+ // want to skip over RSID-only AUTOFMT here, hence the -1
+ if ((nAttributesInPor1 - ((isRsidOnlyAutoFmt1) ? 1 : 0)) ==
+ (nAttributesInPor2 - ((isRsidOnlyAutoFmt2) ? 1 : 0))
+ && (nAttributesInPor1 != 0 || nAttributesInPor2 != 0))
{
- while ( aIter1 != aRange1.second )
+ // _if_ there is one element more either in aRange1 or aRange2
+ // it _must_ be an RSID-only AUTOFMT, which can be ignored here...
+ // But if both have RSID-only AUTOFMT they could be equal, no skip!
+ while (aIter1 != aRange1.second || aIter2 != aRange2.second)
{
- const SwTxtAttr* p1 = (*aIter1).second;
- const SwTxtAttr* p2 = (*aIter2).second;
- if ( *p1->GetEnd() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
+ // first of all test if there's no gap (before skipping stuff!)
+ if (aIter1 != aRange1.second && aIter2 != aRange2.second &&
+ *aIter1->second.first->GetEnd() < *aIter2->second.first->GetStart())
{
- bMerge = false;
+ eMerge = DIFFER;
break;
}
+ // skip it - cannot be equal if bSkipRsidOnlyAutoFmt is set
+ if (bSkipRsidOnlyAutoFmt
+ && aIter1 != aRange1.second && aIter1->second.second)
+ {
+ assert(DIFFER != eMerge);
+ eMerge = DIFFER_ONLY_RSID;
+ ++aIter1;
+ continue;
+ }
+ if (bSkipRsidOnlyAutoFmt
+ && aIter2 != aRange2.second && aIter2->second.second)
+ {
+ assert(DIFFER != eMerge);
+ eMerge = DIFFER_ONLY_RSID;
+ ++aIter2;
+ continue;
+ }
+ assert(aIter1 != aRange1.second && aIter2 != aRange2.second);
+ SwTxtAttr const*const p1 = aIter1->second.first;
+ SwTxtAttr const*const p2 = aIter2->second.first;
+ if (p1->Which() != p2->Which())
+ {
+ eMerge = DIFFER;
+ break;
+ }
+ if (!(*p1 == *p2))
+ {
+ // fdo#52028: for auto styles, check if they differ only
+ // in the RSID, which should have no effect on text layout
+ if (RES_TXTATR_AUTOFMT == p1->Which())
+ {
+ SfxItemSet set1(*p1->GetAutoFmt().GetStyleHandle());
+ SfxItemSet set2(*p2->GetAutoFmt().GetStyleHandle());
+
+ set1.ClearItem(RES_CHRATR_RSID);
+ set2.ClearItem(RES_CHRATR_RSID);
+
+ // sadly SfxItemSet::operator== does not seem to work?
+ SfxItemIter iter1(set1);
+ SfxItemIter iter2(set2);
+ if (set1.Count() == set2.Count())
+ {
+ for (SfxPoolItem const* pItem1 = iter1.FirstItem(),
+ * pItem2 = iter2.FirstItem();
+ pItem1 && pItem2;
+ pItem1 = iter1.NextItem(),
+ pItem2 = iter2.NextItem())
+ {
+ if (pItem1 != pItem2 ||
+ pItem1->Which() != pItem2->Which() ||
+ *pItem1 != *pItem2)
+ {
+ eMerge = DIFFER;
+ break;
+ }
+ if (iter1.IsAtEnd())
+ {
+ assert(iter2.IsAtEnd());
+ eMerge = DIFFER_ONLY_RSID;
+ }
+ }
+ if (DIFFER == eMerge)
+ break; // outer loop too
+ }
+ else
+ {
+ eMerge = DIFFER;
+ break;
+ }
+ }
+ else
+ {
+ eMerge = DIFFER;
+ break;
+ }
+ }
++aIter1;
++aIter2;
}
}
else
{
- bMerge = false;
+ eMerge = DIFFER;
}
- if ( bMerge )
+ if (MATCH == eMerge)
{
+ // important: delete second range so any IgnoreStart on the first
+ // range is still valid
// erase all elements with key i + 1
xub_StrLen nNewPortionEnd = 0;
for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
{
- SwTxtAttr* p2 = (*aIter2).second;
+ SwTxtAttr *const p2 = aIter2->second.first;
nNewPortionEnd = *p2->GetEnd();
const sal_uInt16 nCountBeforeDelete = Count();
@@ -2577,7 +2707,7 @@ bool SwpHints::MergePortions( SwTxtNode& rNode )
aRange1 = aPortionMap.equal_range( i );
for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
{
- SwTxtAttr* p1 = (*aIter1).second;
+ SwTxtAttr *const p1 = aIter1->second.first;
NoteInHistory( p1 );
*p1->GetEnd() = nNewPortionEnd;
NoteInHistory( p1, true );
@@ -2586,8 +2716,37 @@ bool SwpHints::MergePortions( SwTxtNode& rNode )
}
else
{
- ++i;
- j = i + 1;
+ // when not merging the ignore flags need to be either set or reset
+ // (reset too in case one of the autofmts was recently changed)
+ bool const bSetIgnoreFlag(DIFFER_ONLY_RSID == eMerge);
+ for (aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1)
+ {
+ if (!aIter1->second.second) // already set above, don't change
+ {
+ SwTxtAttr *const pCurrent(aIter1->second.first);
+ if (pCurrent->IsFormatIgnoreEnd() != bSetIgnoreFlag)
+ {
+ NoteInHistory(pCurrent);
+ pCurrent->SetFormatIgnoreEnd(bSetIgnoreFlag);
+ NoteInHistory(pCurrent, true);
+ }
+ }
+ }
+ for (aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2)
+ {
+ if (!aIter2->second.second) // already set above, don't change
+ {
+ SwTxtAttr *const pCurrent(aIter2->second.first);
+ if (pCurrent->IsFormatIgnoreStart() != bSetIgnoreFlag)
+ {
+ NoteInHistory(pCurrent);
+ pCurrent->SetFormatIgnoreStart(bSetIgnoreFlag);
+ NoteInHistory(pCurrent, true);
+ }
+ }
+ }
+ i = j; // ++i not enough: i + 1 may have been deleted (MATCH)!
+ ++j;
}
}
@@ -2676,6 +2835,16 @@ bool SwpHints::TryInsertHint( SwTxtAttr* const pHint, SwTxtNode &rNode,
// #i75430# Recalc hidden flags if necessary
case RES_TXTATR_AUTOFMT:
{
+ if (*pHint->GetStart() == *pHint->GetEnd())
+ {
+ boost::shared_ptr<SfxItemSet> const pSet(
+ pHint->GetAutoFmt().GetStyleHandle());
+ if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
+ { // empty range RSID-only hints could cause trouble, there's no
+ rNode.DestroyAttr(pHint); // need for them so don't insert
+ return false;
+ }
+ }
// Check if auto style contains hidden attribute:
const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
if ( pHiddenItem )
@@ -2974,7 +3143,7 @@ void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
}
CalcFlags();
- CHECK;
+ CHECK_NOTMERGED; // called from BuildPortions
}
// Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
diff --git a/sw/source/core/txtnode/txatbase.cxx b/sw/source/core/txtnode/txatbase.cxx
index e0acb29..e59e969 100644
--- a/sw/source/core/txtnode/txatbase.cxx
+++ b/sw/source/core/txtnode/txatbase.cxx
@@ -34,6 +34,8 @@ SwTxtAttr::SwTxtAttr( SfxPoolItem& rAttr, xub_StrLen nStart )
, m_bDontExpandStart( false )
, m_bNesting( false )
, m_bHasDummyChar( false )
+ , m_bFormatIgnoreStart(false)
+ , m_bFormatIgnoreEnd(false)
{
}
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index d498eb7..92a9c8b 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -582,8 +582,8 @@ void SwTxtNode::RstAttr(const SwIndex &rIdx, xub_StrLen nLen, sal_uInt16 nWhich,
if (bChanged)
{
if ( HasHints() )
- {
- m_pSwpHints->Resort();
+ { // possibly sometimes Resort would be sufficient, but...
+ m_pSwpHints->MergePortions(*this);
}
//TxtFrm's reagieren auf aHint, andere auf aNew
SwUpdateAttr aHint( nMin, nMax, 0 );
diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx
index ced76e5..59cfec6 100644
--- a/sw/source/core/undo/rolbck.cxx
+++ b/sw/source/core/undo/rolbck.cxx
@@ -195,6 +195,8 @@ SwHistorySetTxt::SwHistorySetTxt( SwTxtAttr* pTxtHt, sal_uLong nNodePos )
, m_nNodeIndex( nNodePos )
, m_nStart( *pTxtHt->GetStart() )
, m_nEnd( *pTxtHt->GetAnyEnd() )
+ , m_bFormatIgnoreStart(pTxtHt->IsFormatIgnoreStart())
+ , m_bFormatIgnoreEnd (pTxtHt->IsFormatIgnoreEnd ())
{
// Caution: the following attributes generate no format attributes:
// - NoLineBreak, NoHypen, Inserted, Deleted
@@ -234,9 +236,19 @@ void SwHistorySetTxt::SetInDoc( SwDoc* pDoc, bool )
if ( pTxtNd )
{
- pTxtNd->InsertItem( *m_pAttr, m_nStart, m_nEnd,
+ SwTxtAttr *const pAttr = pTxtNd->InsertItem(*m_pAttr, m_nStart, m_nEnd,
nsSetAttrMode::SETATTR_NOTXTATRCHR |
nsSetAttrMode::SETATTR_NOHINTADJUST );
+ // shouldn't be possible to hit any error/merging path from here
+ assert(pAttr);
+ if (m_bFormatIgnoreStart)
+ {
+ pAttr->SetFormatIgnoreStart(true);
+ }
+ if (m_bFormatIgnoreEnd)
+ {
+ pAttr->SetFormatIgnoreEnd(true);
+ }
}
}
commit c69325ea81e3fce6e935c63ba00dfad2a1e74c4f
Author: Michael Stahl <mstahl at redhat.com>
Date: Wed Jun 19 20:52:11 2013 +0200
sw: implement proper Undo for SwDoc::UpdateRsid
This is annoying because it's not possible to use StartUndo/EndUndo
because that would break grouping via SwUndoInsert::CanGrouping();
also SwUndoAttr is somehow incapable of removing the inserted hints of a
grouped insert (it seems to leave no-length hints behind); so add an
explicit call to DeleteAttributes which should avoid the no-length
hints.
Change-Id: I1533daed9b2cf59886f380141b4eace4b22c15e0
(cherry picked from commit e012f326c1c32c053304998a6826cb322f2c7728)
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index f0b97f0..13256ea7 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -868,7 +868,6 @@ public:
virtual bool Overwrite(const SwPaM &rRg, const String& rStr);
virtual bool InsertString(const SwPaM &rRg, const String&,
const enum InsertFlags nInsertMode = INS_EMPTYEXPAND );
- virtual bool UpdateRsid( SwTxtNode *pTxtNode, xub_StrLen nStt, xub_StrLen nEnd );
virtual bool UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal = 0 );
virtual bool UpdateRsid( const SwPaM &rRg, xub_StrLen nLen );
virtual SwFlyFrmFmt* Insert(const SwPaM &rRg, const String& rGrfName, const String& rFltName, const Graphic* pGraphic,
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index db23e35..ba3c943 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -52,7 +52,6 @@
#include <editeng/forbiddencharacterstable.hxx>
#include <svx/svdmodel.hxx>
#include <editeng/pbinitem.hxx>
-#include <editeng/rsiditem.hxx>
#include <unotools/charclass.hxx>
#include <unotools/localedatawrapper.hxx>
#include <vcl/timer.hxx>
@@ -1111,40 +1110,6 @@ SwFieldType *SwDoc::GetSysFldType( const sal_uInt16 eWhich ) const
return 0;
}
-/// Set the rsid from nStt to nEnd of pTxtNode to the current session number
-bool SwDoc::UpdateRsid( SwTxtNode *pTxtNode, xub_StrLen nStt, xub_StrLen nEnd )
-{
- if ( !pTxtNode )
- {
- return false;
- }
-
- SvxRsidItem aRsid( mnRsid, RES_CHRATR_RSID );
- SwTxtAttr* pAttr = MakeTxtAttr( *this, aRsid, nStt, nEnd );
- return pTxtNode->InsertHint( pAttr, INS_DEFAULT );
-}
-
-/// Set the rsid of the next nLen symbols of rRg to the current session number
-bool SwDoc::UpdateRsid( const SwPaM &rRg, const xub_StrLen nLen )
-{
- const SwPosition* pPos = rRg.GetPoint();
- SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode();
- xub_StrLen nInsPos = pPos->nContent.GetIndex();
-
- return UpdateRsid( pTxtNode, nInsPos - nLen, nInsPos );
-}
-
-bool SwDoc::UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal )
-{
- if ( !pTxtNode )
- {
- return false;
- }
-
- SvxRsidItem aRsid( nVal ? nVal : mnRsid, RES_PARATR_RSID );
- return pTxtNode->SetAttr( aRsid );
-}
-
void SwDoc::SetDocStat( const SwDocStat& rStat )
{
*mpDocStat = rStat;
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 49a36da..748b5b2 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -26,6 +26,7 @@
#include <editeng/langitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/formatbreakitem.hxx>
+#include <editeng/rsiditem.hxx>
#include <svl/whiter.hxx>
#include <svl/zforlist.hxx>
#include <comphelper/processfactory.hxx>
@@ -44,6 +45,7 @@
#include <pam.hxx>
#include <UndoCore.hxx>
#include <UndoAttribute.hxx>
+#include <UndoInsert.hxx>
#include <ndgrf.hxx>
#include <pagedesc.hxx> // For special treatment in InsFrmFmt
#include <rolbck.hxx> // Undo-Attr
@@ -63,6 +65,7 @@
#include <fmtautofmt.hxx>
#include <istyleaccess.hxx>
#include <SwUndoFmt.hxx>
+#include <UndoManager.hxx>
#include <docsh.hxx>
using namespace ::com::sun::star::i18n;
@@ -1098,6 +1101,47 @@ bool SwDoc::InsertItemSet ( const SwPaM &rRg, const SfxItemSet &rSet,
return bRet;
}
+/// Set the rsid of the next nLen symbols of rRg to the current session number
+bool SwDoc::UpdateRsid( const SwPaM &rRg, const xub_StrLen nLen )
+{
+ SwTxtNode *pTxtNode = rRg.GetPoint()->nNode.GetNode().GetTxtNode();
+ if (!pTxtNode)
+ {
+ return false;
+ }
+ xub_StrLen const nStart(rRg.GetPoint()->nContent.GetIndex() - nLen);
+ SvxRsidItem aRsid( mnRsid, RES_CHRATR_RSID );
+
+ SfxItemSet aSet(GetAttrPool(), RES_CHRATR_RSID, RES_CHRATR_RSID);
+ aSet.Put(aRsid);
+ bool const bRet(pTxtNode->SetAttr(aSet, nStart,
+ rRg.GetPoint()->nContent.GetIndex(), nsSetAttrMode::SETATTR_DEFAULT));
+
+ if (bRet && GetIDocumentUndoRedo().DoesUndo())
+ {
+ SwUndo *const pLastUndo = GetUndoManager().GetLastUndo();
+ SwUndoInsert *const pUndoInsert(dynamic_cast<SwUndoInsert*>(pLastUndo));
+ // this function is called after Insert so expects to find SwUndoInsert
+ assert(pUndoInsert);
+ if (pUndoInsert)
+ {
+ pUndoInsert->SetWithRsid();
+ }
+ }
+ return bRet;
+}
+
+bool SwDoc::UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal )
+{
+ if (!pTxtNode)
+ {
+ return false;
+ }
+
+ SvxRsidItem aRsid( nVal ? nVal : mnRsid, RES_PARATR_RSID );
+ return pTxtNode->SetAttr( aRsid );
+}
+
/// Set the attribute according to the stated format.
/// If Undo is enabled, the old values is added to the Undo history.
void SwDoc::SetAttr( const SfxPoolItem& rAttr, SwFmt& rFmt )
diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx
index 8185efb..c4a9898 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -108,14 +108,17 @@ void SwEditShell::Insert2(const String &rStr, const bool bForceExpandHints )
const bool bSuccess =
GetDoc()->InsertString(*_pStartCrsr, rStr, nInsertFlags);
OSL_ENSURE( bSuccess, "Doc->Insert() failed." );
- (void) bSuccess;
- GetDoc()->UpdateRsid( *_pStartCrsr, rStr.Len() );
+ if (bSuccess)
+ {
+ GetDoc()->UpdateRsid( *_pStartCrsr, rStr.Len() );
- // Set paragraph rsid if beginning of paragraph
- SwTxtNode *pTxtNode = _pStartCrsr->GetPoint()->nNode.GetNode().GetTxtNode();
- if( pTxtNode && pTxtNode->Len() == 1)
- GetDoc()->UpdateParRsid( pTxtNode );
+ // Set paragraph rsid if beginning of paragraph
+ SwTxtNode *const pTxtNode =
+ _pStartCrsr->GetPoint()->nNode.GetNode().GetTxtNode();
+ if( pTxtNode && pTxtNode->Len() == 1)
+ GetDoc()->UpdateParRsid( pTxtNode );
+ }
SaveTblBoxCntnt( _pStartCrsr->GetPoint() );
diff --git a/sw/source/core/inc/UndoInsert.hxx b/sw/source/core/inc/UndoInsert.hxx
index e16644c..b4689d3 100644
--- a/sw/source/core/inc/UndoInsert.hxx
+++ b/sw/source/core/inc/UndoInsert.hxx
@@ -40,6 +40,7 @@ class SwUndoInsert: public SwUndo, private SwUndoSaveCntnt
xub_StrLen nCntnt, nLen;
sal_Bool bIsWordDelim : 1;
sal_Bool bIsAppend : 1;
+ sal_Bool m_bWithRsid : 1;
const IDocumentContentOperations::InsertFlags m_nInsertFlags;
@@ -76,6 +77,8 @@ public:
*/
virtual SwRewriter GetRewriter() const;
+ void SetWithRsid() { m_bWithRsid = true; }
+
DECL_FIXEDMEMPOOL_NEWDEL(SwUndoInsert)
};
diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx
index eafb7f4..cbacd83 100644
--- a/sw/source/core/undo/unins.cxx
+++ b/sw/source/core/undo/unins.cxx
@@ -115,6 +115,7 @@ SwUndoInsert::SwUndoInsert( const SwNodeIndex& rNd, xub_StrLen nCnt,
: SwUndo(UNDO_TYPING), pTxt( 0 ), pRedlData( 0 ),
nNode( rNd.GetIndex() ), nCntnt(nCnt), nLen(nL),
bIsWordDelim( bWDelim ), bIsAppend( sal_False )
+ , m_bWithRsid(false)
, m_nInsertFlags(nInsertFlags)
{
Init(rNd);
@@ -125,6 +126,7 @@ SwUndoInsert::SwUndoInsert( const SwNodeIndex& rNd )
: SwUndo(UNDO_SPLITNODE), pTxt( 0 ),
pRedlData( 0 ), nNode( rNd.GetIndex() ), nCntnt(0), nLen(1),
bIsWordDelim( sal_False ), bIsAppend( sal_True )
+ , m_bWithRsid(false)
, m_nInsertFlags(IDocumentContentOperations::INS_EMPTYEXPAND)
{
Init(rNd);
@@ -208,8 +210,6 @@ SwUndoInsert::~SwUndoInsert()
delete pUndoTxt;
}
-
-
void SwUndoInsert::UndoImpl(::sw::UndoRedoContext & rContext)
{
SwDoc *const pTmpDoc = & rContext.GetDoc();
@@ -249,6 +249,18 @@ void SwUndoInsert::UndoImpl(::sw::UndoRedoContext & rContext)
aPaM.GetPoint()->nContent -= nLen;
if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
pTmpDoc->DeleteRedline( aPaM, true, USHRT_MAX );
+ if (m_bWithRsid)
+ {
+ // RSID was added: remove any CHARFMT/AUTOFMT that may be
+ // set on the deleted text; EraseText will leave empty
+ // ones behind otherwise
+ pTxtNode->DeleteAttributes(RES_TXTATR_AUTOFMT,
+ aPaM.GetPoint()->nContent.GetIndex(),
+ aPaM.GetMark()->nContent.GetIndex());
+ pTxtNode->DeleteAttributes(RES_TXTATR_CHARFMT,
+ aPaM.GetPoint()->nContent.GetIndex(),
+ aPaM.GetMark()->nContent.GetIndex());
+ }
RemoveIdxFromRange( aPaM, sal_False );
pTxt = new String( pTxtNode->GetTxt().copy(nCntnt-nLen, nLen) );
pTxtNode->EraseText( aPaM.GetPoint()->nContent, nLen );
@@ -354,6 +366,11 @@ void SwUndoInsert::RedoImpl(::sw::UndoRedoContext & rContext)
m_nInsertFlags) );
assert(ins.getLength() == pTxt->Len()); // must succeed
DELETEZ( pTxt );
+ if (m_bWithRsid) // re-insert RSID
+ {
+ SwPaM pam(*pPam->GetMark(), 0); // mark -> point
+ pTmpDoc->UpdateRsid(pam, ins.getLength());
+ }
}
else
{
@@ -384,7 +401,6 @@ void SwUndoInsert::RedoImpl(::sw::UndoRedoContext & rContext)
pUndoTxt = GetTxtFromDoc();
}
-
void SwUndoInsert::RepeatImpl(::sw::RepeatContext & rContext)
{
if( !nLen )
commit 92c0da9ed4ba74c57f3151cc968d8ad83c4fce99
Author: Michael Stahl <mstahl at redhat.com>
Date: Tue Jun 18 00:57:02 2013 +0200
libmwaw: fix infinite loop in findCentralDirectoryEnd
Change-Id: I36ec7ad735fa15cfda88167b11a922883ef2bb72
(cherry picked from commit e3e2cf30373446e5511b12467e3b8008311c81c2)
diff --git a/libmwaw/UnpackedTarball_libmwaw.mk b/libmwaw/UnpackedTarball_libmwaw.mk
index 8e3be68..a17961d 100644
--- a/libmwaw/UnpackedTarball_libmwaw.mk
+++ b/libmwaw/UnpackedTarball_libmwaw.mk
@@ -13,6 +13,7 @@ $(eval $(call gb_UnpackedTarball_set_tarball,libmwaw,$(MWAW_TARBALL)))
$(eval $(call gb_UnpackedTarball_add_patches,libmwaw,\
libmwaw/libmwaw-0.1.9.patch.1 \
+ libmwaw/libmwaw-infinite-loop.patch.1 \
))
# vim: set noet sw=4 ts=4:
diff --git a/libmwaw/libmwaw-infinite-loop.patch.1 b/libmwaw/libmwaw-infinite-loop.patch.1
new file mode 100644
index 0000000..9c8e3a8
--- /dev/null
+++ b/libmwaw/libmwaw-infinite-loop.patch.1
@@ -0,0 +1,32 @@
+fix infinite loop in findCentralDirectoryEnd
+
+WPXSvInputStreamImpl::seek returns -1 if it catches an exception
+
+--- libmwaw/src/lib/MWAWZipStream.cxx 2013-06-18 00:37:57.208657845 +0200
++++ libmwaw/src/lib/MWAWZipStream.cxx 2013-06-18 00:48:20.971665257 +0200
+@@ -258,18 +258,20 @@
+
+ static bool findCentralDirectoryEnd(WPXInputStream *input)
+ {
+- input->seek(0, WPX_SEEK_SET);
++ // seek returns -1 both on error and on seek to position post-the-end
++ int ret = input->seek(0, WPX_SEEK_SET);
+ try {
+- while (!input->atEOS())
+- input->seek(1024, WPX_SEEK_CUR);
++ while (-1 != ret && !input->atEOS())
++ ret = input->seek(1024, WPX_SEEK_CUR);
+ input->seek(-1024, WPX_SEEK_CUR);
+- while (!input->atEOS()) {
++ ret = 0; // perhaps it's smaller than 1024?
++ while (-1 != ret && !input->atEOS()) {
+ unsigned signature = getInt(input);
+ if (signature == CDIR_END_SIG) {
+ input->seek(-4, WPX_SEEK_CUR);
+ return true;
+ } else
+- input->seek(-3, WPX_SEEK_CUR);
++ ret = input->seek(-3, WPX_SEEK_CUR);
+ }
+ } catch (...) {
+ return false;
More information about the Libreoffice-commits
mailing list