[Libreoffice-commits] core.git: 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:37:42 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 fe444d1f74abe417962be0bcd3340f40f2446b58
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

diff --git a/editeng/source/misc/svxacorr.cxx b/editeng/source/misc/svxacorr.cxx
index d119385..883c1f1 100644
--- a/editeng/source/misc/svxacorr.cxx
+++ b/editeng/source/misc/svxacorr.cxx
@@ -762,24 +762,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 6db39dbd7378351f6476f6db25eb7110c9cfb291
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

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 02ea344..4d070e1 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 8d4cdaf..7b3b98d 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 691da30..016d56a 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -584,8 +584,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 e012f326c1c32c053304998a6826cb322f2c7728
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

diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index ee66745..e3eeb61 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -866,7 +866,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 42aa6df..139735d 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 a13598a..c49cb15 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -95,14 +95,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 e3e2cf30373446e5511b12467e3b8008311c81c2
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

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