LCOV - code coverage report
Current view: top level - sw/source/core/txtnode - thints.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1238 1473 84.0 %
Date: 2015-06-13 12:38:46 Functions: 55 57 96.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <hintids.hxx>
      21             : #include <sot/factory.hxx>
      22             : #include <editeng/xmlcnitm.hxx>
      23             : #include <svl/whiter.hxx>
      24             : #include <svl/itemiter.hxx>
      25             : #include <svl/stylepool.hxx>
      26             : #include <editeng/fontitem.hxx>
      27             : #include <editeng/langitem.hxx>
      28             : #include <editeng/emphasismarkitem.hxx>
      29             : #include <editeng/charscaleitem.hxx>
      30             : #include <editeng/charrotateitem.hxx>
      31             : #include <editeng/lrspitem.hxx>
      32             : #include <txtinet.hxx>
      33             : #include <txtflcnt.hxx>
      34             : #include <fmtfld.hxx>
      35             : #include <fmtrfmrk.hxx>
      36             : #include <fmtanchr.hxx>
      37             : #include <fmtinfmt.hxx>
      38             : #include <txtatr.hxx>
      39             : #include <fchrfmt.hxx>
      40             : #include <fmtautofmt.hxx>
      41             : #include <fmtflcnt.hxx>
      42             : #include <fmtftn.hxx>
      43             : #include <txttxmrk.hxx>
      44             : #include <txtrfmrk.hxx>
      45             : #include <txtftn.hxx>
      46             : #include <txtfld.hxx>
      47             : #include <txtannotationfld.hxx>
      48             : #include <charatr.hxx>
      49             : #include <charfmt.hxx>
      50             : #include <frmfmt.hxx>
      51             : #include <ftnidx.hxx>
      52             : #include <fmtruby.hxx>
      53             : #include <fmtmeta.hxx>
      54             : #include <breakit.hxx>
      55             : #include <doc.hxx>
      56             : #include <IDocumentUndoRedo.hxx>
      57             : #include <IDocumentFieldsAccess.hxx>
      58             : #include <IDocumentLayoutAccess.hxx>
      59             : #include <IDocumentStylePoolAccess.hxx>
      60             : #include <fldbas.hxx>
      61             : #include <pam.hxx>
      62             : #include <ndtxt.hxx>
      63             : #include <txtfrm.hxx>
      64             : #include <rolbck.hxx>
      65             : #include <ddefld.hxx>
      66             : #include <docufld.hxx>
      67             : #include <expfld.hxx>
      68             : #include <usrfld.hxx>
      69             : #include <poolfmt.hxx>
      70             : #include <swfont.hxx>
      71             : #include <istyleaccess.hxx>
      72             : #include <dcontact.hxx>
      73             : #include <docsh.hxx>
      74             : #include <svl/smplhint.hxx>
      75             : #include <algorithm>
      76             : #include <map>
      77             : #include <memory>
      78             : 
      79             : #ifdef DBG_UTIL
      80             : #define CHECK           Check(true);
      81             : #define CHECK_NOTMERGED Check(false);
      82             : #else
      83             : #define CHECK_NOTMERGED
      84             : #endif
      85             : 
      86             : using namespace ::com::sun::star::i18n;
      87             : 
      88       72844 : SwpHints::SwpHints()
      89             :     : m_pHistory(0)
      90             :     , m_bFontChange(true)
      91             :     , m_bInSplitNode(false)
      92             :     , m_bCalcHiddenParaField(false)
      93             :     , m_bHasHiddenParaField(false)
      94             :     , m_bFootnote(false)
      95       72844 :     , m_bDDEFields(false)
      96             : {
      97       72844 : }
      98             : 
      99             : struct TextAttrDeleter
     100             : {
     101             :     SwAttrPool & m_rPool;
     102           2 :     explicit TextAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { }
     103           2 :     void operator() (SwTextAttr * const pAttr)
     104             :     {
     105           2 :         if (RES_TXTATR_META == pAttr->Which() ||
     106           0 :             RES_TXTATR_METAFIELD == pAttr->Which())
     107             :         {
     108           2 :             static_txtattr_cast<SwTextMeta *>(pAttr)->ChgTextNode(0); // prevents ASSERT
     109             :         }
     110           2 :         SwTextAttr::Destroy( pAttr, m_rPool );
     111           2 :     }
     112             : };
     113             : 
     114             : struct TextAttrContains
     115             : {
     116             :     sal_Int32 m_nPos;
     117          30 :     explicit TextAttrContains( const sal_Int32 nPos ) : m_nPos( nPos ) { }
     118          39 :     bool operator() (SwTextAttrEnd * const pAttr)
     119             :     {
     120          39 :         return (pAttr->GetStart() < m_nPos) && (m_nPos < *pAttr->End());
     121             :     }
     122             : };
     123             : 
     124             : // a:       |-----|
     125             : // b:
     126             : //    |---|               => valid: b before a
     127             : //    |-----|             => valid: start == end; b before a
     128             : //    |---------|         => invalid: overlap (1)
     129             : //    |-----------|       => valid: same end; b around a
     130             : //    |-----------------| => valid: b around a
     131             : //          |---|         => valid; same start; b within a
     132             : //          |-----|       => valid; same start and end; b around or within a?
     133             : //          |-----------| => valid: same start: b around a
     134             : //            |-|         => valid: b within a
     135             : //            |---|       => valid: same end; b within a
     136             : //            |---------| => invalid: overlap (2)
     137             : //                |-----| => valid: end == start; b after a
     138             : //                  |---| => valid: b after a
     139             : // ===> 2 invalid overlap cases
     140             : static
     141        2291 : bool isOverlap(const sal_Int32 nStart1, const sal_Int32 nEnd1,
     142             :                const sal_Int32 nStart2, const sal_Int32 nEnd2)
     143             : {
     144             :     return
     145        1895 :         ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2))  // (1)
     146        4557 :      || ((nStart1 < nStart2) && (nStart2 < nEnd1) && (nEnd1 < nEnd2)); // (2)
     147             : }
     148             : 
     149             : /// #i106930#: now asymmetric: empty hint1 is _not_ nested, but empty hint2 is
     150             : static
     151        2248 : bool isNestedAny(const sal_Int32 nStart1, const sal_Int32 nEnd1,
     152             :                  const sal_Int32 nStart2, const sal_Int32 nEnd2)
     153             : {
     154        1947 :     return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
     155             :         // same start/end: nested except if hint1 empty and hint2 not empty
     156         339 :         ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
     157        2587 :         : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
     158             : }
     159             : 
     160             : static
     161        2078 : bool isSelfNestable(const sal_uInt16 nWhich)
     162             : {
     163        2078 :     if ((RES_TXTATR_INETFMT  == nWhich) ||
     164         115 :         (RES_TXTATR_CJK_RUBY == nWhich) ||
     165             :         (RES_TXTATR_INPUTFIELD == nWhich))
     166        1981 :         return false;
     167             :     assert((RES_TXTATR_META  == nWhich) ||
     168             :            (RES_TXTATR_METAFIELD  == nWhich));
     169          97 :     return true;
     170             : }
     171             : 
     172             : static
     173          72 : bool isSplittable(const sal_uInt16 nWhich)
     174             : {
     175          72 :     if ((RES_TXTATR_INETFMT  == nWhich) ||
     176             :         (RES_TXTATR_CJK_RUBY == nWhich))
     177          41 :         return true;
     178             :     assert((RES_TXTATR_META  == nWhich) ||
     179             :            (RES_TXTATR_METAFIELD  == nWhich) ||
     180             :            (RES_TXTATR_INPUTFIELD  == nWhich));
     181          31 :     return false;
     182             : }
     183             : 
     184             : enum Split_t { FAIL, SPLIT_NEW, SPLIT_OTHER };
     185             : /**
     186             :   Calculate splitting policy for overlapping hints, based on what kind of
     187             :   hint is inserted, and what kind of existing hint overlaps.
     188             :   */
     189             : static Split_t
     190          43 : splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
     191             : {
     192          43 :     if (!isSplittable(nWhichOther))
     193             :     {
     194          29 :         if (!isSplittable(nWhichNew))
     195           2 :             return FAIL;
     196             :         else
     197          27 :             return SPLIT_NEW;
     198             :     }
     199             :     else
     200             :     {
     201          14 :         if ( RES_TXTATR_INPUTFIELD == nWhichNew )
     202           0 :             return FAIL;
     203          14 :         else if ( (RES_TXTATR_INETFMT  == nWhichNew) &&
     204             :                   (RES_TXTATR_CJK_RUBY == nWhichOther) )
     205           3 :             return SPLIT_NEW;
     206             :         else
     207          11 :             return SPLIT_OTHER;
     208             :     }
     209             : }
     210             : 
     211        1812 : void SwTextINetFormat::InitINetFormat(SwTextNode & rNode)
     212             : {
     213        1812 :     ChgTextNode(&rNode);
     214             :     SwCharFormat * const pFormat(
     215        1812 :          rNode.GetDoc()->getIDocumentStylePoolAccess().GetCharFormatFromPool(RES_POOLCHR_INET_NORMAL) );
     216        1812 :     pFormat->Add( this );
     217        1812 : }
     218             : 
     219         177 : void SwTextRuby::InitRuby(SwTextNode & rNode)
     220             : {
     221         177 :     ChgTextNode(&rNode);
     222             :     SwCharFormat * const pFormat(
     223         177 :         rNode.GetDoc()->getIDocumentStylePoolAccess().GetCharFormatFromPool(RES_POOLCHR_RUBYTEXT) );
     224         177 :     pFormat->Add( this );
     225         177 : }
     226             : 
     227             : /**
     228             :   Create a new nesting text hint.
     229             :  */
     230             : static SwTextAttrNesting *
     231          42 : MakeTextAttrNesting(SwTextNode & rNode, SwTextAttrNesting & rNesting,
     232             :         const sal_Int32 nStart, const sal_Int32 nEnd)
     233             : {
     234             :     SwTextAttr * const pNew( MakeTextAttr(
     235          42 :             *rNode.GetDoc(), rNesting.GetAttr(), nStart, nEnd ) );
     236          42 :     switch (pNew->Which())
     237             :     {
     238             :         case RES_TXTATR_INETFMT:
     239             :         {
     240          14 :             static_txtattr_cast<SwTextINetFormat*>(pNew)->InitINetFormat(rNode);
     241          14 :             break;
     242             :         }
     243             :         case RES_TXTATR_CJK_RUBY:
     244             :         {
     245          28 :             static_txtattr_cast<SwTextRuby*>(pNew)->InitRuby(rNode);
     246          28 :             break;
     247             :         }
     248             :         default:
     249             :             assert(!"MakeTextAttrNesting: what the hell is that?");
     250           0 :             break;
     251             :     }
     252          42 :     return static_txtattr_cast<SwTextAttrNesting*>(pNew);
     253             : }
     254             : 
     255             : typedef ::std::vector<SwTextAttrNesting *> NestList_t;
     256             : 
     257             : static void
     258          30 : lcl_DoSplitNew(NestList_t & rSplits, SwTextNode & rNode,
     259             :     const sal_Int32 nNewStart,
     260             :     const sal_Int32 nOtherStart, const sal_Int32 nOtherEnd, bool bOtherDummy)
     261             : {
     262          30 :     const bool bSplitAtStart(nNewStart < nOtherStart);
     263          30 :     const sal_Int32 nSplitPos( (bSplitAtStart) ? nOtherStart : nOtherEnd );
     264             :     // first find the portion that is split (not necessarily the last one!)
     265             :     NestList_t::iterator const iter(
     266             :         ::std::find_if( rSplits.begin(), rSplits.end(),
     267          30 :             TextAttrContains(nSplitPos) ) );
     268          30 :     if (iter != rSplits.end()) // already split here?
     269             :     {
     270             :         const sal_Int32 nStartPos( // skip other's dummy character!
     271          28 :             (bSplitAtStart && bOtherDummy) ? nSplitPos + 1 : nSplitPos );
     272             :         SwTextAttrNesting * const pNew( MakeTextAttrNesting(
     273          28 :                 rNode, **iter, nStartPos, *(*iter)->GetEnd() ) );
     274          28 :         *(*iter)->GetEnd() = nSplitPos;
     275          28 :         rSplits.insert(iter + 1, pNew);
     276             :     }
     277          30 : }
     278             : 
     279             : /**
     280             :   Insert nesting hint into the hints array. Also calls NoteInHistory.
     281             :   @param    rNewHint    the hint to be inserted (must not overlap existing!)
     282             :  */
     283        2120 : void SwpHints::InsertNesting(SwTextAttrNesting & rNewHint)
     284             : {
     285        2120 :     SwpHintsArray::Insert(& rNewHint);
     286        2120 :     NoteInHistory( & rNewHint, true );
     287        2120 : }
     288             : 
     289             : /**
     290             : 
     291             : The following hints correspond to well-formed XML elements in ODF:
     292             : RES_TXTATR_INETFMT, RES_TXTATR_CJK_RUBY, RES_TXTATR_META, RES_TXTATR_METAFIELD
     293             : 
     294             : The writer core must ensure that these do not overlap; if they did,
     295             : the document would not be storable as ODF.
     296             : 
     297             : Also, a Hyperlink must not be nested within another Hyperlink,
     298             : and a Ruby must not be nested within another Ruby.
     299             : 
     300             : The ODF export in xmloff will only put a hyperlink into a ruby, never a ruby
     301             : into a hyperlink.
     302             : 
     303             : Unfortunately the UNO API for Hyperlink and Ruby consists of the properties
     304             : Hyperlink* and Ruby* of the css.text.CharacterProperties service.  In other
     305             : words, they are treated as formatting attributes, not as content entites.
     306             : Furthermore, for API users it is not possible to easily test whether a certain
     307             : range would be overlapping with other nested attributes, and most importantly,
     308             : <em>which ones</em>, so we can hardly refuse to insert these in cases of
     309             : overlap.
     310             : 
     311             : It is possible to split Hyperlink and Ruby into multiple portions, such that
     312             : the result is properly nested.
     313             : 
     314             : meta and meta-field must not be split, because they have xml:id.
     315             : 
     316             : These constraints result in the following design:
     317             : 
     318             : RES_TXTATR_INETFMT:
     319             :     always succeeds
     320             :     inserts n attributes split at RES_TXTATR_CJK_RUBY, RES_TXTATR_META,
     321             :         RES_TXTATR_METAFIELD
     322             :     may replace existing RES_TXTATR_INETFMT at overlap
     323             : RES_TXTATR_CJK_RUBY:
     324             :     always succeeds
     325             :     inserts n attributes split at RES_TXTATR_META, RES_TXTATR_METAFIELD
     326             :     may replace existing RES_TXTATR_CJK_RUBY at overlap
     327             :     may split existing overlapping RES_TXTATR_INETFMT
     328             : RES_TXTATR_META:
     329             :     may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
     330             :     may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
     331             :     inserts 1 attribute
     332             : RES_TXTATR_METAFIELD:
     333             :     may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
     334             :     may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
     335             :     inserts 1 attribute
     336             : 
     337             : The nesting is expressed by the position of the hints.
     338             : RES_TXTATR_META and RES_TXTATR_METAFIELD have a CH_TXTATR, and there can
     339             : only be one such hint starting and ending at a given position.
     340             : Only RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY lack a CH_TXTATR.
     341             : The interpretation given is that RES_TXTATR_CJK_RUBY is always around
     342             : a RES_TXTATR_INETFMT at the same start and end position (which corresponds
     343             : with the UNO API).
     344             : Both of these are always around a nesting hint with CH_TXTATR at the same
     345             : start and end position (if they should be inside, then the start should be
     346             : after the CH_TXTATR).
     347             : It would probably be a bad idea to add another nesting hint without
     348             : CH_TXTATR; on the other hand, it would be difficult adding a CH_TXTATR to
     349             : RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY, due to the overwriting and
     350             : splitting of exising hints that is necessary for backward compatibility.
     351             : 
     352             :     @param rNode    the text node
     353             :     @param rHint    the hint to be inserted
     354             :     @returns        true iff hint was successfully inserted
     355             : */
     356             : bool
     357        2078 : SwpHints::TryInsertNesting( SwTextNode & rNode, SwTextAttrNesting & rNewHint )
     358             : {
     359             : //    INVARIANT:  the nestable hints in the array are properly nested
     360        2078 :     const sal_uInt16 nNewWhich( rNewHint.Which() );
     361        2078 :     const sal_Int32 nNewStart( rNewHint.GetStart() );
     362        2078 :     const sal_Int32 nNewEnd  ( *rNewHint.GetEnd()   );
     363        2078 :     const bool bNewSelfNestable( isSelfNestable(nNewWhich) );
     364             : 
     365             :     assert( (RES_TXTATR_INETFMT   == nNewWhich) ||
     366             :             (RES_TXTATR_CJK_RUBY  == nNewWhich) ||
     367             :             (RES_TXTATR_META      == nNewWhich) ||
     368             :             (RES_TXTATR_METAFIELD == nNewWhich) ||
     369             :             (RES_TXTATR_INPUTFIELD == nNewWhich));
     370             : 
     371        2078 :     NestList_t OverlappingExisting; // existing hints to be split
     372        4156 :     NestList_t OverwrittenExisting; // existing hints to be replaced
     373        4156 :     NestList_t SplitNew;            // new hints to be inserted
     374             : 
     375        2078 :     SplitNew.push_back(& rNewHint);
     376             : 
     377             :     // pass 1: split the inserted hint into fragments if necessary
     378       12308 :     for ( size_t i = 0; i < GetEndCount(); ++i )
     379             :     {
     380       10232 :         SwTextAttr * const pOther = GetEnd(i);
     381             : 
     382       10232 :         if (pOther->IsNesting())
     383             :         {
     384        2291 :             const sal_uInt16 nOtherWhich( pOther->Which() );
     385        2291 :             const sal_Int32 nOtherStart( pOther->GetStart() );
     386        2291 :             const sal_Int32 nOtherEnd  ( *(pOther)->GetEnd()   );
     387        2291 :             if (isOverlap(nNewStart, nNewEnd, nOtherStart, nOtherEnd ))
     388             :             {
     389          43 :                 switch (splitPolicy(nNewWhich, nOtherWhich))
     390             :                 {
     391             :                     case FAIL:
     392             :                         SAL_INFO("sw.core", "cannot insert hint: overlap");
     393             :                         ::std::for_each(SplitNew.begin(), SplitNew.end(),
     394           2 :                             TextAttrDeleter(*rNode.GetDoc()));
     395           2 :                         return false;
     396             :                     case SPLIT_NEW:
     397             :                         lcl_DoSplitNew(SplitNew, rNode, nNewStart,
     398          30 :                             nOtherStart, nOtherEnd, pOther->HasDummyChar());
     399          30 :                         break;
     400             :                     case SPLIT_OTHER:
     401             :                         OverlappingExisting.push_back(
     402          11 :                             static_txtattr_cast<SwTextAttrNesting*>(pOther));
     403          11 :                         break;
     404             :                     default:
     405             :                         assert(!"bad code monkey");
     406           0 :                         break;
     407             :                 }
     408             :             }
     409        2248 :             else if (isNestedAny(nNewStart, nNewEnd, nOtherStart, nOtherEnd))
     410             :             {
     411         383 :                 if (!bNewSelfNestable && (nNewWhich == nOtherWhich))
     412             :                 {
     413             :                 // ruby and hyperlink: if there is nesting, _overwrite_
     414             :                 OverwrittenExisting.push_back(
     415         291 :                     static_txtattr_cast<SwTextAttrNesting*>(pOther));
     416             :                 }
     417          92 :                 else if ((nNewStart == nOtherStart) && pOther->HasDummyChar())
     418             :                 {
     419          18 :                     if (rNewHint.HasDummyChar())
     420             :                     {
     421             :                         assert(!"ERROR: inserting duplicate CH_TXTATR hint");
     422           0 :                         return false;
     423          18 :                     } else if (nNewEnd < nOtherEnd) {
     424             :                         // other has dummy char, new is inside other, but
     425             :                         // new contains the other's dummy char?
     426             :                         // should be corrected because it may lead to problems
     427             :                         // in SwXMeta::createEnumeration
     428             :                         // SplitNew is sorted, so this is the first split
     429           2 :                         sal_Int32& rStart(SplitNew.front()->GetStart());
     430             :                         assert(rStart == nNewStart);
     431           2 :                         rStart = nNewStart + 1;
     432             :                     }
     433             :                 }
     434             :             }
     435             :         }
     436             :     }
     437             : 
     438             :     assert((isSplittable(nNewWhich) || SplitNew.size() == 1) &&
     439             :             "splitting the unsplittable ???");
     440             : 
     441             :     // pass 2: split existing hints that overlap/nest with new hint
     442             :     // do not iterate over hints array, but over remembered set of overlapping
     443             :     // hints, to keep things simple w.r.t. insertion/removal
     444             :     // N.B: if there is a hint that splits the inserted hint, then
     445             :     // that hint would also have already split any hint in OverlappingExisting
     446             :     // so any hint in OverlappingExisting can be split at most by one hint
     447             :     // in SplitNew, or even not at all (this is not true for existing hints
     448             :     // that go _around_ new hint, which is the raison d'^etre for pass 4)
     449        6261 :     for (NestList_t::iterator itOther = OverlappingExisting.begin();
     450        4174 :             itOther != OverlappingExisting.end(); ++itOther)
     451             :     {
     452          11 :         const sal_Int32 nOtherStart( (*itOther)->GetStart() );
     453          11 :         const sal_Int32 nOtherEnd  ( *(*itOther)->GetEnd()   );
     454             : 
     455          69 :         for (NestList_t::iterator itNew = SplitNew.begin();
     456          46 :                 itNew != SplitNew.end(); ++itNew)
     457             :         {
     458          12 :             const sal_Int32 nSplitNewStart( (*itNew)->GetStart() );
     459          12 :             const sal_Int32 nSplitNewEnd  ( *(*itNew)->GetEnd()   );
     460             :             // 4 cases: within, around, overlap l, overlap r, (OTHER: no action)
     461             :             const bool bRemoveOverlap(
     462          12 :                 !bNewSelfNestable && (nNewWhich == (*itOther)->Which()) );
     463             : 
     464          12 :             switch (ComparePosition(nSplitNewStart, nSplitNewEnd,
     465          12 :                                     nOtherStart,    nOtherEnd))
     466             :             {
     467             :                 case POS_INSIDE:
     468             :                     {
     469             :                         assert(!bRemoveOverlap &&
     470             :                             "this one should be in OverwrittenExisting?");
     471             :                     }
     472           1 :                     break;
     473             :                 case POS_OUTSIDE:
     474             :                 case POS_EQUAL:
     475             :                     {
     476             :                         assert(!"existing hint inside new hint: why?");
     477             :                     }
     478           0 :                     break;
     479             :                 case POS_OVERLAP_BEFORE:
     480             :                     {
     481           5 :                         Delete( *itOther ); // this also does NoteInHistory!
     482           5 :                         (*itOther)->GetStart() = nSplitNewEnd;
     483           5 :                         InsertNesting( **itOther );
     484           5 :                         if (!bRemoveOverlap)
     485             :                         {
     486           3 :                             if ( MAX_HINTS <= Count() )
     487             :                             {
     488             :                                 SAL_INFO("sw.core", "hints array full :-(");
     489           0 :                                 return false;
     490             :                             }
     491             :                             SwTextAttrNesting * const pOtherLeft(
     492           3 :                                 MakeTextAttrNesting( rNode, **itOther,
     493           6 :                                     nOtherStart, nSplitNewEnd ) );
     494           3 :                             InsertNesting( *pOtherLeft );
     495             :                         }
     496             :                     }
     497           5 :                     break;
     498             :                 case POS_OVERLAP_BEHIND:
     499             :                     {
     500           5 :                         Delete( *itOther ); // this also does NoteInHistory!
     501           5 :                         *(*itOther)->GetEnd() = nSplitNewStart;
     502           5 :                         InsertNesting( **itOther );
     503           5 :                         if (!bRemoveOverlap)
     504             :                         {
     505           3 :                             if ( MAX_HINTS <= Count() )
     506             :                             {
     507             :                                 SAL_INFO("sw.core", "hints array full :-(");
     508           0 :                                 return false;
     509             :                             }
     510             :                             SwTextAttrNesting * const pOtherRight(
     511           3 :                                 MakeTextAttrNesting( rNode, **itOther,
     512           6 :                                     nSplitNewStart, nOtherEnd ) );
     513           3 :                             InsertNesting( *pOtherRight );
     514             :                         }
     515             :                     }
     516           5 :                     break;
     517             :                 default:
     518           1 :                     break; // overlap resolved by splitting new: nothing to do
     519             :             }
     520             :         }
     521             :     }
     522             : 
     523        2076 :     if ( MAX_HINTS <= Count() || MAX_HINTS - Count() <= SplitNew.size() )
     524             :     {
     525             :         SAL_INFO("sw.core", "hints array full :-(");
     526           0 :         return false;
     527             :     }
     528             : 
     529             :     // pass 3: insert new hints
     530       12540 :     for (NestList_t::iterator iter = SplitNew.begin();
     531        8360 :             iter != SplitNew.end(); ++iter)
     532             :     {
     533        2104 :         InsertNesting(**iter);
     534             :     }
     535             : 
     536             :     // pass 4: handle overwritten hints
     537             :     // RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY should displace attributes
     538             :     // of the same kind.
     539        7101 :     for (NestList_t::iterator itOther = OverwrittenExisting.begin();
     540        4734 :             itOther != OverwrittenExisting.end(); ++itOther)
     541             :     {
     542         291 :         const sal_Int32 nOtherStart( (*itOther)->GetStart() );
     543         291 :         const sal_Int32 nOtherEnd  ( *(*itOther)->GetEnd()   );
     544             : 
     545             :         // overwritten portion is given by start/end of inserted hint
     546         291 :         if ((nNewStart <= nOtherStart) && (nOtherEnd <= nNewEnd))
     547             :         {
     548         282 :             Delete(*itOther);
     549         282 :             rNode.DestroyAttr( *itOther );
     550             :         }
     551             :         else
     552             :         {
     553             :            assert((nOtherStart < nNewStart) || (nNewEnd < nOtherEnd));
     554             :         // scenario: there is a RUBY, and contained within that a META;
     555             :         // now a RUBY is inserted within the META => the exising RUBY is split:
     556             :         // here it is not possible to simply insert the left/right fragment
     557             :         // of the existing RUBY because they <em>overlap</em> with the META!
     558           9 :             Delete( *itOther ); // this also does NoteInHistory!
     559           9 :             if (nNewEnd < nOtherEnd)
     560             :             {
     561             :                 SwTextAttrNesting * const pOtherRight(
     562             :                     MakeTextAttrNesting(
     563           8 :                         rNode, **itOther, nNewEnd, nOtherEnd ) );
     564           8 :                 bool const bSuccess( TryInsertNesting(rNode, *pOtherRight) );
     565             :                 SAL_WARN_IF(!bSuccess, "sw.core", "recursive call 1 failed?");
     566             :             }
     567           9 :             if (nOtherStart < nNewStart)
     568             :             {
     569           8 :                 *(*itOther)->GetEnd() = nNewStart;
     570           8 :                 bool const bSuccess( TryInsertNesting(rNode, **itOther) );
     571             :                 SAL_WARN_IF(!bSuccess, "sw.core", "recursive call 2 failed?");
     572             :             }
     573             :             else
     574             :             {
     575           1 :                 rNode.DestroyAttr(*itOther);
     576             :             }
     577             :         }
     578             :     }
     579             : 
     580        4154 :     return true;
     581             : }
     582             : 
     583             : // This function takes care for the following text attribute:
     584             : // RES_TXTATR_CHARFMT, RES_TXTATR_AUTOFMT
     585             : // These attributes have to be handled in a special way (Portion building).
     586             : 
     587             : // The new attribute will be split by any existing RES_TXTATR_AUTOFMT or
     588             : // RES_TXTATR_CHARFMT. The new attribute itself will
     589             : // split any existing RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT.
     590             : 
     591       72499 : void SwpHints::BuildPortions( SwTextNode& rNode, SwTextAttr& rNewHint,
     592             :         const SetAttrMode nMode )
     593             : {
     594       72499 :     const sal_uInt16 nWhich = rNewHint.Which();
     595             : 
     596       72499 :     const sal_Int32 nThisStart = rNewHint.GetStart();
     597       72499 :     const sal_Int32 nThisEnd =   *rNewHint.GetEnd();
     598       72499 :     const bool bNoLengthAttribute = nThisStart == nThisEnd;
     599             : 
     600       72499 :     std::vector<SwTextAttr*> aInsDelHints;
     601       72499 :     std::vector<SwTextAttr*>::iterator aIter;
     602             : 
     603             :     assert( RES_TXTATR_CHARFMT == rNewHint.Which() ||
     604             :             RES_TXTATR_AUTOFMT == rNewHint.Which() );
     605             : 
     606             :     // 2. Find the hints which cover the start and end position
     607             :     // of the new hint. These hints have to be split into two portions:
     608             : 
     609       72499 :     if ( !bNoLengthAttribute ) // nothing to do for no length attributes
     610             :     {
     611      226813 :         for ( size_t i = 0; i < Count(); ++i )
     612             :         {
     613      180595 :             SwTextAttr* pOther = GetTextHint(i);
     614             : 
     615      343585 :             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
     616      162990 :                  RES_TXTATR_AUTOFMT != pOther->Which() )
     617       20944 :                 continue;
     618             : 
     619      159651 :             sal_Int32 nOtherStart = pOther->GetStart();
     620      159651 :             const sal_Int32 nOtherEnd = *pOther->GetEnd();
     621             : 
     622             :             // Check if start of new attribute overlaps with pOther:
     623             :             // Split pOther if necessary:
     624      159651 :             if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
     625             :             {
     626         311 :                 SwTextAttr* pNewAttr = MakeTextAttr( *rNode.GetDoc(),
     627         622 :                         pOther->GetAttr(), nOtherStart, nThisStart );
     628         311 :                 if ( RES_TXTATR_CHARFMT == pOther->Which() )
     629             :                 {
     630             :                     static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(
     631          76 :                         static_txtattr_cast<SwTextCharFormat*>(pOther)->GetSortNumber() );
     632             :                 }
     633         311 :                 aInsDelHints.push_back( pNewAttr );
     634             : 
     635         311 :                 NoteInHistory( pOther );
     636         311 :                 pOther->GetStart() = nThisStart;
     637         311 :                 NoteInHistory( pOther, true );
     638             : 
     639         311 :                 nOtherStart = nThisStart;
     640             :             }
     641             : 
     642             :             // Check if end of new attribute overlaps with pOther:
     643             :             // Split pOther if necessary:
     644      159651 :             if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
     645             :             {
     646         863 :                 SwTextAttr* pNewAttr = MakeTextAttr( *rNode.GetDoc(),
     647        1726 :                         pOther->GetAttr(), nOtherStart, nThisEnd );
     648         863 :                 if ( RES_TXTATR_CHARFMT == pOther->Which() )
     649             :                 {
     650             :                     static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(
     651           0 :                         static_txtattr_cast<SwTextCharFormat*>(pOther)->GetSortNumber());
     652             :                 }
     653         863 :                 aInsDelHints.push_back( pNewAttr );
     654             : 
     655         863 :                 NoteInHistory( pOther );
     656         863 :                 pOther->GetStart() = nThisEnd;
     657         863 :                 NoteInHistory( pOther, true );
     658             :             }
     659             :         }
     660             : 
     661             :         // Insert the newly created attributes:
     662       47392 :         for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
     663             :         {
     664        1174 :             SwpHintsArray::Insert( *aIter );
     665        1174 :             NoteInHistory( *aIter, true );
     666             :         }
     667             :     }
     668             : 
     669             : #ifdef DBG_UTIL
     670             :     if( !rNode.GetDoc()->IsInReading() )
     671             :         CHECK_NOTMERGED; // ignore flags not set properly yet, don't check them
     672             : #endif
     673             : 
     674             :     // 4. Split rNewHint into 1 ... n new hints:
     675             : 
     676      144998 :     std::set<sal_Int32> aBounds;
     677       72499 :     aBounds.insert( nThisStart );
     678       72499 :     aBounds.insert( nThisEnd );
     679             : 
     680       72499 :     if ( !bNoLengthAttribute ) // nothing to do for no length attributes
     681             :     {
     682      227987 :         for ( size_t i = 0; i < Count(); ++i )
     683             :         {
     684      181769 :             const SwTextAttr* pOther = GetTextHint(i);
     685             : 
     686      345857 :             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
     687      164088 :                  RES_TXTATR_AUTOFMT != pOther->Which() )
     688       20944 :                 continue;
     689             : 
     690      160825 :             const sal_Int32 nOtherStart = pOther->GetStart();
     691      160825 :             const sal_Int32 nOtherEnd = *pOther->End();
     692             : 
     693      160825 :             aBounds.insert( nOtherStart );
     694      160825 :             aBounds.insert( nOtherEnd );
     695             :         }
     696             :     }
     697             : 
     698       72499 :     std::set<sal_Int32>::iterator aStartIter = aBounds.lower_bound( nThisStart );
     699       72499 :     std::set<sal_Int32>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
     700       72499 :     sal_Int32 nPorStart = *aStartIter;
     701       72499 :     ++aStartIter;
     702       72499 :     bool bDestroyHint = true;
     703             : 
     704             :     // Insert the 1...n new parts of the new attribute:
     705             : 
     706      192242 :     while ( aStartIter != aEndIter || bNoLengthAttribute )
     707             :     {
     708             :         OSL_ENSURE( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" );
     709             : 
     710       73525 :         const sal_Int32 nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
     711       73525 :         aInsDelHints.clear();
     712             : 
     713             :         // Get all hints that are in [nPorStart, nPorEnd[:
     714      326703 :         for ( size_t i = 0; i < Count(); ++i )
     715             :         {
     716      255486 :             SwTextAttr *pOther = GetTextHint(i);
     717             : 
     718      487629 :             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
     719      232143 :                  RES_TXTATR_AUTOFMT != pOther->Which() )
     720       24308 :                 continue;
     721             : 
     722      231178 :             const sal_Int32 nOtherStart = pOther->GetStart();
     723             : 
     724      231178 :             if ( nOtherStart > nPorStart )
     725        2308 :                 break;
     726             : 
     727      228870 :             if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
     728             :             {
     729             :                 OSL_ENSURE( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" );
     730       25725 :                 aInsDelHints.push_back( pOther );
     731             :             }
     732             :         }
     733             : 
     734       73525 :         SwTextAttr* pNewAttr = 0;
     735       73525 :         if ( RES_TXTATR_CHARFMT == nWhich )
     736             :         {
     737             :             // pNewHint can be inserted after calculating the sort value.
     738             :             // This should ensure, that pNewHint comes behind the already present
     739             :             // character style
     740        6242 :             sal_uInt16 nCharStyleCount = 0;
     741        6242 :             aIter = aInsDelHints.begin();
     742       13446 :             while ( aIter != aInsDelHints.end() )
     743             :             {
     744         962 :                 if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
     745             :                 {
     746             :                     // #i74589#
     747         689 :                     const SwFormatCharFormat& rOtherCharFormat = (*aIter)->GetCharFormat();
     748         689 :                     const SwFormatCharFormat& rThisCharFormat = rNewHint.GetCharFormat();
     749         689 :                     const bool bSameCharFormat = rOtherCharFormat.GetCharFormat() == rThisCharFormat.GetCharFormat();
     750             : 
     751             :                     // #i90311#
     752             :                     // Do not remove existing character format hint during XML import
     753        3445 :                     if ( !rNode.GetDoc()->IsInXMLImport() &&
     754        2756 :                          ( !( SetAttrMode::DONTREPLACE & nMode ) ||
     755           0 :                            bNoLengthAttribute ||
     756             :                            bSameCharFormat ) )
     757             :                     {
     758             :                         // Remove old hint
     759         689 :                         Delete( *aIter );
     760         689 :                         rNode.DestroyAttr( *aIter );
     761             :                     }
     762             :                     else
     763           0 :                         ++nCharStyleCount;
     764             :                 }
     765             :                 else
     766             :                 {
     767             :                     // remove all attributes from auto styles, which are explicitly set in
     768             :                     // the new character format:
     769             :                     OSL_ENSURE( RES_TXTATR_AUTOFMT == (*aIter)->Which(), "AUTOSTYLES - Misc trouble" );
     770         273 :                     SwTextAttr* pOther = *aIter;
     771         273 :                     std::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFormatAutoFormat&>(pOther->GetAttr()).GetStyleHandle();
     772             : 
     773             :                     // For each attribute in the automatic style check if it
     774             :                     // is also set the new character style:
     775         273 :                     SfxItemSet aNewSet( *pOldStyle->GetPool(),
     776         546 :                         aCharAutoFormatSetRange);
     777         546 :                     SfxItemIter aItemIter( *pOldStyle );
     778         273 :                     const SfxPoolItem* pItem = aItemIter.GetCurItem();
     779             :                     while( true )
     780             :                     {
     781         925 :                         if ( !CharFormat::IsItemIncluded( pItem->Which(), &rNewHint ) )
     782             :                         {
     783         412 :                             aNewSet.Put( *pItem );
     784             :                         }
     785             : 
     786         925 :                         if( aItemIter.IsAtEnd() )
     787         273 :                             break;
     788             : 
     789         652 :                         pItem = aItemIter.NextItem();
     790             :                     }
     791             : 
     792             :                     // Remove old hint
     793         273 :                     Delete( pOther );
     794         273 :                     rNode.DestroyAttr( pOther );
     795             : 
     796             :                     // Create new AutoStyle
     797         273 :                     if ( aNewSet.Count() )
     798             :                     {
     799         106 :                         pNewAttr = MakeTextAttr( *rNode.GetDoc(),
     800         106 :                                 aNewSet, nPorStart, nPorEnd );
     801         106 :                         SwpHintsArray::Insert( pNewAttr );
     802         106 :                         NoteInHistory( pNewAttr, true );
     803         273 :                     }
     804             :                 }
     805         962 :                 ++aIter;
     806             :             }
     807             : 
     808             :             // If there is no current hint and start and end of rNewHint
     809             :             // is ok, we do not need to create a new txtattr.
     810       12484 :             if ( nPorStart == nThisStart &&
     811       12484 :                  nPorEnd == nThisEnd &&
     812             :                  !nCharStyleCount )
     813             :             {
     814        6242 :                 pNewAttr = &rNewHint;
     815        6242 :                 bDestroyHint = false;
     816             :             }
     817             :             else
     818             :             {
     819           0 :                 pNewAttr = MakeTextAttr( *rNode.GetDoc(), rNewHint.GetAttr(),
     820           0 :                         nPorStart, nPorEnd );
     821           0 :                 static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(nCharStyleCount);
     822             :             }
     823             :         }
     824             :         else
     825             :         {
     826             :             // Find the current autostyle. Mix attributes if necessary.
     827       67283 :             SwTextAttr* pCurrentAutoStyle = 0;
     828       67283 :             SwTextAttr* pCurrentCharFormat = 0;
     829       67283 :             aIter = aInsDelHints.begin();
     830      159329 :             while ( aIter != aInsDelHints.end() )
     831             :             {
     832       24763 :                 if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
     833       23502 :                     pCurrentAutoStyle = *aIter;
     834        1261 :                 else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
     835        1261 :                     pCurrentCharFormat = *aIter;
     836       24763 :                 ++aIter;
     837             :             }
     838             : 
     839       67283 :             std::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFormatAutoFormat&>(rNewHint.GetAttr()).GetStyleHandle();
     840       67283 :             if ( pCurrentAutoStyle )
     841             :             {
     842       23493 :                 std::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFormatAutoFormat&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
     843             : 
     844             :                 // Merge attributes
     845       46986 :                 SfxItemSet aNewSet( *pCurrentStyle );
     846       23493 :                 aNewSet.Put( *pNewStyle );
     847             : 
     848             :                 // #i75750# Remove attributes already set at whole paragraph
     849             :                 // #i81764# This should not be applied for no length attributes!!! <--
     850       23493 :                 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
     851             :                 {
     852        8363 :                     SfxItemIter aIter2( aNewSet );
     853        8363 :                     const SfxPoolItem* pItem = aIter2.GetCurItem();
     854        8363 :                     const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
     855             : 
     856       41618 :                     do
     857             :                     {
     858       41618 :                         const SfxPoolItem* pTmpItem = 0;
     859       41648 :                         if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
     860          30 :                              pTmpItem == pItem )
     861             :                         {
     862             :                             // Do not clear item if the attribute is set in a character format:
     863           0 :                             if ( !pCurrentCharFormat || 0 == CharFormat::GetItem( *pCurrentCharFormat, pItem->Which() ) )
     864           0 :                                 aNewSet.ClearItem( pItem->Which() );
     865             :                         }
     866             :                     }
     867       49981 :                     while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
     868             :                 }
     869             : 
     870             :                 // Remove old hint
     871       23493 :                 Delete( pCurrentAutoStyle );
     872       23493 :                 rNode.DestroyAttr( pCurrentAutoStyle );
     873             : 
     874             :                 // Create new AutoStyle
     875       23493 :                 if ( aNewSet.Count() )
     876       23493 :                     pNewAttr = MakeTextAttr( *rNode.GetDoc(), aNewSet,
     877       46986 :                             nPorStart, nPorEnd );
     878             :             }
     879             :             else
     880             :             {
     881             :                 // Remove any attributes which are already set at the whole paragraph:
     882       43790 :                 bool bOptimizeAllowed = true;
     883             : 
     884             :                 // #i75750# Remove attributes already set at whole paragraph
     885             :                 // #i81764# This should not be applied for no length attributes!!! <--
     886       43790 :                 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
     887             :                 {
     888        5206 :                     SfxItemSet* pNewSet = 0;
     889             : 
     890        5206 :                     SfxItemIter aIter2( *pNewStyle );
     891        5206 :                     const SfxPoolItem* pItem = aIter2.GetCurItem();
     892        5206 :                     const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
     893             : 
     894       23116 :                     do
     895             :                     {
     896       23116 :                         const SfxPoolItem* pTmpItem = 0;
     897       23225 :                         if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
     898         109 :                              pTmpItem == pItem )
     899             :                         {
     900             :                             // Do not clear item if the attribute is set in a character format:
     901          89 :                             if ( !pCurrentCharFormat || 0 == CharFormat::GetItem( *pCurrentCharFormat, pItem->Which() ) )
     902             :                             {
     903          89 :                                 if ( !pNewSet )
     904          66 :                                     pNewSet = pNewStyle->Clone( true );
     905          89 :                                 pNewSet->ClearItem( pItem->Which() );
     906             :                             }
     907             :                         }
     908             :                     }
     909       23116 :                     while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
     910             : 
     911        5206 :                     if ( pNewSet )
     912             :                     {
     913          66 :                         bOptimizeAllowed = false;
     914          66 :                         if ( pNewSet->Count() )
     915           0 :                             pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
     916             :                         else
     917          66 :                             pNewStyle.reset();
     918             : 
     919          66 :                         delete pNewSet;
     920        5206 :                     }
     921             :                 }
     922             : 
     923             :                 // Create new AutoStyle
     924             :                 // If there is no current hint and start and end of rNewHint
     925             :                 // is ok, we do not need to create a new txtattr.
     926       87514 :                 if ( bOptimizeAllowed &&
     927       87412 :                      nPorStart == nThisStart &&
     928       43688 :                      nPorEnd == nThisEnd )
     929             :                 {
     930       43683 :                     pNewAttr = &rNewHint;
     931       43683 :                     bDestroyHint = false;
     932             :                 }
     933         107 :                 else if ( pNewStyle.get() )
     934             :                 {
     935          41 :                     pNewAttr = MakeTextAttr( *rNode.GetDoc(), *pNewStyle,
     936          41 :                             nPorStart, nPorEnd );
     937             :                 }
     938       67283 :             }
     939             :         }
     940             : 
     941       73525 :         if ( pNewAttr )
     942             :         {
     943       73459 :             SwpHintsArray::Insert( pNewAttr );
     944             : //            if ( bDestroyHint )
     945       73459 :                 NoteInHistory( pNewAttr, true );
     946             :         }
     947             : 
     948       73525 :         if ( !bNoLengthAttribute )
     949             :         {
     950       47244 :             nPorStart = *aStartIter;
     951       47244 :             ++aStartIter;
     952             :         }
     953             :         else
     954       26281 :             break;
     955             :     }
     956             : 
     957       72499 :     if ( bDestroyHint )
     958       95073 :         rNode.DestroyAttr( &rNewHint );
     959       72499 : }
     960             : 
     961        5301 : SwTextAttr* MakeRedlineTextAttr( SwDoc & rDoc, SfxPoolItem & rAttr )
     962             : {
     963             :     // this is intended _only_ for special-purpose redline attributes!
     964        5301 :     switch (rAttr.Which())
     965             :     {
     966             :         case RES_CHRATR_COLOR:
     967             :         case RES_CHRATR_WEIGHT:
     968             :         case RES_CHRATR_CJK_WEIGHT:
     969             :         case RES_CHRATR_CTL_WEIGHT:
     970             :         case RES_CHRATR_POSTURE:
     971             :         case RES_CHRATR_CJK_POSTURE:
     972             :         case RES_CHRATR_CTL_POSTURE:
     973             :         case RES_CHRATR_UNDERLINE:
     974             :         case RES_CHRATR_CROSSEDOUT:
     975             :         case RES_CHRATR_CASEMAP:
     976             :         case RES_CHRATR_BACKGROUND:
     977        5301 :             break;
     978             :         default:
     979             :             OSL_FAIL("unsupported redline attribute");
     980           0 :             break;
     981             :     }
     982             : 
     983             :     // Put new attribute into pool
     984             :     // FIXME: this const_cast is evil!
     985             :     SfxPoolItem& rNew =
     986        5301 :         const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
     987        5301 :     return new SwTextAttrEnd( rNew, 0, 0 );
     988             : }
     989             : 
     990             : // create new text attribute
     991      107264 : SwTextAttr* MakeTextAttr(
     992             :     SwDoc & rDoc,
     993             :     SfxPoolItem& rAttr,
     994             :     sal_Int32 const nStt,
     995             :     sal_Int32 const nEnd,
     996             :     CopyOrNew_t const bIsCopy,
     997             :     SwTextNode *const pTextNode )
     998             : {
     999      107264 :     if ( isCHRATR(rAttr.Which()) )
    1000             :     {
    1001             :         // Somebody wants to build a SwTextAttr for a character attribute.
    1002             :         // Sorry, this is not allowed any longer.
    1003             :         // You'll get a brand new autostyle attribute:
    1004           0 :         SfxItemSet aItemSet( rDoc.GetAttrPool(),
    1005           0 :                 RES_CHRATR_BEGIN, RES_CHRATR_END );
    1006           0 :         aItemSet.Put( rAttr );
    1007           0 :         return MakeTextAttr( rDoc, aItemSet, nStt, nEnd );
    1008             :     }
    1009      414623 :     else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
    1010             :               static_cast<const SwFormatAutoFormat&>(rAttr).GetStyleHandle()->
    1011      385757 :                 GetPool() != &rDoc.GetAttrPool() )
    1012             :     {
    1013             :         // If the attribute is an auto-style which refers to a pool that is
    1014             :         // different from rDoc's pool, we have to correct this:
    1015           9 :         const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFormatAutoFormat&>(rAttr).GetStyleHandle();
    1016             :         std::unique_ptr<const SfxItemSet> pNewSet(
    1017          18 :                 pAutoStyle->SfxItemSet::Clone( true, &rDoc.GetAttrPool() ));
    1018           9 :         SwTextAttr* pNew = MakeTextAttr( rDoc, *pNewSet, nStt, nEnd );
    1019          18 :         return pNew;
    1020             :     }
    1021             : 
    1022             :     // Put new attribute into pool
    1023             :     // FIXME: this const_cast is evil!
    1024             :     SfxPoolItem& rNew =
    1025      107255 :         const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
    1026             : 
    1027      107255 :     SwTextAttr* pNew = 0;
    1028      107255 :     switch( rNew.Which() )
    1029             :     {
    1030             :     case RES_TXTATR_CHARFMT:
    1031             :         {
    1032        6318 :             SwFormatCharFormat &rFormatCharFormat = static_cast<SwFormatCharFormat&>(rNew);
    1033        6318 :             if( !rFormatCharFormat.GetCharFormat() )
    1034             :             {
    1035           0 :                 rFormatCharFormat.SetCharFormat( rDoc.GetDfltCharFormat() );
    1036             :             }
    1037             : 
    1038        6318 :             pNew = new SwTextCharFormat( rFormatCharFormat, nStt, nEnd );
    1039             :         }
    1040        6318 :         break;
    1041             :     case RES_TXTATR_INETFMT:
    1042        1804 :         pNew = new SwTextINetFormat( static_cast<SwFormatINetFormat&>(rNew), nStt, nEnd );
    1043        1804 :         break;
    1044             : 
    1045             :     case RES_TXTATR_FIELD:
    1046        3766 :         pNew = new SwTextField( static_cast<SwFormatField &>(rNew), nStt,
    1047        5649 :                     rDoc.IsClipBoard() );
    1048        1883 :         break;
    1049             : 
    1050             :     case RES_TXTATR_ANNOTATION:
    1051             :         {
    1052         139 :             pNew = new SwTextAnnotationField( static_cast<SwFormatField &>(rNew), nStt, rDoc.IsClipBoard() );
    1053         139 :             if (bIsCopy == COPY)
    1054             :             {
    1055             :                 // On copy of the annotation field do not keep the annotated text range by removing
    1056             :                 // the relation to its annotation mark (relation established via annotation field's name).
    1057             :                 // If the annotation mark is also copied, the relation and thus the annotated text range will be reestablished,
    1058             :                 // when the annotation mark is created and inserted into the document.
    1059           5 :                 const_cast<SwPostItField&>(dynamic_cast<const SwPostItField&>(*(pNew->GetFormatField().GetField()))).SetName(OUString());
    1060             :             }
    1061             :         }
    1062         139 :         break;
    1063             : 
    1064             :     case RES_TXTATR_INPUTFIELD:
    1065          36 :         pNew = new SwTextInputField( static_cast<SwFormatField &>(rNew), nStt, nEnd,
    1066          54 :                     rDoc.IsClipBoard() );
    1067          18 :         break;
    1068             : 
    1069             :     case RES_TXTATR_FLYCNT:
    1070             :         {
    1071             :             // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
    1072        3648 :             pNew = new SwTextFlyCnt( static_cast<SwFormatFlyCnt&>(rNew), nStt );
    1073             :             // Kopie von einem Text-Attribut
    1074        3648 :             if ( static_cast<const SwFormatFlyCnt &>(rAttr).GetTextFlyCnt() )
    1075             :             {
    1076             :                 // then the format must be copied
    1077         176 :                 static_cast<SwTextFlyCnt *>(pNew)->CopyFlyFormat( &rDoc );
    1078             :             }
    1079             :         }
    1080        3648 :         break;
    1081             :     case RES_TXTATR_FTN:
    1082         138 :         pNew = new SwTextFootnote( static_cast<SwFormatFootnote&>(rNew), nStt );
    1083             :         // ggfs. SeqNo kopieren
    1084         138 :         if( static_cast<SwFormatFootnote&>(rAttr).GetTextFootnote() )
    1085           0 :             static_cast<SwTextFootnote*>(pNew)->SetSeqNo( static_cast<SwFormatFootnote&>(rAttr).GetTextFootnote()->GetSeqRefNo() );
    1086         138 :         break;
    1087             :     case RES_TXTATR_REFMARK:
    1088          78 :         pNew = nStt == nEnd
    1089          25 :                 ? new SwTextRefMark( static_cast<SwFormatRefMark&>(rNew), nStt )
    1090          53 :                 : new SwTextRefMark( static_cast<SwFormatRefMark&>(rNew), nStt, &nEnd );
    1091          39 :         break;
    1092             :     case RES_TXTATR_TOXMARK:
    1093         173 :         pNew = new SwTextTOXMark( static_cast<SwTOXMark&>(rNew), nStt, &nEnd );
    1094         173 :         break;
    1095             :     case RES_TXTATR_CJK_RUBY:
    1096         176 :         pNew = new SwTextRuby( static_cast<SwFormatRuby&>(rNew), nStt, nEnd );
    1097         176 :         break;
    1098             :     case RES_TXTATR_META:
    1099             :     case RES_TXTATR_METAFIELD:
    1100         194 :         pNew = SwTextMeta::CreateTextMeta( rDoc.GetMetaFieldManager(), pTextNode,
    1101         291 :                 static_cast<SwFormatMeta&>(rNew), nStt, nEnd, bIsCopy == COPY );
    1102          97 :         break;
    1103             :     default:
    1104             :         assert(RES_TXTATR_AUTOFMT == rNew.Which());
    1105       92822 :         pNew = new SwTextAttrEnd( rNew, nStt, nEnd );
    1106       92822 :         break;
    1107             :     }
    1108             : 
    1109      107255 :     return pNew;
    1110             : }
    1111             : 
    1112       87768 : SwTextAttr* MakeTextAttr( SwDoc & rDoc, const SfxItemSet& rSet,
    1113             :                         sal_Int32 nStt, sal_Int32 nEnd )
    1114             : {
    1115       87768 :     IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
    1116       87768 :     const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
    1117      175536 :     SwFormatAutoFormat aNewAutoFormat;
    1118       87768 :     aNewAutoFormat.SetStyleHandle( pAutoStyle );
    1119       87768 :     SwTextAttr* pNew = MakeTextAttr( rDoc, aNewAutoFormat, nStt, nEnd );
    1120      175536 :     return pNew;
    1121             : }
    1122             : 
    1123             : // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
    1124      107221 : void SwTextNode::DestroyAttr( SwTextAttr* pAttr )
    1125             : {
    1126      107221 :     if( pAttr )
    1127             :     {
    1128             :         // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
    1129      107221 :         SwDoc* pDoc = GetDoc();
    1130      107221 :         switch( pAttr->Which() )
    1131             :         {
    1132             :         case RES_TXTATR_FLYCNT:
    1133             :             {
    1134             :                 // siehe auch die Anmerkung "Loeschen von Formaten
    1135             :                 // zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFormat()
    1136        3647 :                 SwFrameFormat* pFormat = pAttr->GetFlyCnt().GetFrameFormat();
    1137        3647 :                 if( pFormat )      // vom Undo auf 0 gesetzt ??
    1138        1508 :                     pDoc->getIDocumentLayoutAccess().DelLayoutFormat( pFormat );
    1139             :             }
    1140        3647 :             break;
    1141             : 
    1142             :         case RES_CHRATR_HIDDEN:
    1143           0 :             SetCalcHiddenCharFlags();
    1144           0 :             break;
    1145             : 
    1146             :         case RES_TXTATR_FTN:
    1147         138 :             static_cast<SwTextFootnote*>(pAttr)->SetStartNode( 0 );
    1148         138 :             static_cast<SwFormatFootnote&>(pAttr->GetAttr()).InvalidateFootnote();
    1149         138 :             break;
    1150             : 
    1151             :         case RES_TXTATR_FIELD:
    1152             :         case RES_TXTATR_ANNOTATION:
    1153             :         case RES_TXTATR_INPUTFIELD:
    1154        2031 :             if( !pDoc->IsInDtor() )
    1155             :             {
    1156         774 :                 SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pAttr));
    1157             :                 // Wenn wir ein HiddenParaField sind, dann muessen wir
    1158             :                 // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
    1159         774 :                 const SwField* pField = pAttr->GetFormatField().GetField();
    1160             : 
    1161             :                 //JP 06-08-95: DDE-Felder bilden eine Ausnahme
    1162             :                 OSL_ENSURE( RES_DDEFLD == pField->GetTyp()->Which() ||
    1163             :                         this == pTextField->GetpTextNode(),
    1164             :                         "Wo steht denn dieses Feld?" );
    1165             : 
    1166             :                 // bestimmte Felder mussen am Doc das Calculations-Flag updaten
    1167         774 :                 switch( pField->GetTyp()->Which() )
    1168             :                 {
    1169             :                 case RES_HIDDENPARAFLD:
    1170           0 :                     SetCalcHiddenParaField();
    1171             :                     // no break
    1172             :                 case RES_DBSETNUMBERFLD:
    1173             :                 case RES_GETEXPFLD:
    1174             :                 case RES_DBFLD:
    1175             :                 case RES_SETEXPFLD:
    1176             :                 case RES_HIDDENTXTFLD:
    1177             :                 case RES_DBNUMSETFLD:
    1178             :                 case RES_DBNEXTSETFLD:
    1179          30 :                     if( !pDoc->getIDocumentFieldsAccess().IsNewFieldLst() && GetNodes().IsDocNodes() )
    1180          30 :                         pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(false, *pTextField);
    1181          30 :                     break;
    1182             :                 case RES_DDEFLD:
    1183           0 :                     if (GetNodes().IsDocNodes() && pTextField->GetpTextNode())
    1184           0 :                         static_cast<SwDDEFieldType*>(pField->GetTyp())->DecRefCnt();
    1185           0 :                     break;
    1186             :                 case RES_POSTITFLD:
    1187             :                     {
    1188          18 :                         const_cast<SwFormatField&>(pAttr->GetFormatField()).Broadcast(
    1189          36 :                             SwFormatFieldHint(&pTextField->GetFormatField(), SwFormatFieldHintWhich::REMOVED));
    1190          18 :                         break;
    1191             :                     }
    1192             :                 }
    1193             :             }
    1194        2031 :             static_cast<SwFormatField&>(pAttr->GetAttr()).InvalidateField();
    1195        2031 :             break;
    1196             : 
    1197             :         case RES_TXTATR_TOXMARK:
    1198         173 :             static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
    1199         173 :             break;
    1200             : 
    1201             :         case RES_TXTATR_REFMARK:
    1202          39 :             static_cast<SwFormatRefMark&>(pAttr->GetAttr()).InvalidateRefMark();
    1203          39 :             break;
    1204             : 
    1205             :         case RES_TXTATR_META:
    1206             :         case RES_TXTATR_METAFIELD:
    1207          95 :             static_txtattr_cast<SwTextMeta*>(pAttr)->ChgTextNode(0);
    1208          95 :             break;
    1209             : 
    1210             :         default:
    1211      101098 :             break;
    1212             :         }
    1213             : 
    1214      107221 :         SwTextAttr::Destroy( pAttr, pDoc->GetAttrPool() );
    1215             :     }
    1216      107221 : }
    1217             : 
    1218        6563 : SwTextAttr* SwTextNode::InsertItem(
    1219             :     SfxPoolItem& rAttr,
    1220             :     const sal_Int32 nStart,
    1221             :     const sal_Int32 nEnd,
    1222             :     const SetAttrMode nMode )
    1223             : {
    1224             :    // character attributes will be inserted as automatic styles:
    1225             :     OSL_ENSURE( !isCHRATR(rAttr.Which()), "AUTOSTYLES - "
    1226             :         "SwTextNode::InsertItem should not be called with character attributes");
    1227             : 
    1228             :     SwTextAttr *const pNew =
    1229             :         MakeTextAttr(
    1230        6563 :             *GetDoc(),
    1231             :             rAttr,
    1232             :             nStart,
    1233             :             nEnd,
    1234       13126 :             (nMode & SetAttrMode::IS_COPY) ? COPY : NEW,
    1235       13126 :             this );
    1236             : 
    1237        6563 :     if ( pNew )
    1238             :     {
    1239        6563 :         const bool bSuccess( InsertHint( pNew, nMode ) );
    1240             :         // N.B.: also check that the hint is actually in the hints array,
    1241             :         // because hints of certain types may be merged after successful
    1242             :         // insertion, and thus destroyed!
    1243        6563 :         if (!bSuccess || !m_pSwpHints->Contains( pNew ))
    1244             :         {
    1245          10 :             return 0;
    1246             :         }
    1247             :     }
    1248             : 
    1249        6553 :     return pNew;
    1250             : }
    1251             : 
    1252             : // take ownership of pAttr; if insertion fails, delete pAttr
    1253       82499 : bool SwTextNode::InsertHint( SwTextAttr * const pAttr, const SetAttrMode nMode )
    1254             : {
    1255       82499 :     bool bHiddenPara = false;
    1256             : 
    1257             :     OSL_ENSURE( pAttr && pAttr->GetStart() <= Len(), "StartIdx out of bounds!" );
    1258             :     OSL_ENSURE( !pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()),
    1259             :             "EndIdx out of bounds!" );
    1260             : 
    1261             :     // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR)
    1262             :     const SwInsertFlags nInsertFlags =
    1263      164998 :         (nMode & SetAttrMode::FORCEHINTEXPAND)
    1264       82529 :         ? (SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND)
    1265       82529 :         : SwInsertFlags::EMPTYEXPAND;
    1266             : 
    1267             :     // need this after TryInsertHint, when pAttr may be deleted
    1268       82499 :     const sal_Int32 nStart( pAttr->GetStart() );
    1269       82499 :     const bool bDummyChar( pAttr->HasDummyChar() );
    1270       82499 :     if (bDummyChar)
    1271             :     {
    1272        6099 :         SetAttrMode nInsMode = nMode;
    1273        6099 :         switch( pAttr->Which() )
    1274             :         {
    1275             :         case RES_TXTATR_FLYCNT:
    1276             :             {
    1277        3653 :                 SwTextFlyCnt *pFly = static_cast<SwTextFlyCnt *>(pAttr);
    1278        3653 :                 SwFrameFormat* pFormat = pAttr->GetFlyCnt().GetFrameFormat();
    1279             : 
    1280             :                 // In order to maintain data coherency, if the hint is a fly
    1281             :                 // moved from a text node to another, we have to remove it from
    1282             :                 // the first textnode then to add it to the new (this) textnode
    1283        3653 :                 const SwFormatAnchor* pAnchor = 0;
    1284             :                 pFormat->GetItemState( RES_ANCHOR, false,
    1285        3653 :                     reinterpret_cast<const SfxPoolItem**>(&pAnchor) );
    1286             : 
    1287        3653 :                 SwIndex aIdx( this, pAttr->GetStart() );
    1288             : 
    1289        3653 :                 bool bChangeFlyParentNode( false );
    1290       10979 :                 if (pAnchor &&
    1291        7286 :                     pAnchor->GetAnchorId() == FLY_AS_CHAR &&
    1292       14552 :                     pAnchor->GetContentAnchor() &&
    1293       14552 :                     pAnchor->GetContentAnchor()->nNode != *this)
    1294             :                 {
    1295             :                     assert(pAnchor->GetContentAnchor()->nNode.GetNode().IsTextNode());
    1296         890 :                     SwTextNode* textNode = pAnchor->GetContentAnchor()->nNode.GetNode().GetTextNode();
    1297             : 
    1298         890 :                     if ( textNode->IsModifyLocked() )
    1299             :                     {
    1300             :                         //  Fly parent has changed but the FlyFormat is locked, so it will
    1301             :                         //  not be updated by SetAnchor (that calls Modify that updates
    1302             :                         //  relationships)
    1303           0 :                         textNode->RemoveAnchoredFly( pFormat );
    1304           0 :                         bChangeFlyParentNode = true;
    1305             :                     }
    1306             :                 }
    1307             : 
    1308        3653 :                 if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
    1309             :                 {
    1310             : 
    1311             :                     // Wir muessen zuerst einfuegen, da in SetAnchor()
    1312             :                     // dem FlyFrm GetStart() uebermittelt wird.
    1313             :                     //JP 11.05.98: falls das Anker-Attribut schon richtig
    1314             :                     // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
    1315             :                     // des Zeichens. Sonst muesste das immer  ausserhalb
    1316             :                     // erfolgen (Fehleranfaellig !)
    1317             : 
    1318        3472 :                     const OUString c(GetCharOfTextAttr(*pAttr));
    1319        6944 :                     OUString const ins( InsertText(c, aIdx, nInsertFlags) );
    1320        3472 :                     if (ins.isEmpty())
    1321             :                     {
    1322             :                         // do not record deletion of Format!
    1323             :                         ::sw::UndoGuard const ug(
    1324           0 :                                 pFormat->GetDoc()->GetIDocumentUndoRedo());
    1325           0 :                         DestroyAttr(pAttr);
    1326           0 :                         return false; // text node full :(
    1327             :                     }
    1328        3472 :                     nInsMode |= SetAttrMode::NOTXTATRCHR;
    1329             : 
    1330       10436 :                     if (pAnchor &&
    1331        6924 :                         (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
    1332       10356 :                         pAnchor->GetContentAnchor() &&
    1333       20043 :                         pAnchor->GetContentAnchor()->nNode == *this &&
    1334        2743 :                         pAnchor->GetContentAnchor()->nContent == aIdx )
    1335             :                     {
    1336             :                         --const_cast<SwIndex&>(
    1337        2680 :                             pAnchor->GetContentAnchor()->nContent);
    1338        3472 :                     }
    1339             :                 }
    1340        3653 :                 pFly->SetAnchor( this );
    1341             : 
    1342             :                 // Format-Pointer kann sich im SetAnchor geaendert haben!
    1343             :                 // (Kopieren in andere Docs!)
    1344        3653 :                 pFormat = pAttr->GetFlyCnt().GetFrameFormat();
    1345        3653 :                 SwDoc *pDoc = pFormat->GetDoc();
    1346             : 
    1347             :                 // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
    1348             :                 // But don't allow control objects in header/footer
    1349        6437 :                 if( RES_DRAWFRMFMT == pFormat->Which() &&
    1350        2784 :                     pDoc->IsInHeaderFooter( pFormat->GetAnchor().GetContentAnchor()->nNode ) )
    1351             :                 {
    1352             :                     SwDrawContact* pDrawContact =
    1353         118 :                         static_cast<SwDrawContact*>(pFormat->FindContactObj());
    1354         233 :                     if ( pDrawContact &&
    1355         233 :                          pDrawContact->GetMaster() &&
    1356         115 :                          ::CheckControlLayer( pDrawContact->GetMaster() ) )
    1357             :                     {
    1358             :                         // das soll nicht meoglich sein; hier verhindern
    1359             :                         // Der Dtor des TextHints loescht nicht das Zeichen.
    1360             :                         // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
    1361             :                         // dieses explizit loeschen
    1362           0 :                         if( SetAttrMode::NOTXTATRCHR & nInsMode )
    1363             :                         {
    1364             :                             // loesche das Zeichen aus dem String !
    1365             :                             OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
    1366             :                                         m_Text[pAttr->GetStart()] ||
    1367             :                                       CH_TXTATR_INWORD ==
    1368             :                                         m_Text[pAttr->GetStart()]),
    1369             :                                     "where is my attribute character?" );
    1370           0 :                             m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
    1371             :                             // Indizies Updaten
    1372           0 :                             SwIndex aTmpIdx( this, pAttr->GetStart() );
    1373           0 :                             Update( aTmpIdx, 1, true );
    1374             :                         }
    1375             :                         // do not record deletion of Format!
    1376           0 :                         ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
    1377           0 :                         DestroyAttr( pAttr );
    1378           0 :                         return false;
    1379             :                     }
    1380             :                 }
    1381             : 
    1382             :                 // Finish relationships update now that SetAnchor has fixed part of it.
    1383        3653 :                 if (bChangeFlyParentNode)
    1384           0 :                     AddAnchoredFly( pFormat );
    1385             : 
    1386        3653 :                 break;
    1387             :             }
    1388             : 
    1389             :         case RES_TXTATR_FTN :
    1390             :             {
    1391             :                 // Fussnoten, man kommt an alles irgendwie heran.
    1392             :                 // ContentNode erzeugen und in die Inserts-Section stellen
    1393         140 :                 SwDoc *pDoc = GetDoc();
    1394         140 :                 SwNodes &rNodes = pDoc->GetNodes();
    1395             : 
    1396             :                 // FussNote in nicht Content-/Redline-Bereich einfuegen ??
    1397         140 :                 if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
    1398             :                 {
    1399             :                     // das soll nicht meoglich sein; hier verhindern
    1400             :                     // Der Dtor des TextHints loescht nicht das Zeichen.
    1401             :                     // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
    1402             :                     // dieses explizit loeschen
    1403           0 :                     if( SetAttrMode::NOTXTATRCHR & nInsMode )
    1404             :                     {
    1405             :                         // loesche das Zeichen aus dem String !
    1406             :                         OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
    1407             :                                       m_Text[pAttr->GetStart()] ||
    1408             :                                   CH_TXTATR_INWORD ==
    1409             :                                       m_Text[pAttr->GetStart()]),
    1410             :                                 "where is my attribute character?" );
    1411           0 :                         m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
    1412             :                         // Indizies Updaten
    1413           0 :                         SwIndex aTmpIdx( this, pAttr->GetStart() );
    1414           0 :                         Update( aTmpIdx, 1, true );
    1415             :                     }
    1416           0 :                     DestroyAttr( pAttr );
    1417           0 :                     return false;
    1418             :                 }
    1419             : 
    1420             :                 // wird eine neue Fussnote eingefuegt ??
    1421         140 :                 bool bNewFootnote = 0 == static_cast<SwTextFootnote*>(pAttr)->GetStartNode();
    1422         140 :                 if( bNewFootnote )
    1423             :                 {
    1424         138 :                     static_cast<SwTextFootnote*>(pAttr)->MakeNewTextSection( GetNodes() );
    1425         138 :                     SwRegHistory* pHist = GetpSwpHints()
    1426         138 :                         ? GetpSwpHints()->GetHistory() : 0;
    1427         138 :                     if( pHist )
    1428          18 :                         pHist->ChangeNodeIndex( GetIndex() );
    1429             :                 }
    1430           2 :                 else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
    1431             :                 {
    1432             :                     // loesche alle Frames der Section, auf die der StartNode zeigt
    1433             :                     sal_uLong nSttIdx =
    1434           2 :                         static_cast<SwTextFootnote*>(pAttr)->GetStartNode()->GetIndex();
    1435           2 :                     sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
    1436           4 :                     for( ; nSttIdx < nEndIdx; ++nSttIdx )
    1437             :                     {
    1438           2 :                         SwContentNode* pCNd = rNodes[ nSttIdx ]->GetContentNode();
    1439           2 :                         if( 0 != pCNd )
    1440           2 :                             pCNd->DelFrms();
    1441             :                     }
    1442             :                 }
    1443             : 
    1444         140 :                 if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
    1445             :                 {
    1446             :                     // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
    1447             :                     // entstehen koennen und das Attribut im _SortArr_ am
    1448             :                     // Dokument nicht eingetrage wird.
    1449         138 :                     SwIndex aNdIdx( this, pAttr->GetStart() );
    1450         276 :                     const OUString c(GetCharOfTextAttr(*pAttr));
    1451         276 :                     OUString const ins( InsertText(c, aNdIdx, nInsertFlags) );
    1452         138 :                     if (ins.isEmpty())
    1453             :                     {
    1454           0 :                         DestroyAttr(pAttr);
    1455           0 :                         return false; // text node full :(
    1456             :                     }
    1457         276 :                     nInsMode |= SetAttrMode::NOTXTATRCHR;
    1458             :                 }
    1459             : 
    1460             :                 // Wir tragen uns am FootnoteIdx-Array des Docs ein ...
    1461         140 :                 SwTextFootnote* pTextFootnote = 0;
    1462         140 :                 if( !bNewFootnote )
    1463             :                 {
    1464             :                     // eine alte Footnote wird umgehaengt (z.B. SplitNode)
    1465           2 :                     for( size_t n = 0; n < pDoc->GetFootnoteIdxs().size(); ++n )
    1466           2 :                         if( pAttr == pDoc->GetFootnoteIdxs()[n] )
    1467             :                         {
    1468             :                             // neuen Index zuweisen, dafuer aus dem SortArray
    1469             :                             // loeschen und neu eintragen
    1470           2 :                             pTextFootnote = pDoc->GetFootnoteIdxs()[n];
    1471           2 :                             pDoc->GetFootnoteIdxs().erase( pDoc->GetFootnoteIdxs().begin() + n );
    1472           2 :                             break;
    1473             :                         }
    1474             :                         // wenn ueber Undo der StartNode gesetzt wurde, kann
    1475             :                         // der Index noch gar nicht in der Verwaltung stehen !!
    1476             :                 }
    1477         140 :                 if( !pTextFootnote )
    1478         138 :                     pTextFootnote = static_cast<SwTextFootnote*>(pAttr);
    1479             : 
    1480             :                 // fuers Update der Nummern und zum Sortieren
    1481             :                 // muss der Node gesetzt sein.
    1482         140 :                 static_cast<SwTextFootnote*>(pAttr)->ChgTextNode( this );
    1483             : 
    1484             :                 // FussNote im Redline-Bereich NICHT ins FootnoteArray einfuegen!
    1485         140 :                 if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
    1486             :                 {
    1487         140 :                     const bool bSuccess = pDoc->GetFootnoteIdxs().insert(pTextFootnote).second;
    1488             :                     OSL_ENSURE( bSuccess, "FootnoteIdx not inserted." );
    1489             :                     (void) bSuccess; // unused in non-debug
    1490             :                 }
    1491         140 :                 SwNodeIndex aTmpIndex( *this );
    1492         140 :                 pDoc->GetFootnoteIdxs().UpdateFootnote( aTmpIndex);
    1493         140 :                 static_cast<SwTextFootnote*>(pAttr)->SetSeqRefNo();
    1494             :             }
    1495         140 :             break;
    1496             : 
    1497             :             case RES_TXTATR_FIELD:
    1498             :                 {
    1499             :                     // fuer HiddenParaFields Benachrichtigungsmechanismus
    1500             :                     // anwerfen
    1501        1885 :                     if( RES_HIDDENPARAFLD == pAttr->GetFormatField().GetField()->GetTyp()->Which() )
    1502             :                     {
    1503           0 :                         bHiddenPara = true;
    1504             :                     }
    1505             :                 }
    1506        1885 :                 break;
    1507             : 
    1508             :         }
    1509             :         // Fuer SwTextHints ohne Endindex werden CH_TXTATR_..
    1510             :         // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
    1511             :         // Wenn wir im SwTextNode::Copy stehen, so wurde das Zeichen bereits
    1512             :         // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
    1513        6099 :         if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
    1514             :         {
    1515        1541 :             SwIndex aIdx( this, pAttr->GetStart() );
    1516        1541 :             OUString const ins( InsertText(OUString(GetCharOfTextAttr(*pAttr)),
    1517        3082 :                         aIdx, nInsertFlags) );
    1518        1541 :             if (ins.isEmpty())
    1519             :             {
    1520           0 :                 DestroyAttr(pAttr);
    1521           0 :                 return false; // text node full :(
    1522             :             }
    1523             : 
    1524             :             // adjust end of hint to account for inserted CH_TXTATR
    1525        1541 :             sal_Int32 * const pEnd(pAttr->GetEnd());
    1526        1541 :             if (pEnd)
    1527             :             {
    1528          97 :                 *pEnd = *pEnd + 1;
    1529        1541 :             }
    1530             :         }
    1531             :     }
    1532             : 
    1533             :     // handle attributes which provide content
    1534       82499 :     sal_Int32 nEnd = nStart;
    1535       82499 :     bool bInputFieldStartCharInserted = false;
    1536       82499 :     bool bInputFieldEndCharInserted = false;
    1537       82499 :     const bool bHasContent( pAttr->HasContent() );
    1538       82499 :     if ( bHasContent )
    1539             :     {
    1540          18 :         switch( pAttr->Which() )
    1541             :         {
    1542             :         case RES_TXTATR_INPUTFIELD:
    1543             :             {
    1544          18 :                 SwTextInputField* pTextInputField = dynamic_cast<SwTextInputField*>(pAttr);
    1545          18 :                 if ( pTextInputField )
    1546             :                 {
    1547          18 :                     if( !(SetAttrMode::NOTXTATRCHR & nMode) )
    1548             :                     {
    1549          14 :                         SwIndex aIdx( this, pAttr->GetStart() );
    1550          14 :                         InsertText( OUString(CH_TXT_ATR_INPUTFIELDSTART), aIdx, nInsertFlags );
    1551          28 :                         const OUString aContent = pTextInputField->GetFieldContent();
    1552          14 :                         InsertText( aContent, aIdx, nInsertFlags );
    1553          14 :                         InsertText( OUString(CH_TXT_ATR_INPUTFIELDEND), aIdx, nInsertFlags );
    1554             : 
    1555          14 :                         sal_Int32* const pEnd(pAttr->GetEnd());
    1556             :                         OSL_ENSURE( pEnd != NULL, "<SwTextNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
    1557          14 :                         if ( pEnd != NULL )
    1558             :                         {
    1559          14 :                             *pEnd = *pEnd + 2 + aContent.getLength();
    1560          14 :                             nEnd = *pEnd;
    1561          14 :                         }
    1562             :                     }
    1563             :                     else
    1564             :                     {
    1565             :                         // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted.
    1566           4 :                         if ( m_Text[ pAttr->GetStart() ] != CH_TXT_ATR_INPUTFIELDSTART )
    1567             :                         {
    1568           0 :                             SwIndex aIdx( this, pAttr->GetStart() );
    1569           0 :                             InsertText( OUString(CH_TXT_ATR_INPUTFIELDSTART), aIdx, nInsertFlags );
    1570           0 :                             bInputFieldStartCharInserted = true;
    1571           0 :                             sal_Int32* const pEnd(pAttr->GetEnd());
    1572             :                             OSL_ENSURE( pEnd != NULL, "<SwTextNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
    1573           0 :                             if ( pEnd != NULL )
    1574             :                             {
    1575           0 :                                 *pEnd = *pEnd + 1;
    1576           0 :                                 nEnd = *pEnd;
    1577           0 :                             }
    1578             :                         }
    1579             : 
    1580           4 :                         sal_Int32* const pEnd(pAttr->GetEnd());
    1581             :                         OSL_ENSURE( pEnd != NULL, "<SwTextNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
    1582           4 :                         if ( pEnd != NULL
    1583           4 :                              && m_Text[ *(pEnd) - 1 ] != CH_TXT_ATR_INPUTFIELDEND )
    1584             :                         {
    1585           0 :                             SwIndex aIdx( this, *(pEnd) );
    1586           0 :                             InsertText( OUString(CH_TXT_ATR_INPUTFIELDEND), aIdx, nInsertFlags );
    1587           0 :                             bInputFieldEndCharInserted = true;
    1588           0 :                             *pEnd = *pEnd + 1;
    1589           0 :                             nEnd = *pEnd;
    1590             :                         }
    1591             :                     }
    1592             :                 }
    1593             :             }
    1594          18 :             break;
    1595             :         default:
    1596           0 :             break;
    1597             :         }
    1598             :     }
    1599             : 
    1600       82499 :     GetOrCreateSwpHints();
    1601             : 
    1602             :     // handle overlap with an existing InputField
    1603       82499 :     bool bInsertHint = true;
    1604             :     {
    1605       82499 :         const SwTextInputField* pTextInputField = GetOverlappingInputField( *pAttr );
    1606       82499 :         if ( pTextInputField != NULL )
    1607             :         {
    1608           0 :             if ( pAttr->End() == NULL )
    1609             :             {
    1610           0 :                 bInsertHint = false;
    1611             :             }
    1612             :             else
    1613             :             {
    1614           0 :                 if ( pAttr->GetStart() > pTextInputField->GetStart() )
    1615             :                 {
    1616           0 :                     pAttr->GetStart() = pTextInputField->GetStart();
    1617             :                 }
    1618           0 :                 if ( *(pAttr->End()) < *(pTextInputField->End()) )
    1619             :                 {
    1620           0 :                     *(pAttr->GetEnd()) = *(pTextInputField->End());
    1621             :                 }
    1622             :             }
    1623             :         }
    1624             :     }
    1625             : 
    1626             :     // 4263: AttrInsert durch TextInsert => kein Adjust
    1627             :     const bool bRet = bInsertHint
    1628       82499 :                       && m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
    1629             : 
    1630       82499 :     if ( !bRet )
    1631             :     {
    1632           4 :         if ( bDummyChar
    1633           6 :              && !(SetAttrMode::NOTXTATRCHR & nMode) )
    1634             :         {
    1635             :             // undo insertion of dummy character
    1636             :             // N.B. cannot insert the dummy character after inserting the hint,
    1637             :             // because if the hint has no extent it will be moved in InsertText,
    1638             :             // resulting in infinite recursion
    1639             :             OSL_ENSURE( ( CH_TXTATR_BREAKWORD == m_Text[nStart] ||
    1640             :                           CH_TXTATR_INWORD    == m_Text[nStart] ),
    1641             :                     "where is my attribute character?" );
    1642           2 :             SwIndex aIdx( this, nStart );
    1643           2 :             EraseText( aIdx, 1 );
    1644             :         }
    1645             : 
    1646           2 :         if ( bHasContent )
    1647             :         {
    1648           0 :             if ( !(SetAttrMode::NOTXTATRCHR & nMode)
    1649           0 :                  && (nEnd - nStart) > 0 )
    1650             :             {
    1651           0 :                 SwIndex aIdx( this, nStart );
    1652           0 :                 EraseText( aIdx, (nEnd - nStart) );
    1653             :             }
    1654             :             else
    1655             :             {
    1656           0 :                 if ( bInputFieldEndCharInserted
    1657           0 :                      && (nEnd - nStart) > 0 )
    1658             :                 {
    1659           0 :                     SwIndex aIdx( this, nEnd - 1 );
    1660           0 :                     EraseText( aIdx, 1 );
    1661             :                 }
    1662             : 
    1663           0 :                 if ( bInputFieldStartCharInserted )
    1664             :                 {
    1665           0 :                     SwIndex aIdx( this, nStart );
    1666           0 :                     EraseText( aIdx, 1 );
    1667             :                 }
    1668             :             }
    1669             :         }
    1670             :     }
    1671             : 
    1672       82499 :     if ( bHiddenPara )
    1673             :     {
    1674           0 :         SetCalcHiddenParaField();
    1675             :     }
    1676             : 
    1677       82499 :     return bRet;
    1678             : }
    1679             : 
    1680        1368 : void SwTextNode::DeleteAttribute( SwTextAttr * const pAttr )
    1681             : {
    1682        1368 :     if ( !HasHints() )
    1683             :     {
    1684             :         OSL_FAIL("DeleteAttribute called, but text node without hints?");
    1685        1368 :         return;
    1686             :     }
    1687             : 
    1688        1368 :     if ( pAttr->HasDummyChar() )
    1689             :     {
    1690             :         // Unbedingt Copy-konstruieren!
    1691        1368 :         const SwIndex aIdx( this, pAttr->GetStart() );
    1692             :         // erase the CH_TXTATR, which will also delete pAttr
    1693        1368 :         EraseText( aIdx, 1 );
    1694             :     }
    1695           0 :     else if ( pAttr->HasContent() )
    1696             :     {
    1697           0 :         const SwIndex aIdx( this, pAttr->GetStart() );
    1698             :         OSL_ENSURE( pAttr->End() != NULL, "<SwTextNode::DeleteAttribute(..)> - missing End() at <SwTextAttr> instance which has content" );
    1699           0 :         EraseText( aIdx, *pAttr->End() - pAttr->GetStart() );
    1700             :     }
    1701             :     else
    1702             :     {
    1703             :         // create MsgHint before start/end become invalid
    1704             :         SwUpdateAttr aHint(
    1705           0 :             pAttr->GetStart(),
    1706           0 :             *pAttr->GetEnd(),
    1707           0 :             pAttr->Which());
    1708             : 
    1709           0 :         m_pSwpHints->Delete( pAttr );
    1710           0 :         SwTextAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
    1711           0 :         NotifyClients( 0, &aHint );
    1712             : 
    1713           0 :         TryDeleteSwpHints();
    1714             :     }
    1715             : }
    1716             : 
    1717             : //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
    1718        2264 : void SwTextNode::DeleteAttributes(
    1719             :     const sal_uInt16 nWhich,
    1720             :     const sal_Int32 nStart,
    1721             :     const sal_Int32 nEnd )
    1722             : {
    1723        2264 :     if ( !HasHints() )
    1724        2264 :         return;
    1725             : 
    1726        4797 :     for ( size_t nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); ++nPos )
    1727             :     {
    1728        2569 :         SwTextAttr * const pTextHt = m_pSwpHints->GetTextHint( nPos );
    1729        2569 :         const sal_Int32 nHintStart = pTextHt->GetStart();
    1730        2569 :         if (nStart < nHintStart)
    1731             :         {
    1732          36 :             break; // sorted by start
    1733             :         }
    1734        2533 :         else if ( (nStart == nHintStart) && (nWhich == pTextHt->Which()) )
    1735             :         {
    1736        2263 :             if ( nWhich == RES_CHRATR_HIDDEN  )
    1737             :             {
    1738             :                 OSL_FAIL("hey, that's a CHRATR! how did that get in?");
    1739           0 :                 SetCalcHiddenCharFlags();
    1740             :             }
    1741        2263 :             else if ( nWhich == RES_TXTATR_CHARFMT )
    1742             :             {
    1743             :                 // Check if character format contains hidden attribute:
    1744           0 :                 const SwCharFormat* pFormat = pTextHt->GetCharFormat().GetCharFormat();
    1745             :                 const SfxPoolItem* pItem;
    1746           0 :                 if ( SfxItemState::SET == pFormat->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
    1747           0 :                     SetCalcHiddenCharFlags();
    1748             :             }
    1749             :             // #i75430# Recalc hidden flags if necessary
    1750        2263 :             else if ( nWhich == RES_TXTATR_AUTOFMT )
    1751             :             {
    1752             :                 // Check if auto style contains hidden attribute:
    1753           1 :                 const SfxPoolItem* pHiddenItem = CharFormat::GetItem( *pTextHt, RES_CHRATR_HIDDEN );
    1754           1 :                 if ( pHiddenItem )
    1755           0 :                     SetCalcHiddenCharFlags();
    1756             :                 // for auto styles DeleteAttributes is only called from Undo
    1757             :                 // so it shouldn't need to care about ignore start/end flags
    1758             :             }
    1759             : 
    1760        2263 :             sal_Int32 const * const pEndIdx = pTextHt->GetEnd();
    1761             : 
    1762        2263 :             if ( pTextHt->HasDummyChar() )
    1763             :             {
    1764             :                 // Unbedingt Copy-konstruieren!
    1765        2262 :                 const SwIndex aIdx( this, nStart );
    1766             :                 // erase the CH_TXTATR, which will also delete pTextHt
    1767        2262 :                 EraseText( aIdx, 1 );
    1768             :             }
    1769           1 :             else if ( pTextHt->HasContent() )
    1770             :             {
    1771           0 :                 const SwIndex aIdx( this, nStart );
    1772             :                 OSL_ENSURE( pTextHt->End() != NULL, "<SwTextNode::DeleteAttributes(..)> - missing End() at <SwTextAttr> instance which has content" );
    1773           0 :                 EraseText( aIdx, *pTextHt->End() - nStart );
    1774             :             }
    1775           1 :             else if( *pEndIdx == nEnd )
    1776             :             {
    1777             :                 // den MsgHint jetzt fuettern, weil gleich sind
    1778             :                 // Start und End weg.
    1779             :                 // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
    1780             :                 // da dies das Feld im Dtor selbst erledigt.
    1781             :                 SwUpdateAttr aHint(
    1782             :                     nStart,
    1783             :                     *pEndIdx,
    1784           1 :                     nWhich);
    1785             : 
    1786           1 :                 m_pSwpHints->DeleteAtPos( nPos );    // gefunden, loeschen,
    1787           1 :                 SwTextAttr::Destroy( pTextHt, GetDoc()->GetAttrPool() );
    1788           1 :                 NotifyClients( 0, &aHint );
    1789             :             }
    1790             :         }
    1791             :     }
    1792        2264 :     TryDeleteSwpHints();
    1793             : }
    1794             : 
    1795           0 : void SwTextNode::DelSoftHyph( const sal_Int32 nStt, const sal_Int32 nEnd )
    1796             : {
    1797           0 :     sal_Int32 nFndPos = nStt;
    1798           0 :     sal_Int32 nEndPos = nEnd;
    1799             :     for (;;)
    1800             :     {
    1801           0 :         nFndPos = m_Text.indexOf(CHAR_SOFTHYPHEN, nFndPos);
    1802           0 :         if (nFndPos<0 || nFndPos>=nEndPos )
    1803             :         {
    1804             :             break;
    1805             :         }
    1806           0 :         const SwIndex aIdx( this, nFndPos );
    1807           0 :         EraseText( aIdx, 1 );
    1808           0 :         --nEndPos;
    1809           0 :     }
    1810           0 : }
    1811             : 
    1812        3966 : bool SwTextNode::IsIgnoredCharFormatForNumbering(const sal_uInt16 nWhich)
    1813             : {
    1814        3966 :     return (nWhich ==  RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_COLOR || nWhich == RES_CHRATR_BACKGROUND || nWhich == RES_CHRATR_ESCAPEMENT);
    1815             : }
    1816             : 
    1817             : //In MS Word, following properties of the paragraph end position wont affect the formatting of bullets, so we ignore them:
    1818             : //Font underline;
    1819             : //Font Italic of Western, CJK and CTL;
    1820             : //Font Bold of Wertern, CJK and CTL;
    1821          55 : bool lcl_IsIgnoredCharFormatForBullets(const sal_uInt16 nWhich)
    1822             : {
    1823          55 :     return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_POSTURE || nWhich == RES_CHRATR_WEIGHT
    1824          50 :         || nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT
    1825         100 :         || nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT);
    1826             : }
    1827             : 
    1828             : //Condition for expanding char set to character style of specified number rule level:
    1829             : //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwContentNode::SwPAttrSet);
    1830             : //The node should have applied a number rule;
    1831             : //The node should be counted in a list, if not, make it to be;
    1832             : //The item should not conflict to any exist and non-default item inside the character of specified number rule level;
    1833             : //The item should not be ignored depend on the exact number rule type;
    1834        5825 : bool SwTextNode::TryCharSetExpandToNum(const SfxItemSet& aCharSet)
    1835             : {
    1836        5825 :     bool bRet = false;
    1837        5825 :     SfxItemIter aIter( aCharSet );
    1838        5825 :         const SfxPoolItem* pItem = aIter.FirstItem();
    1839        5825 :         const sal_uInt16 nWhich = pItem->Which();
    1840             : 
    1841        5825 :     const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
    1842             : 
    1843        5825 :     if (!IsDefaultItem(&rInnerItem) &&  !IsInvalidItem(&rInnerItem))
    1844        4849 :         return bRet;
    1845             : 
    1846         976 :     if (!IsInList() && GetNumRule() && !GetListId().isEmpty())
    1847             :     {
    1848           0 :         return bRet;
    1849             :     }
    1850             : 
    1851         976 :     SwNumRule* pCurrNum = GetNumRule(false);
    1852             : 
    1853         976 :     int nLevel = GetActualListLevel();
    1854             : 
    1855         976 :     if (nLevel != -1 && pCurrNum)
    1856             :     {
    1857          63 :         const SwNumFormat* pCurrNumFormat = pCurrNum->GetNumFormat(static_cast<sal_uInt16>(nLevel));
    1858          63 :         if (pCurrNumFormat)
    1859             :         {
    1860          63 :             if (pCurrNumFormat->IsItemize() && lcl_IsIgnoredCharFormatForBullets(nWhich))
    1861          15 :                 return bRet;
    1862          48 :             if (pCurrNumFormat->IsEnumeration() && SwTextNode::IsIgnoredCharFormatForNumbering(nWhich))
    1863           1 :                 return bRet;
    1864          47 :             SwCharFormat* pCurrCharFormat =pCurrNumFormat->GetCharFormat();
    1865             : 
    1866          47 :             if (pCurrCharFormat && pCurrCharFormat->GetItemState(nWhich,false) != SfxItemState::SET)
    1867             :             {
    1868          11 :                 pCurrCharFormat->SetFormatAttr(*pItem);
    1869          11 :                 SwNumFormat aNewNumFormat(*pCurrNumFormat);
    1870          11 :                 aNewNumFormat.SetCharFormat(pCurrCharFormat);
    1871          11 :                 pCurrNum->Set(nLevel,aNewNumFormat);
    1872          11 :                 bRet = true;
    1873             :             }
    1874             :         }
    1875             :     }
    1876             : 
    1877         960 :     return bRet;
    1878             : }
    1879             : 
    1880             : // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
    1881             : // dann setze sie nur im AutoAttrSet (SwContentNode:: SetAttr)
    1882      101786 : bool SwTextNode::SetAttr(
    1883             :     const SfxItemSet& rSet,
    1884             :     const sal_Int32 nStt,
    1885             :     const sal_Int32 nEnd,
    1886             :     const SetAttrMode nMode )
    1887             : {
    1888      101786 :     if( !rSet.Count() )
    1889           0 :         return false;
    1890             : 
    1891             :     // teil die Sets auf (fuer Selektion in Nodes)
    1892      101786 :     const SfxItemSet* pSet = &rSet;
    1893      101786 :     SfxItemSet aTextSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
    1894             : 
    1895             :     // gesamter Bereich
    1896      346837 :     if ( !nStt && (nEnd == m_Text.getLength()) &&
    1897      226223 :          !(nMode & SetAttrMode::NOFORMATATTR ) )
    1898             :     {
    1899             :         // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
    1900             :         // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
    1901       30468 :         bool bHasCharFormats = false;
    1902       30468 :         if ( HasHints() )
    1903             :         {
    1904       14539 :             for ( size_t n = 0; n < m_pSwpHints->Count(); ++n )
    1905             :             {
    1906        9074 :                 if ( (*m_pSwpHints)[ n ]->IsCharFormatAttr() )
    1907             :                 {
    1908         403 :                     bHasCharFormats = true;
    1909         403 :                     break;
    1910             :                 }
    1911             :             }
    1912             :         }
    1913             : 
    1914       30468 :         if( !bHasCharFormats )
    1915             :         {
    1916       30065 :             aTextSet.Put( rSet );
    1917             :             // If there are any character attributes in rSet,
    1918             :             // we want to set them at the paragraph:
    1919       30065 :             if( aTextSet.Count() != rSet.Count() )
    1920             :             {
    1921       27109 :                 const bool bRet = SetAttr( rSet );
    1922       27109 :                 if( !aTextSet.Count() )
    1923       55580 :                     return bRet;
    1924             :             }
    1925             : 
    1926             :             // check for auto style:
    1927             :             const SfxPoolItem* pItem;
    1928        3017 :             const bool bAutoStyle = SfxItemState::SET == aTextSet.GetItemState( RES_TXTATR_AUTOFMT, false, &pItem );
    1929        3017 :             if ( bAutoStyle )
    1930             :             {
    1931        1484 :                 std::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFormatAutoFormat*>(pItem)->GetStyleHandle();
    1932        1484 :                 const bool bRet = SetAttr( *pAutoStyleSet );
    1933        1484 :                 if( 1 == aTextSet.Count() )
    1934        1484 :                     return bRet;
    1935             :             }
    1936             : 
    1937             :             // Continue with the text attributes:
    1938        1533 :             pSet = &aTextSet;
    1939             :         }
    1940             :     }
    1941             : 
    1942       73254 :     GetOrCreateSwpHints();
    1943             : 
    1944      146508 :     SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFormatSetRange );
    1945             : 
    1946       73254 :     size_t nCount = 0;
    1947      146508 :     SfxItemIter aIter( *pSet );
    1948       73254 :     const SfxPoolItem* pItem = aIter.GetCurItem();
    1949             : 
    1950             :     do
    1951             :     {
    1952      224590 :         if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
    1953             :         {
    1954      224590 :             const sal_uInt16 nWhich = pItem->Which();
    1955             :             OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
    1956             :                     "SwTextNode::SetAttr(): unknown attribute" );
    1957      224590 :             if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
    1958             :             {
    1959      230586 :                 if ((RES_TXTATR_CHARFMT == nWhich) &&
    1960        5996 :                     (GetDoc()->GetDfltCharFormat() ==
    1961        5996 :                      static_cast<const SwFormatCharFormat*>(pItem)->GetCharFormat()))
    1962             :                 {
    1963           0 :                     SwIndex aIndex( this, nStt );
    1964           0 :                     RstTextAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
    1965           0 :                     DontExpandFormat( aIndex );
    1966             :                 }
    1967             :                 else
    1968             :                 {
    1969      224590 :                     if (isCHRATR(nWhich) ||
    1970             :                         (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
    1971             :                     {
    1972      212897 :                         aCharSet.Put( *pItem );
    1973             :                     }
    1974             :                     else
    1975             :                     {
    1976             : 
    1977       11693 :                         SwTextAttr *const pNew = MakeTextAttr( *GetDoc(),
    1978       11693 :                                 const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
    1979       11693 :                         if ( pNew )
    1980             :                         {
    1981       11693 :                             if ( nEnd != nStt && !pNew->GetEnd() )
    1982             :                             {
    1983             :                                 OSL_FAIL("Attribut without end, but area marked");
    1984           0 :                                 DestroyAttr( pNew ); // do not insert
    1985             :                             }
    1986       11693 :                             else if ( InsertHint( pNew, nMode ) )
    1987             :                             {
    1988       11691 :                                 ++nCount;
    1989             :                             }
    1990             :                         }
    1991             :                     }
    1992             :                 }
    1993             :             }
    1994             :         }
    1995      224590 :         if ( aIter.IsAtEnd() )
    1996       73254 :             break;
    1997      151336 :         pItem = aIter.NextItem();
    1998             :     } while( true );
    1999             : 
    2000       73254 :     if ( aCharSet.Count() )
    2001             :     {
    2002       62673 :         SwTextAttr* pTmpNew = MakeTextAttr( *GetDoc(), aCharSet, nStt, nEnd );
    2003       62673 :         if ( InsertHint( pTmpNew, nMode ) )
    2004             :         {
    2005       62673 :             ++nCount;
    2006             :         }
    2007             :     }
    2008             : 
    2009       73254 :     TryDeleteSwpHints();
    2010             : 
    2011      175040 :     return nCount != 0;
    2012             : }
    2013             : 
    2014        5101 : static void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
    2015             : {
    2016        5101 :     if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
    2017             :     {
    2018        4446 :         const SfxItemSet* pCFSet = CharFormat::GetItemSet( rAttr );
    2019        4446 :         if ( !pCFSet )
    2020        5101 :             return;
    2021        4446 :         SfxWhichIter aIter( *pCFSet );
    2022        4446 :         sal_uInt16 nWhich = aIter.FirstWhich();
    2023      217849 :         while( nWhich )
    2024             :         {
    2025      217844 :             if( ( nWhich < RES_CHRATR_END ||
    2026      413468 :                   RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
    2027      204511 :                 ( SfxItemState::SET == pCFSet->GetItemState( nWhich, true ) ) )
    2028       30187 :                 rSet.Put( pCFSet->Get( nWhich ) );
    2029      208957 :             nWhich = aIter.NextWhich();
    2030        4446 :         }
    2031             :     }
    2032             :     else
    2033         655 :         rSet.Put( rAttr );
    2034             : }
    2035             : 
    2036       57609 : static void lcl_MergeAttr_ExpandChrFormat( SfxItemSet& rSet, const SfxPoolItem& rAttr )
    2037             : {
    2038      168678 :     if( RES_TXTATR_CHARFMT == rAttr.Which() ||
    2039      109718 :         RES_TXTATR_INETFMT == rAttr.Which() ||
    2040       52109 :         RES_TXTATR_AUTOFMT == rAttr.Which() )
    2041             :     {
    2042       53763 :         const SfxItemSet* pCFSet = CharFormat::GetItemSet( rAttr );
    2043             : 
    2044       53763 :         if ( pCFSet )
    2045             :         {
    2046       53702 :             SfxWhichIter aIter( *pCFSet );
    2047       53702 :             sal_uInt16 nWhich = aIter.FirstWhich();
    2048     2625942 :             while( nWhich )
    2049             :             {
    2050     2620486 :                 if( ( nWhich < RES_CHRATR_END ||
    2051     5079883 :                       ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
    2052     2464836 :                     ( SfxItemState::SET == pCFSet->GetItemState( nWhich, true ) ) )
    2053      249885 :                     rSet.Put( pCFSet->Get( nWhich ) );
    2054     2518538 :                 nWhich = aIter.NextWhich();
    2055       53702 :             }
    2056             :         }
    2057             :     }
    2058             : 
    2059             :     // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
    2060             : 
    2061             : /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
    2062             :  z.B
    2063             :             1234567890123456789
    2064             :               |------------|        Font1
    2065             :                  |------|           Font2
    2066             :                     ^  ^
    2067             :                     |--|        Abfragebereich: -> Gueltig ist Font2
    2068             : */
    2069       57609 :     rSet.Put( rAttr );
    2070       57609 : }
    2071             : 
    2072             : struct SwPoolItemEndPair
    2073             : {
    2074             : public:
    2075             :     const SfxPoolItem* mpItem;
    2076             :     sal_Int32 mnEndPos;
    2077             : 
    2078       81455 :     SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
    2079             : };
    2080             : 
    2081       13910 : static void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTextNode& rTextNode,
    2082             :                                             SfxItemSet& rSet )
    2083             : {
    2084       13910 :     if ( rTextNode.AreListLevelIndentsApplicable() )
    2085             :     {
    2086           3 :         const SwNumRule* pRule = rTextNode.GetNumRule();
    2087           3 :         if ( pRule && rTextNode.GetActualListLevel() >= 0 )
    2088             :         {
    2089           3 :             const SwNumFormat& rFormat = pRule->Get(static_cast<sal_uInt16>(rTextNode.GetActualListLevel()));
    2090           3 :             if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
    2091             :             {
    2092           3 :                 SvxLRSpaceItem aLR( RES_LR_SPACE );
    2093           3 :                 aLR.SetTextLeft( rFormat.GetIndentAt() );
    2094           3 :                 aLR.SetTextFirstLineOfst( static_cast<short>(rFormat.GetFirstLineIndent()) );
    2095           3 :                 rSet.Put( aLR );
    2096             :             }
    2097             :         }
    2098             :     }
    2099       13910 : }
    2100             : 
    2101             : // erfrage die Attribute vom TextNode ueber den Bereich
    2102      189192 : bool SwTextNode::GetAttr( SfxItemSet& rSet, sal_Int32 nStt, sal_Int32 nEnd,
    2103             :                          const bool bOnlyTextAttr, const bool bGetFromChrFormat,
    2104             :                          const bool bMergeIndentValuesOfNumRule ) const
    2105             : {
    2106      189192 :     if( HasHints() )
    2107             :     {
    2108             :         /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
    2109             :          * sind. Dabei gibt es folgende Faelle:
    2110             :          *  UnEindeutig wenn: (wenn != Format-Attribut)
    2111             :          *      - das Attribut liegt vollstaendig im Bereich
    2112             :          *      - das Attributende liegt im Bereich
    2113             :          *      - der Attributanfang liegt im Bereich:
    2114             :          * Eindeutig (im Set mergen):
    2115             :          *      - das Attrib umfasst den Bereich
    2116             :          * nichts tun:
    2117             :          *      das Attribut liegt ausserhalb des Bereiches
    2118             :          */
    2119             : 
    2120             :         void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
    2121             :             = bGetFromChrFormat ? &lcl_MergeAttr_ExpandChrFormat
    2122       77020 :                              : &lcl_MergeAttr;
    2123             : 
    2124             :         // dann besorge mal die Auto-(Format)Attribute
    2125       77020 :         SfxItemSet aFormatSet( *rSet.GetPool(), rSet.GetRanges() );
    2126       77020 :         if( !bOnlyTextAttr )
    2127             :         {
    2128       72041 :             SwContentNode::GetAttr( aFormatSet );
    2129       72041 :             if ( bMergeIndentValuesOfNumRule )
    2130             :             {
    2131         396 :                 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFormatSet );
    2132             :             }
    2133             :         }
    2134             : 
    2135       77020 :         const size_t nSize = m_pSwpHints->Count();
    2136             : 
    2137       77020 :         if( nStt == nEnd )             // kein Bereich:
    2138             :         {
    2139      197883 :             for (size_t n = 0; n < nSize; ++n)
    2140             :             {
    2141      168878 :                 const SwTextAttr* pHt = (*m_pSwpHints)[n];
    2142      168878 :                 const sal_Int32 nAttrStart = pHt->GetStart();
    2143      168878 :                 if( nAttrStart > nEnd )         // ueber den Bereich hinaus
    2144          63 :                     break;
    2145             : 
    2146      168815 :                 const sal_Int32* pAttrEnd = pHt->End();
    2147      168815 :                 if ( ! pAttrEnd ) // no attributes without end
    2148      118971 :                     continue;
    2149             : 
    2150       86612 :                 if( ( nAttrStart < nStt &&
    2151       38966 :                         ( pHt->DontExpand() ? nStt < *pAttrEnd
    2152      184094 :                                             : nStt <= *pAttrEnd )) ||
    2153       13076 :                     ( nStt == nAttrStart &&
    2154       13256 :                         ( nAttrStart == *pAttrEnd || !nStt )))
    2155       34986 :                     (*fnMergeAttr)( rSet, pHt->GetAttr() );
    2156             :             }
    2157             :         }
    2158             :         else                            // es ist ein Bereich definiert
    2159             :         {
    2160             :             // #i75299#
    2161       47952 :             std::unique_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
    2162             : 
    2163       47952 :             const size_t coArrSz = RES_TXTATR_WITHEND_END - RES_CHRATR_BEGIN;
    2164             : 
    2165      179758 :             for (size_t n = 0; n < nSize; ++n)
    2166             :             {
    2167      132814 :                 const SwTextAttr* pHt = (*m_pSwpHints)[n];
    2168      132814 :                 const sal_Int32 nAttrStart = pHt->GetStart();
    2169      132814 :                 if( nAttrStart > nEnd )         // ueber den Bereich hinaus
    2170        1008 :                     break;
    2171             : 
    2172      131806 :                 const sal_Int32* pAttrEnd = pHt->End();
    2173      131806 :                 if ( ! pAttrEnd ) // no attributes without end
    2174        4976 :                     continue;
    2175             : 
    2176      126830 :                 bool bChkInvalid = false;
    2177      126830 :                 if( nAttrStart <= nStt )       // vor oder genau Start
    2178             :                 {
    2179      103583 :                     if( *pAttrEnd <= nStt )    // liegt davor
    2180       77146 :                         continue;
    2181             : 
    2182       26437 :                     if( nEnd <= *pAttrEnd )     // hinter oder genau Ende
    2183       25612 :                         (*fnMergeAttr)( aFormatSet, pHt->GetAttr() );
    2184             :                     else
    2185             : //                  else if( pHt->GetAttr() != aFormatSet.Get( pHt->Which() ) )
    2186             :                         // uneindeutig
    2187         825 :                         bChkInvalid = true;
    2188             :                 }
    2189       23247 :                 else if( nAttrStart < nEnd      // reicht in den Bereich
    2190             : )//                      && pHt->GetAttr() != aFormatSet.Get( pHt->Which() ) )
    2191        2359 :                     bChkInvalid = true;
    2192             : 
    2193       49684 :                 if( bChkInvalid )
    2194             :                 {
    2195             :                     // uneindeutig ?
    2196        3184 :                     std::unique_ptr< SfxItemIter > pItemIter;
    2197        3184 :                     const SfxPoolItem* pItem = 0;
    2198             : 
    2199        3184 :                     if ( RES_TXTATR_AUTOFMT == pHt->Which() )
    2200             :                     {
    2201        2596 :                         const SfxItemSet* pAutoSet = CharFormat::GetItemSet( pHt->GetAttr() );
    2202        2596 :                         if ( pAutoSet )
    2203             :                         {
    2204        2596 :                             pItemIter.reset( new SfxItemIter( *pAutoSet ) );
    2205        2596 :                             pItem = pItemIter->GetCurItem();
    2206             :                         }
    2207             :                     }
    2208             :                     else
    2209         588 :                         pItem = &pHt->GetAttr();
    2210             : 
    2211        3184 :                     const sal_Int32 nHintEnd = *pAttrEnd;
    2212             : 
    2213       16044 :                     while ( pItem )
    2214             :                     {
    2215        9676 :                         const sal_uInt16 nHintWhich = pItem->Which();
    2216             :                         OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
    2217             :                                 "SwTextNode::GetAttr(): unknown attribute?");
    2218             : 
    2219        9676 :                         if ( !pAttrArr.get() )
    2220             :                         {
    2221             :                             pAttrArr.reset(
    2222        1481 :                                 new std::vector< SwPoolItemEndPair >(coArrSz));
    2223             :                         }
    2224             : 
    2225        9676 :                         std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
    2226       10264 :                         if (isCHRATR(nHintWhich) ||
    2227         588 :                             isTXTATR_WITHEND(nHintWhich))
    2228             :                         {
    2229        9676 :                             pPrev += nHintWhich - RES_CHRATR_BEGIN;
    2230             :                         }
    2231             :                         else
    2232             :                         {
    2233           0 :                             pPrev = pAttrArr->end();
    2234             :                         }
    2235             : 
    2236        9676 :                         if( pPrev != pAttrArr->end() )
    2237             :                         {
    2238        9676 :                             if( !pPrev->mpItem )
    2239             :                             {
    2240        4655 :                                 if ( bOnlyTextAttr || *pItem != aFormatSet.Get( nHintWhich ) )
    2241             :                                 {
    2242        3842 :                                     if( nAttrStart > nStt )
    2243             :                                     {
    2244         586 :                                         rSet.InvalidateItem( nHintWhich );
    2245         586 :                                         pPrev->mpItem = reinterpret_cast<SfxPoolItem*>(-1);
    2246             :                                     }
    2247             :                                     else
    2248             :                                     {
    2249        3256 :                                         pPrev->mpItem = pItem;
    2250        3256 :                                         pPrev->mnEndPos = nHintEnd;
    2251             :                                     }
    2252             :                                 }
    2253             :                             }
    2254        5021 :                             else if( reinterpret_cast<SfxPoolItem*>(-1) != pPrev->mpItem )
    2255             :                             {
    2256        8150 :                                 if( pPrev->mnEndPos == nAttrStart &&
    2257        4007 :                                     *pPrev->mpItem == *pItem )
    2258             :                                 {
    2259        3824 :                                     pPrev->mpItem = pItem;
    2260        3824 :                                     pPrev->mnEndPos = nHintEnd;
    2261             :                                 }
    2262             :                                 else
    2263             :                                 {
    2264         319 :                                     rSet.InvalidateItem( nHintWhich );
    2265         319 :                                     pPrev->mpItem = reinterpret_cast<SfxPoolItem*>(-1);
    2266             :                                 }
    2267             :                             }
    2268             :                         }
    2269             : 
    2270       18764 :                         pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
    2271       16168 :                                     ? pItemIter->NextItem() : 0;
    2272        3184 :                     } // end while
    2273             :                 }
    2274             :             }
    2275             : 
    2276       47952 :             if ( pAttrArr.get() )
    2277             :             {
    2278       82936 :                 for (size_t n = 0; n < coArrSz; ++n)
    2279             :                 {
    2280       81455 :                     const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
    2281       81455 :                     if( (0 != rItemPair.mpItem) && (reinterpret_cast<SfxPoolItem*>(-1) != rItemPair.mpItem) )
    2282             :                     {
    2283             :                         const sal_uInt16 nWh =
    2284        2937 :                             static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
    2285             : 
    2286        2937 :                         if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
    2287             :                         {
    2288        2114 :                             if( *rItemPair.mpItem != aFormatSet.Get( nWh ) )
    2289        2112 :                                 (*fnMergeAttr)( rSet, *rItemPair.mpItem );
    2290             :                         }
    2291             :                         else
    2292             :                             // uneindeutig
    2293         823 :                             rSet.InvalidateItem( nWh );
    2294             :                     }
    2295             :                 }
    2296       47952 :             }
    2297             :         }
    2298       77020 :         if( aFormatSet.Count() )
    2299             :         {
    2300             :             // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
    2301       42287 :             aFormatSet.Differentiate( rSet );
    2302             :             // jetzt alle zusammen "mergen"
    2303       42287 :             rSet.Put( aFormatSet );
    2304       77020 :         }
    2305             :     }
    2306      112172 :     else if( !bOnlyTextAttr )
    2307             :     {
    2308             :         // dann besorge mal die Auto-(Format)Attribute
    2309      108955 :         SwContentNode::GetAttr( rSet );
    2310      108955 :         if ( bMergeIndentValuesOfNumRule )
    2311             :         {
    2312       13514 :             lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
    2313             :         }
    2314             :     }
    2315             : 
    2316      189192 :     return rSet.Count() != 0;
    2317             : }
    2318             : 
    2319             : namespace
    2320             : {
    2321             : 
    2322             : typedef std::pair<sal_Int32, sal_Int32> AttrSpan_t;
    2323             : typedef std::multimap<AttrSpan_t, const SwTextAttr*> AttrSpanMap_t;
    2324             : 
    2325             : struct IsAutoStyle
    2326             : {
    2327             :     bool
    2328          58 :     operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
    2329             :     const
    2330             :     {
    2331          58 :         return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
    2332             :     }
    2333             : };
    2334             : 
    2335             : /** Removes from io_rAttrSet all items that are set by style on the
    2336             :     given span.
    2337             :   */
    2338             : struct RemovePresentAttrs
    2339             : {
    2340          58 :     explicit RemovePresentAttrs(SfxItemSet& io_rAttrSet)
    2341          58 :         : m_rAttrSet(io_rAttrSet)
    2342             :     {
    2343          58 :     }
    2344             : 
    2345             :     void
    2346          58 :     operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
    2347             :     const
    2348             :     {
    2349          58 :         if (!i_rAttrSpan.second)
    2350             :         {
    2351         116 :             return;
    2352             :         }
    2353             : 
    2354           0 :         const SwTextAttr* const pAutoStyle(i_rAttrSpan.second);
    2355           0 :         SfxItemIter aIter(m_rAttrSet);
    2356           0 :         const SfxPoolItem* pItem(aIter.GetCurItem());
    2357           0 :         while (pItem)
    2358             :         {
    2359           0 :             const sal_uInt16 nWhich(pItem->Which());
    2360           0 :             if (CharFormat::IsItemIncluded(nWhich, pAutoStyle))
    2361             :             {
    2362           0 :                 m_rAttrSet.ClearItem(nWhich);
    2363             :             }
    2364             : 
    2365           0 :             if (aIter.IsAtEnd())
    2366             :             {
    2367           0 :                 break;
    2368             :             }
    2369           0 :             pItem = aIter.NextItem();
    2370           0 :         }
    2371             :     }
    2372             : 
    2373             : private:
    2374             :     SfxItemSet& m_rAttrSet;
    2375             : };
    2376             : 
    2377             : /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
    2378             :     addition inserts dummy spans with pointer to format equal to 0 for
    2379             :     all gaps (i.e. spans not covered by any style). This simplifies
    2380             :     creation of autostyles for all needed spans, but it means all code
    2381             :     that tries to access the pointer has to check if it's non-null!
    2382             :  */
    2383             : void
    2384          64 : lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_Int32 nLength,
    2385             :         AttrSpanMap_t& o_rSpanMap)
    2386             : {
    2387          64 :     sal_Int32 nLastEnd(0);
    2388             : 
    2389         107 :     for (size_t i = 0; i < i_rHints.Count(); ++i)
    2390             :     {
    2391          43 :         const SwTextAttr* const pHint(i_rHints[i]);
    2392          43 :         const sal_uInt16 nWhich(pHint->Which());
    2393          43 :         if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
    2394             :         {
    2395           0 :             const AttrSpan_t aSpan(pHint->GetStart(), *pHint->End());
    2396           0 :             o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
    2397             : 
    2398             :             // < not != because there may be multiple CHARFMT at same range
    2399           0 :             if (nLastEnd < aSpan.first)
    2400             :             {
    2401             :                 // insert dummy span covering the gap
    2402             :                 o_rSpanMap.insert(AttrSpanMap_t::value_type(
    2403           0 :                     AttrSpan_t(nLastEnd, aSpan.first), nullptr));
    2404             :             }
    2405             : 
    2406           0 :             nLastEnd = aSpan.second;
    2407             :         }
    2408             :     }
    2409             : 
    2410             :     // no hints at the end (special case: no hints at all in i_rHints)
    2411          64 :     if (nLastEnd != nLength && nLength != 0)
    2412             :     {
    2413             :         o_rSpanMap.insert(
    2414          58 :             AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), nullptr));
    2415             :     }
    2416          64 : }
    2417             : 
    2418             : void
    2419          64 : lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
    2420             : {
    2421          64 :     o_rClearIds.reserve(i_rAttrSet.Count());
    2422          64 :     SfxItemIter aIter(i_rAttrSet);
    2423          64 :     const SfxPoolItem* pItem(aIter.GetCurItem());
    2424         244 :     while (pItem)
    2425             :     {
    2426         180 :         o_rClearIds.push_back(pItem->Which());
    2427             : 
    2428         180 :         if (aIter.IsAtEnd())
    2429             :         {
    2430          64 :             break;
    2431             :         }
    2432         116 :         pItem = aIter.NextItem();
    2433          64 :     }
    2434          64 : }
    2435             : 
    2436             : struct SfxItemSetClearer
    2437             : {
    2438             :     SfxItemSet & m_rItemSet;
    2439        1586 :     explicit SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
    2440         174 :     void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
    2441             : };
    2442             : 
    2443             : }
    2444             : 
    2445             : /** Does the hard work of SwTextNode::FormatToTextAttr: the real conversion
    2446             :     of items to automatic styles.
    2447             :  */
    2448             : void
    2449       75161 : SwTextNode::impl_FormatToTextAttr(const SfxItemSet& i_rAttrSet)
    2450             : {
    2451             :     typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
    2452       75161 :     AttrSpanMap_t aAttrSpanMap;
    2453             : 
    2454       75161 :     if (i_rAttrSet.Count() == 0)
    2455             :     {
    2456      150258 :         return;
    2457             :     }
    2458             : 
    2459             :     // 1. Identify all spans in hints' array
    2460             : 
    2461          64 :     lcl_CollectHintSpans(*m_pSwpHints, m_Text.getLength(), aAttrSpanMap);
    2462             : 
    2463             :     // 2. Go through all spans and insert new attrs
    2464             : 
    2465          64 :     AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
    2466          64 :     const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
    2467         186 :     while (aCurRange != aEnd)
    2468             :     {
    2469             :         typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
    2470             :             AttrSpanMapRange_t;
    2471          58 :         AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
    2472             : 
    2473             :         // 2a. Collect attributes to insert
    2474             : 
    2475          58 :         SfxItemSet aCurSet(i_rAttrSet);
    2476          58 :         std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
    2477             : 
    2478             :         // 2b. Insert automatic style containing the collected attributes
    2479             : 
    2480          58 :         if (aCurSet.Count() != 0)
    2481             :         {
    2482             :             AttrSpanMap_iterator_t aAutoStyleIt(
    2483          58 :                     std::find_if(aRange.first, aRange.second, IsAutoStyle()));
    2484          58 :             if (aAutoStyleIt != aRange.second)
    2485             :             {
    2486             :                 // there already is an automatic style on that span:
    2487             :                 // create new one and remove the original one
    2488           0 :                 SwTextAttr* const pAutoStyle(const_cast<SwTextAttr*>(aAutoStyleIt->second));
    2489             :                 const std::shared_ptr<SfxItemSet> pOldStyle(
    2490             :                         static_cast<const SwFormatAutoFormat&>(
    2491           0 :                             pAutoStyle->GetAttr()).GetStyleHandle());
    2492           0 :                 aCurSet.Put(*pOldStyle);
    2493             : 
    2494             :                 // remove the old hint
    2495           0 :                 m_pSwpHints->Delete(pAutoStyle);
    2496           0 :                 DestroyAttr(pAutoStyle);
    2497             :             }
    2498             :             m_pSwpHints->Insert(
    2499          58 :                     MakeTextAttr(*GetDoc(), aCurSet,
    2500         116 :                         aCurRange->first.first, aCurRange->first.second));
    2501             :         }
    2502             : 
    2503          58 :         aCurRange = aRange.second;
    2504          58 :     }
    2505             : 
    2506             :     // hints were directly inserted, so need to fix the Ignore flags now
    2507          64 :     m_pSwpHints->MergePortions(*this);
    2508             : 
    2509             :     // 3. Clear items from the node
    2510         128 :     std::vector<sal_uInt16> aClearedIds;
    2511          64 :     lcl_FillWhichIds(i_rAttrSet, aClearedIds);
    2512         128 :     ClearItemsFromAttrSet(aClearedIds);
    2513             : }
    2514             : 
    2515       74991 : void SwTextNode::FormatToTextAttr( SwTextNode* pNd )
    2516             : {
    2517       74991 :     SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFormatSetRange );
    2518       74991 :     if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
    2519        1767 :         aThisSet.Put( *GetpSwAttrSet() );
    2520             : 
    2521       74991 :     GetOrCreateSwpHints();
    2522             : 
    2523       74991 :     if( pNd == this )
    2524             :     {
    2525       73405 :         impl_FormatToTextAttr(aThisSet);
    2526             :     }
    2527             :     else
    2528             :     {
    2529             :         // There are five possible combinations of items from this and
    2530             :         // pNd (pNd is the 'main' node):
    2531             : 
    2532             :         //  case    pNd     this     action
    2533             : 
    2534             :         //     1     -       -      do nothing
    2535             :         //     2     -       a      convert item to attr of this
    2536             :         //     3     a       -      convert item to attr of pNd
    2537             :         //     4     a       a      clear item in this
    2538             :         //     5     a       b      convert item to attr of this
    2539             : 
    2540        1586 :         SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFormatSetRange );
    2541        1586 :         if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
    2542        1164 :             aNdSet.Put( *pNd->GetpSwAttrSet() );
    2543             : 
    2544        1586 :         pNd->GetOrCreateSwpHints();
    2545             : 
    2546        3172 :         std::vector<sal_uInt16> aProcessedIds;
    2547             : 
    2548        1586 :         if( aThisSet.Count() )
    2549             :         {
    2550         170 :             SfxItemIter aIter( aThisSet );
    2551         170 :             const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
    2552         340 :             SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFormatSetRange );
    2553         340 :             std::vector<sal_uInt16> aClearWhichIds;
    2554             : 
    2555             :             while( true )
    2556             :             {
    2557         174 :                 if( SfxItemState::SET == aNdSet.GetItemState( pItem->Which(), false, &pNdItem ) )
    2558             :                 {
    2559         174 :                     if (*pItem == *pNdItem) // 4
    2560             :                     {
    2561         174 :                         aClearWhichIds.push_back( pItem->Which() );
    2562             :                     }
    2563             :                     else    // 5
    2564             :                     {
    2565           0 :                         aConvertSet.Put(*pItem);
    2566             :                     }
    2567         174 :                     aProcessedIds.push_back(pItem->Which());
    2568             :                 }
    2569             :                 else    // 2
    2570             :                 {
    2571           0 :                     aConvertSet.Put(*pItem);
    2572             :                 }
    2573             : 
    2574         174 :                 if( aIter.IsAtEnd() )
    2575         170 :                     break;
    2576           4 :                 pItem = aIter.NextItem();
    2577             :             }
    2578             : 
    2579             :             // 4/ clear items of this that are set with the same value on pNd
    2580         170 :             ClearItemsFromAttrSet( aClearWhichIds );
    2581             : 
    2582             :             // 2, 5/ convert all other items to attrs
    2583         340 :             impl_FormatToTextAttr(aConvertSet);
    2584             :         }
    2585             : 
    2586             :         {
    2587             :             std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
    2588        1586 :                     SfxItemSetClearer(aNdSet));
    2589             : 
    2590             :             // 3/ convert items to attrs
    2591        1586 :             pNd->impl_FormatToTextAttr(aNdSet);
    2592             : 
    2593        1586 :             if( aNdSet.Count() )
    2594             :             {
    2595          15 :                 SwFormatChg aTmp1( pNd->GetFormatColl() );
    2596          15 :                 pNd->NotifyClients( &aTmp1, &aTmp1 );
    2597             :             }
    2598        1586 :         }
    2599             :     }
    2600             : 
    2601       74991 :     SetCalcHiddenCharFlags();
    2602             : 
    2603       74991 :     pNd->TryDeleteSwpHints();
    2604       74991 : }
    2605             : 
    2606       51231 : void SwpHints::CalcFlags()
    2607             : {
    2608       51231 :     m_bDDEFields = m_bFootnote = false;
    2609       51231 :     const size_t nSize = Count();
    2610      325598 :     for( size_t nPos = 0; nPos < nSize; ++nPos )
    2611             :     {
    2612      274367 :         const SwTextAttr* pAttr = (*this)[ nPos ];
    2613      274367 :         switch( pAttr->Which() )
    2614             :         {
    2615             :         case RES_TXTATR_FTN:
    2616         253 :             m_bFootnote = true;
    2617         253 :             if ( m_bDDEFields )
    2618           0 :                 return;
    2619         253 :             break;
    2620             :         case RES_TXTATR_FIELD:
    2621             :             {
    2622      127138 :                 const SwField* pField = pAttr->GetFormatField().GetField();
    2623      127138 :                 if( RES_DDEFLD == pField->GetTyp()->Which() )
    2624             :                 {
    2625           0 :                     m_bDDEFields = true;
    2626           0 :                     if ( m_bFootnote )
    2627           0 :                         return;
    2628             :                 }
    2629             :             }
    2630      127138 :             break;
    2631             :         }
    2632             :     }
    2633             : }
    2634             : 
    2635        1239 : bool SwpHints::CalcHiddenParaField()
    2636             : {
    2637        1239 :     m_bCalcHiddenParaField = false;
    2638        1239 :     bool bOldHasHiddenParaField = m_bHasHiddenParaField;
    2639        1239 :     bool bNewHasHiddenParaField  = false;
    2640        1239 :     const size_t nSize = Count();
    2641             :     const SwTextAttr *pTextHt;
    2642             : 
    2643        3838 :     for( size_t nPos = 0; nPos < nSize; ++nPos )
    2644             :     {
    2645        2599 :         pTextHt = (*this)[ nPos ];
    2646        2599 :         const sal_uInt16 nWhich = pTextHt->Which();
    2647             : 
    2648        2599 :         if( RES_TXTATR_FIELD == nWhich )
    2649             :         {
    2650        1882 :             const SwFormatField& rField = pTextHt->GetFormatField();
    2651        1882 :             if( RES_HIDDENPARAFLD == rField.GetField()->GetTyp()->Which() )
    2652             :             {
    2653           0 :                 if( !static_cast<const SwHiddenParaField*>(rField.GetField())->IsHidden() )
    2654             :                 {
    2655           0 :                     SetHiddenParaField(false);
    2656           0 :                     return bOldHasHiddenParaField != bNewHasHiddenParaField;
    2657             :                 }
    2658             :                 else
    2659             :                 {
    2660           0 :                     bNewHasHiddenParaField = true;
    2661             :                 }
    2662             :             }
    2663             :         }
    2664             :     }
    2665        1239 :     SetHiddenParaField( bNewHasHiddenParaField );
    2666        1239 :     return bOldHasHiddenParaField != bNewHasHiddenParaField;
    2667             : }
    2668             : 
    2669      175408 : void SwpHints::NoteInHistory( SwTextAttr *pAttr, const bool bNew )
    2670             : {
    2671      175408 :     if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
    2672      175408 : }
    2673             : 
    2674       64476 : bool SwpHints::MergePortions( SwTextNode& rNode )
    2675             : {
    2676       64476 :     if ( !Count() )
    2677         107 :         return false;
    2678             : 
    2679             :     // sort before merging
    2680       64369 :     SwpHintsArray::Resort();
    2681             : 
    2682       64369 :     bool bRet = false;
    2683             :     typedef std::multimap< int, std::pair<SwTextAttr*, bool> > PortionMap;
    2684       64369 :     PortionMap aPortionMap;
    2685      128738 :     std::map<int, bool> RsidOnlyAutoFormatFlagMap;
    2686       64369 :     sal_Int32 nLastPorStart = COMPLETE_STRING;
    2687       64369 :     int nKey = 0;
    2688             : 
    2689             :     // get portions by start position:
    2690      323629 :     for ( size_t i = 0; i < Count(); ++i )
    2691             :     {
    2692      259260 :         SwTextAttr *pHt = GetTextHint( i );
    2693      490191 :         if ( RES_TXTATR_CHARFMT != pHt->Which() &&
    2694      230931 :              RES_TXTATR_AUTOFMT != pHt->Which() )
    2695             :              //&&
    2696             :              //RES_TXTATR_INETFMT != pHt->Which() )
    2697       71634 :             continue;
    2698             : 
    2699      233429 :         bool isRsidOnlyAutoFormat(false);
    2700             :         // check for RSID-only AUTOFMT
    2701      233429 :         if (RES_TXTATR_AUTOFMT == pHt->Which())
    2702             :         {
    2703             :             std::shared_ptr<SfxItemSet> const pSet(
    2704      205100 :                     pHt->GetAutoFormat().GetStyleHandle());
    2705      205100 :             if ((pSet->Count() == 1) && pSet->GetItem(RES_CHRATR_RSID, false))
    2706             :             {
    2707             :                 // fdo#70201: eliminate no-extent RSID-only AUTOFMT
    2708             :                 // could be produced by ReplaceText or (maybe?) RstAttr
    2709         136 :                 if (pHt->GetStart() == *pHt->GetEnd())
    2710             :                 {
    2711          12 :                     SwpHintsArray::DeleteAtPos(i); // kill it without History!
    2712          12 :                     SwTextAttr::Destroy(pHt, rNode.GetDoc()->GetAttrPool());
    2713          12 :                     --i;
    2714          12 :                     continue;
    2715             :                 }
    2716             :                 // fdo#52028: this one has _only_ RSID => ignore it completely
    2717         124 :                 if (!pHt->IsFormatIgnoreStart() || !pHt->IsFormatIgnoreEnd())
    2718             :                 {
    2719         104 :                     NoteInHistory(pHt);
    2720         104 :                     pHt->SetFormatIgnoreStart(true);
    2721         104 :                     pHt->SetFormatIgnoreEnd  (true);
    2722         104 :                     NoteInHistory(pHt, true);
    2723             :                 }
    2724         124 :                 isRsidOnlyAutoFormat = true;
    2725      205088 :             }
    2726             :         }
    2727             : 
    2728      233417 :         if (pHt->GetStart() == *pHt->GetEnd())
    2729             :         {
    2730             :             // no-length hints are a disease. ignore them here.
    2731             :             // the SwAttrIter::SeekFwd will not call Rst/Chg for them.
    2732       19960 :             continue;
    2733             :         }
    2734             : 
    2735      213457 :         const sal_Int32 nPorStart = pHt->GetStart();
    2736      213457 :         if (nPorStart != nLastPorStart)
    2737      204120 :             ++nKey;
    2738      213457 :         nLastPorStart = nPorStart;
    2739             :         aPortionMap.insert(std::make_pair(nKey,
    2740      213457 :                             std::make_pair(pHt, isRsidOnlyAutoFormat)));
    2741      213457 :         RsidOnlyAutoFormatFlagMap[nKey] = isRsidOnlyAutoFormat;
    2742             :     }
    2743             : 
    2744             :     // check if portion i can be merged with portion i+1:
    2745             :     // note: need to include i=0 to set IgnoreStart and j=nKey+1 to reset
    2746             :     // IgnoreEnd at first / last portion
    2747       64369 :     int i = 0;
    2748       64369 :     int j = i + 1;
    2749      397227 :     while ( i <= nKey )
    2750             :     {
    2751      268489 :         std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
    2752      268489 :         std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
    2753      268489 :         PortionMap::iterator aIter1 = aRange1.first;
    2754      268489 :         PortionMap::iterator aIter2 = aRange2.first;
    2755             : 
    2756      268489 :         enum { MATCH, DIFFER_ONLY_RSID, DIFFER } eMerge(MATCH);
    2757      268489 :         size_t const nAttributesInPor1 = std::distance(aRange1.first, aRange1.second);
    2758      268489 :         size_t const nAttributesInPor2 = std::distance(aRange2.first, aRange2.second);
    2759      268489 :         bool const isRsidOnlyAutoFormat1(RsidOnlyAutoFormatFlagMap[i]);
    2760      268489 :         bool const isRsidOnlyAutoFormat2(RsidOnlyAutoFormatFlagMap[j]);
    2761             : 
    2762             :         // if both have one they could be equal, but not if only one has it
    2763      268489 :         bool const bSkipRsidOnlyAutoFormat(nAttributesInPor1 != nAttributesInPor2);
    2764             : 
    2765             :         // this loop needs to handle the case where one has a CHARFMT and the
    2766             :         // other CHARFMT + RSID-only AUTOFMT, so...
    2767             :         // want to skip over RSID-only AUTOFMT here, hence the -1
    2768      536978 :         if ((nAttributesInPor1 - ((isRsidOnlyAutoFormat1) ? 1 : 0)) ==
    2769      268489 :             (nAttributesInPor2 - ((isRsidOnlyAutoFormat2) ? 1 : 0))
    2770      137231 :             && (nAttributesInPor1 != 0 || nAttributesInPor2 != 0))
    2771             :         {
    2772             :             // _if_ there is one element more either in aRange1 or aRange2
    2773             :             // it _must_ be an RSID-only AUTOFMT, which can be ignored here...
    2774             :             // But if both have RSID-only AUTOFMT they could be equal, no skip!
    2775      280432 :             while (aIter1 != aRange1.second || aIter2 != aRange2.second)
    2776             :             {
    2777             :                 // first of all test if there's no gap (before skipping stuff!)
    2778      266517 :                 if (aIter1 != aRange1.second && aIter2 != aRange2.second &&
    2779      133163 :                     *aIter1->second.first->End() < aIter2->second.first->GetStart())
    2780             :                 {
    2781       10062 :                     eMerge = DIFFER;
    2782       10062 :                     break;
    2783             :                 }
    2784             :                 // skip it - cannot be equal if bSkipRsidOnlyAutoFormat is set
    2785      123292 :                 if (bSkipRsidOnlyAutoFormat
    2786      123292 :                     && aIter1 != aRange1.second && aIter1->second.second)
    2787             :                 {
    2788             :                     assert(DIFFER != eMerge);
    2789          94 :                     eMerge = DIFFER_ONLY_RSID;
    2790          94 :                     ++aIter1;
    2791          94 :                     continue;
    2792             :                 }
    2793      123198 :                 if (bSkipRsidOnlyAutoFormat
    2794      123198 :                     && aIter2 != aRange2.second && aIter2->second.second)
    2795             :                 {
    2796             :                     assert(DIFFER != eMerge);
    2797          97 :                     eMerge = DIFFER_ONLY_RSID;
    2798          97 :                     ++aIter2;
    2799          97 :                     continue;
    2800             :                 }
    2801             :                 assert(aIter1 != aRange1.second && aIter2 != aRange2.second);
    2802      123101 :                 SwTextAttr const*const p1 = aIter1->second.first;
    2803      123101 :                 SwTextAttr const*const p2 = aIter2->second.first;
    2804      123101 :                 if (p1->Which() != p2->Which())
    2805             :                 {
    2806        4430 :                     eMerge = DIFFER;
    2807        4430 :                     break;
    2808             :                 }
    2809      118671 :                 if (!(*p1 == *p2))
    2810             :                 {
    2811             :                     // fdo#52028: for auto styles, check if they differ only
    2812             :                     // in the RSID, which should have no effect on text layout
    2813      104285 :                     if (RES_TXTATR_AUTOFMT == p1->Which())
    2814             :                     {
    2815       99870 :                         SfxItemSet set1(*p1->GetAutoFormat().GetStyleHandle());
    2816       99871 :                         SfxItemSet set2(*p2->GetAutoFormat().GetStyleHandle());
    2817             : 
    2818       99870 :                         set1.ClearItem(RES_CHRATR_RSID);
    2819       99870 :                         set2.ClearItem(RES_CHRATR_RSID);
    2820             : 
    2821             :                         // sadly SfxItemSet::operator== does not seem to work?
    2822       99871 :                         SfxItemIter iter1(set1);
    2823       99871 :                         SfxItemIter iter2(set2);
    2824       99870 :                         if (set1.Count() == set2.Count())
    2825             :                         {
    2826       34476 :                             for (SfxPoolItem const* pItem1 = iter1.FirstItem(),
    2827       11092 :                                                   * pItem2 = iter2.FirstItem();
    2828       23383 :                                  pItem1 && pItem2;
    2829             :                                  pItem1 = iter1.NextItem(),
    2830             :                                  pItem2 = iter2.NextItem())
    2831             :                             {
    2832       35675 :                                 if (pItem1 != pItem2 ||
    2833       35675 :                                     pItem1->Which() != pItem2->Which() ||
    2834       12292 :                                     *pItem1 != *pItem2)
    2835             :                                 {
    2836       11091 :                                     eMerge = DIFFER;
    2837       11091 :                                     break;
    2838             :                                 }
    2839       12292 :                                 if (iter1.IsAtEnd())
    2840             :                                 {
    2841             :                                     assert(iter2.IsAtEnd());
    2842           0 :                                     eMerge = DIFFER_ONLY_RSID;
    2843             :                                 }
    2844             :                             }
    2845       11092 :                             if (DIFFER == eMerge)
    2846       11091 :                                 break; // outer loop too
    2847             :                         }
    2848             :                         else
    2849             :                         {
    2850       88778 :                             eMerge = DIFFER;
    2851       88778 :                             break;
    2852           1 :                         }
    2853             :                     }
    2854             :                     else
    2855             :                     {
    2856        4415 :                         eMerge = DIFFER;
    2857        4415 :                         break;
    2858             :                     }
    2859             :                 }
    2860       14387 :                 ++aIter1;
    2861       14387 :                 ++aIter2;
    2862      132927 :             }
    2863             :         }
    2864             :         else
    2865             :         {
    2866      135562 :             eMerge = DIFFER;
    2867             :         }
    2868             : 
    2869      268489 :         if (MATCH == eMerge)
    2870             :         {
    2871             :             // important: delete second range so any IgnoreStart on the first
    2872             :             // range is still valid
    2873             :             // erase all elements with key i + 1
    2874       13960 :             sal_Int32 nNewPortionEnd = 0;
    2875       28163 :             for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
    2876             :             {
    2877       14203 :                 SwTextAttr *const p2 = aIter2->second.first;
    2878       14203 :                 nNewPortionEnd = *p2->GetEnd();
    2879             : 
    2880       14203 :                 const size_t nCountBeforeDelete = Count();
    2881       14203 :                 Delete( p2 );
    2882             : 
    2883             :                 // robust: check if deletion actually took place before destroying attribute:
    2884       14203 :                 if ( Count() < nCountBeforeDelete )
    2885       14203 :                     rNode.DestroyAttr( p2 );
    2886             :             }
    2887       13960 :             aPortionMap.erase( aRange2.first, aRange2.second );
    2888       13960 :             ++j;
    2889             : 
    2890             :             // change all attributes with key i
    2891       13960 :             aRange1 = aPortionMap.equal_range( i );
    2892       28163 :             for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
    2893             :             {
    2894       14203 :                 SwTextAttr *const p1 = aIter1->second.first;
    2895       14203 :                 NoteInHistory( p1 );
    2896       14203 :                 *p1->GetEnd() = nNewPortionEnd;
    2897       14203 :                 NoteInHistory( p1, true );
    2898       14203 :                 bRet = true;
    2899             :             }
    2900             : 
    2901       13960 :             if (bRet)
    2902             :             {
    2903       13960 :                 SwpHintsArray::Resort();
    2904             :             }
    2905             :         }
    2906             :         else
    2907             :         {
    2908             :             // when not merging the ignore flags need to be either set or reset
    2909             :             // (reset too in case one of the autofmts was recently changed)
    2910      254529 :             bool const bSetIgnoreFlag(DIFFER_ONLY_RSID == eMerge);
    2911      453783 :             for (aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1)
    2912             :             {
    2913      199254 :                 if (!aIter1->second.second) // already set above, don't change
    2914             :                 {
    2915      199146 :                     SwTextAttr *const pCurrent(aIter1->second.first);
    2916      199146 :                     if (pCurrent->IsFormatIgnoreEnd() != bSetIgnoreFlag)
    2917             :                     {
    2918           0 :                         NoteInHistory(pCurrent);
    2919           0 :                         pCurrent->SetFormatIgnoreEnd(bSetIgnoreFlag);
    2920           0 :                         NoteInHistory(pCurrent, true);
    2921             :                     }
    2922             :                 }
    2923             :             }
    2924      453783 :             for (aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2)
    2925             :             {
    2926      199254 :                 if (!aIter2->second.second) // already set above, don't change
    2927             :                 {
    2928      199146 :                     SwTextAttr *const pCurrent(aIter2->second.first);
    2929      199146 :                     if (pCurrent->IsFormatIgnoreStart() != bSetIgnoreFlag)
    2930             :                     {
    2931           0 :                         NoteInHistory(pCurrent);
    2932           0 :                         pCurrent->SetFormatIgnoreStart(bSetIgnoreFlag);
    2933           0 :                         NoteInHistory(pCurrent, true);
    2934             :                     }
    2935             :                 }
    2936             :             }
    2937      254529 :             i = j; // ++i not enough: i + 1 may have been deleted (MATCH)!
    2938      254529 :             ++j;
    2939             :         }
    2940             :     }
    2941             : 
    2942      128738 :     return bRet;
    2943             : }
    2944             : 
    2945             : // check if there is already a character format and adjust the sort numbers
    2946           2 : static void lcl_CheckSortNumber( const SwpHints& rHints, SwTextCharFormat& rNewCharFormat )
    2947             : {
    2948           2 :     const sal_Int32 nHtStart = rNewCharFormat.GetStart();
    2949           2 :     const sal_Int32 nHtEnd   = *rNewCharFormat.GetEnd();
    2950           2 :     sal_uInt16 nSortNumber = 0;
    2951             : 
    2952           2 :     for ( size_t i = 0; i < rHints.Count(); ++i )
    2953             :     {
    2954           0 :         const SwTextAttr* pOtherHt = rHints[i];
    2955             : 
    2956           0 :         const sal_Int32 nOtherStart = pOtherHt->GetStart();
    2957             : 
    2958           0 :         if ( nOtherStart > nHtStart )
    2959           0 :             break;
    2960             : 
    2961           0 :         if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
    2962             :         {
    2963           0 :             const sal_Int32 nOtherEnd = *pOtherHt->End();
    2964             : 
    2965           0 :             if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
    2966             :             {
    2967           0 :                 nSortNumber = static_txtattr_cast<const SwTextCharFormat*>(pOtherHt)->GetSortNumber() + 1;
    2968             :             }
    2969             :         }
    2970             :     }
    2971             : 
    2972           2 :     if ( nSortNumber > 0 )
    2973           0 :         rNewCharFormat.SetSortNumber( nSortNumber );
    2974           2 : }
    2975             : 
    2976             : /*
    2977             :  * Try to insert the new hint.
    2978             :  * Depending on the type of the hint, this either always succeeds, or may fail.
    2979             :  * Depending on the type of the hint, other hints may be deleted or
    2980             :  * overwritten.
    2981             :  * The return value indicates successful insertion.
    2982             :  */
    2983       82501 : bool SwpHints::TryInsertHint(
    2984             :     SwTextAttr* const pHint,
    2985             :     SwTextNode &rNode,
    2986             :     const SetAttrMode nMode )
    2987             : {
    2988       82501 :     if ( MAX_HINTS <= Count() ) // we're sorry, this flight is overbooked...
    2989             :     {
    2990             :         OSL_FAIL("hints array full :-(");
    2991           0 :         return false;
    2992             :     }
    2993             : 
    2994             :     // Felder bilden eine Ausnahme:
    2995             :     // 1) Sie koennen nie ueberlappen
    2996             :     // 2) Wenn zwei Felder genau aneinander liegen,
    2997             :     //    sollen sie nicht zu einem verschmolzen werden.
    2998             :     // Wir koennen also auf die while-Schleife verzichten
    2999             : 
    3000       82501 :     sal_Int32 *pHtEnd = pHint->GetEnd();
    3001       82501 :     const sal_uInt16 nWhich = pHint->Which();
    3002       82501 :     std::vector<sal_uInt16> aWhichSublist;
    3003             : 
    3004       82501 :     switch( nWhich )
    3005             :     {
    3006             :     case RES_TXTATR_CHARFMT:
    3007             :     {
    3008             :         // Check if character format contains hidden attribute:
    3009        6244 :         const SwCharFormat* pFormat = pHint->GetCharFormat().GetCharFormat();
    3010             :         const SfxPoolItem* pItem;
    3011        6244 :         if ( SfxItemState::SET == pFormat->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
    3012           0 :             rNode.SetCalcHiddenCharFlags();
    3013             : 
    3014        6244 :         static_txtattr_cast<SwTextCharFormat*>(pHint)->ChgTextNode( &rNode );
    3015        6244 :         break;
    3016             :     }
    3017             :     // #i75430# Recalc hidden flags if necessary
    3018             :     case RES_TXTATR_AUTOFMT:
    3019             :     {
    3020       68165 :         std::shared_ptr<SfxItemSet> const pSet( pHint->GetAutoFormat().GetStyleHandle() );
    3021       68165 :         if (pHint->GetStart() == *pHint->GetEnd())
    3022             :         {
    3023       25692 :             if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
    3024             :             {   // empty range RSID-only hints could cause trouble, there's no
    3025           0 :                 rNode.DestroyAttr(pHint); // need for them so don't insert
    3026           0 :                 return false;
    3027             :             }
    3028             :         }
    3029             :         // Check if auto style contains hidden attribute:
    3030       68165 :         const SfxPoolItem* pHiddenItem = CharFormat::GetItem( *pHint, RES_CHRATR_HIDDEN );
    3031       68165 :         if ( pHiddenItem )
    3032         867 :             rNode.SetCalcHiddenCharFlags();
    3033             : 
    3034             :         // fdo#71556: populate aWhichFormatAttr member of SwMsgPoolItem
    3035       68165 :         const sal_uInt16 *pRanges = pSet->GetRanges();
    3036      340708 :         while( (*pRanges) != 0 )
    3037             :         {
    3038      204378 :             const sal_uInt16 nBeg = (*pRanges);
    3039      204378 :             ++pRanges;
    3040      204378 :             const sal_uInt16 nEnd = (*pRanges);
    3041      204378 :             ++pRanges;
    3042     3408016 :             for( sal_uInt16 nSubElem = nBeg; nSubElem <= nEnd; ++nSubElem )
    3043     3203638 :                 if( pSet->HasItem( nSubElem ) )
    3044      240294 :                     aWhichSublist.push_back( nSubElem );
    3045             :         }
    3046       68165 :         break;
    3047             :     }
    3048             :     case RES_TXTATR_INETFMT:
    3049        1798 :         static_txtattr_cast<SwTextINetFormat*>(pHint)->InitINetFormat(rNode);
    3050        1798 :         break;
    3051             : 
    3052             :     case RES_TXTATR_FIELD:
    3053             :     case RES_TXTATR_ANNOTATION:
    3054             :     case RES_TXTATR_INPUTFIELD:
    3055             :         {
    3056        2043 :             SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
    3057        2043 :             bool bDelFirst = 0 != pTextField->GetpTextNode();
    3058        2043 :             pTextField->ChgTextNode( &rNode );
    3059        2043 :             SwDoc* pDoc = rNode.GetDoc();
    3060        2043 :             const SwField* pField = pTextField->GetFormatField().GetField();
    3061             : 
    3062        2043 :             if( !pDoc->getIDocumentFieldsAccess().IsNewFieldLst() )
    3063             :             {
    3064             :                 // was fuer ein Feld ist es denn ??
    3065             :                 // bestimmte Felder mussen am Doc das Calculations-Flag updaten
    3066          15 :                 switch( pField->GetTyp()->Which() )
    3067             :                 {
    3068             :                 case RES_DBFLD:
    3069             :                 case RES_SETEXPFLD:
    3070             :                 case RES_HIDDENPARAFLD:
    3071             :                 case RES_HIDDENTXTFLD:
    3072             :                 case RES_DBNUMSETFLD:
    3073             :                 case RES_DBNEXTSETFLD:
    3074             :                     {
    3075           0 :                         if( bDelFirst )
    3076           0 :                             pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(false, *pTextField);
    3077           0 :                         if( rNode.GetNodes().IsDocNodes() )
    3078           0 :                             pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(true, *pTextField);
    3079             :                     }
    3080           0 :                     break;
    3081             :                 case RES_DDEFLD:
    3082           0 :                     if( rNode.GetNodes().IsDocNodes() )
    3083           0 :                         static_cast<SwDDEFieldType*>(pField->GetTyp())->IncRefCnt();
    3084           0 :                     break;
    3085             :                 }
    3086             :             }
    3087             : 
    3088             :             // gehts ins normale Nodes-Array?
    3089        2043 :             if( rNode.GetNodes().IsDocNodes() )
    3090             :             {
    3091        2043 :                 bool bInsFieldType = false;
    3092        2043 :                 switch( pField->GetTyp()->Which() )
    3093             :                 {
    3094             :                 case RES_SETEXPFLD:
    3095          63 :                     bInsFieldType = static_cast<SwSetExpFieldType*>(pField->GetTyp())->IsDeleted();
    3096          63 :                     if( nsSwGetSetExpType::GSE_SEQ & static_cast<SwSetExpFieldType*>(pField->GetTyp())->GetType() )
    3097             :                     {
    3098             :                         // bevor die ReferenzNummer gesetzt wird, sollte
    3099             :                         // das Feld am richtigen FeldTypen haengen!
    3100             :                         SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(
    3101          54 :                                     pDoc->getIDocumentFieldsAccess().InsertFieldType( *pField->GetTyp() ) );
    3102          54 :                         if( pFieldType != pField->GetTyp() )
    3103             :                         {
    3104           0 :                             SwFormatField* pFormatField = const_cast<SwFormatField*>(&pTextField->GetFormatField());
    3105           0 :                             pFormatField->RegisterToFieldType( *pFieldType );
    3106           0 :                             pFormatField->GetField()->ChgTyp( pFieldType );
    3107             :                         }
    3108          54 :                         pFieldType->SetSeqRefNo( *const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField)) );
    3109             :                     }
    3110          63 :                     break;
    3111             :                 case RES_USERFLD:
    3112           2 :                     bInsFieldType = static_cast<SwUserFieldType*>(pField->GetTyp())->IsDeleted();
    3113           2 :                     break;
    3114             : 
    3115             :                 case RES_DDEFLD:
    3116           0 :                     if( pDoc->getIDocumentFieldsAccess().IsNewFieldLst() )
    3117           0 :                         static_cast<SwDDEFieldType*>(pField->GetTyp())->IncRefCnt();
    3118           0 :                     bInsFieldType = static_cast<SwDDEFieldType*>(pField->GetTyp())->IsDeleted();
    3119           0 :                     break;
    3120             : 
    3121             :                 case RES_POSTITFLD:
    3122         140 :                     if ( pDoc->GetDocShell() )
    3123             :                     {
    3124         140 :                         pDoc->GetDocShell()->Broadcast( SwFormatFieldHint(
    3125         280 :                             &pTextField->GetFormatField(), SwFormatFieldHintWhich::INSERTED));
    3126             :                     }
    3127         140 :                     break;
    3128             :                 }
    3129        2043 :                 if( bInsFieldType )
    3130           0 :                     pDoc->getIDocumentFieldsAccess().InsDeletedFieldType( *pField->GetTyp() );
    3131             :             }
    3132             :         }
    3133        2043 :         break;
    3134             :     case RES_TXTATR_FTN :
    3135         140 :         static_cast<SwTextFootnote*>(pHint)->ChgTextNode( &rNode );
    3136         140 :         break;
    3137             :     case RES_TXTATR_REFMARK:
    3138          39 :         static_txtattr_cast<SwTextRefMark*>(pHint)->ChgTextNode( &rNode );
    3139          39 :         if( rNode.GetNodes().IsDocNodes() )
    3140             :         {
    3141             :             // search for a reference with the same name
    3142             :             SwTextAttr* pTmpHt;
    3143             :             sal_Int32 *pTmpHtEnd;
    3144             :             sal_Int32 *pTmpHintEnd;
    3145          94 :             for( size_t n = 0, nEnd = Count(); n < nEnd; ++n )
    3146             :             {
    3147         198 :                 if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
    3148          33 :                     pHint->GetAttr() == pTmpHt->GetAttr() &&
    3149         110 :                     0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
    3150           0 :                     0 != ( pTmpHintEnd = pHint->GetEnd() ) )
    3151             :                 {
    3152             :                     SwComparePosition eCmp = ::ComparePosition(
    3153           0 :                             pTmpHt->GetStart(), *pTmpHtEnd,
    3154           0 :                             pHint->GetStart(), *pTmpHintEnd );
    3155           0 :                     bool bDelOld = true, bChgStart = false, bChgEnd = false;
    3156           0 :                     switch( eCmp )
    3157             :                     {
    3158             :                     case POS_BEFORE:
    3159           0 :                     case POS_BEHIND:    bDelOld = false; break;
    3160             : 
    3161           0 :                     case POS_OUTSIDE:   bChgStart = bChgEnd = true; break;
    3162             : 
    3163             :                     case POS_COLLIDE_END:
    3164           0 :                     case POS_OVERLAP_BEFORE:    bChgStart = true; break;
    3165             :                     case POS_COLLIDE_START:
    3166           0 :                     case POS_OVERLAP_BEHIND:    bChgEnd = true; break;
    3167           0 :                     default: break;
    3168             :                     }
    3169             : 
    3170           0 :                     if( bChgStart )
    3171           0 :                         pHint->GetStart() = pTmpHt->GetStart();
    3172           0 :                     if( bChgEnd )
    3173           0 :                         *pTmpHintEnd = *pTmpHtEnd;
    3174             : 
    3175           0 :                     if( bDelOld )
    3176             :                     {
    3177           0 :                         NoteInHistory( pTmpHt );
    3178           0 :                         rNode.DestroyAttr( Cut( n-- ) );
    3179           0 :                         --nEnd;
    3180             :                     }
    3181             :                 }
    3182             :             }
    3183             :         }
    3184          39 :         break;
    3185             :     case RES_TXTATR_TOXMARK:
    3186         173 :         static_txtattr_cast<SwTextTOXMark*>(pHint)->ChgTextNode( &rNode );
    3187         173 :         break;
    3188             : 
    3189             :     case RES_TXTATR_CJK_RUBY:
    3190         149 :         static_txtattr_cast<SwTextRuby*>(pHint)->InitRuby(rNode);
    3191         149 :         break;
    3192             : 
    3193             :     case RES_TXTATR_META:
    3194             :     case RES_TXTATR_METAFIELD:
    3195          97 :         static_txtattr_cast<SwTextMeta *>(pHint)->ChgTextNode( &rNode );
    3196          97 :         break;
    3197             : 
    3198             :     case RES_CHRATR_HIDDEN:
    3199           0 :         rNode.SetCalcHiddenCharFlags();
    3200           0 :         break;
    3201             :     }
    3202             : 
    3203       82501 :     if( SetAttrMode::DONTEXPAND & nMode )
    3204         310 :         pHint->SetDontExpand( true );
    3205             : 
    3206             :     // SwTextAttrs ohne Ende werden sonderbehandelt:
    3207             :     // Sie werden natuerlich in das Array insertet, aber sie werden nicht
    3208             :     // in die pPrev/Next/On/Off-Verkettung aufgenommen.
    3209             :     // Der Formatierer erkennt diese TextHints an dem CH_TXTATR_.. im Text !
    3210       82501 :     sal_Int32 nHtStart = pHint->GetStart();
    3211       82501 :     if( !pHtEnd )
    3212             :     {
    3213        6002 :         SwpHintsArray::Insert( pHint );
    3214        6002 :         CalcFlags();
    3215             : #ifdef DBG_UTIL
    3216             :         if( !rNode.GetDoc()->IsInReading() )
    3217             :             CHECK;
    3218             : #endif
    3219             :         // ... und die Abhaengigen benachrichtigen
    3220        6002 :         if(rNode.HasWriterListeners())
    3221             :         {
    3222             :             SwUpdateAttr aHint(
    3223             :                 nHtStart,
    3224             :                 nHtStart,
    3225        1977 :                 nWhich);
    3226             : 
    3227        1977 :             rNode.ModifyNotification(0,&aHint);
    3228             :         }
    3229             : 
    3230        6002 :         return true;
    3231             :     }
    3232             : 
    3233             :     // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
    3234             : 
    3235       76499 :     if( *pHtEnd < nHtStart )
    3236             :     {
    3237             :         OSL_ENSURE( *pHtEnd >= nHtStart,
    3238             :                     "+SwpHints::Insert: invalid hint, end < start" );
    3239             : 
    3240             :         // Wir drehen den Quatsch einfach um:
    3241           3 :         pHint->GetStart() = *pHtEnd;
    3242           3 :         *pHtEnd = nHtStart;
    3243           3 :         nHtStart = pHint->GetStart();
    3244             :     }
    3245             : 
    3246             :     // I need this value later on for notification but the pointer may become invalid
    3247       76499 :     const sal_Int32 nHintEnd = *pHtEnd;
    3248       76499 :     const bool bNoHintAdjustMode = bool(SetAttrMode::NOHINTADJUST & nMode);
    3249             : 
    3250             :     // handle nesting attributes: inserting may fail due to overlap!
    3251       76499 :     if (pHint->IsNesting())
    3252             :     {
    3253             :         const bool bRet(
    3254        2062 :             TryInsertNesting(rNode, *static_txtattr_cast<SwTextAttrNesting*>(pHint)));
    3255        2062 :         if (!bRet) return false;
    3256             :     }
    3257             :     // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
    3258             :     // These attributes may be inserted directly.
    3259             :     // Also attributes without length may be inserted directly.
    3260             :     // SETATTR_NOHINTADJUST is set e.g., during undo.
    3261             :     // Portion building in not necessary during XML import.
    3262      221819 :     else if ( !bNoHintAdjustMode &&
    3263      145862 :          !pHint->IsOverlapAllowedAttr() &&
    3264      292236 :          !rNode.GetDoc()->IsInXMLImport() &&
    3265        6184 :          ( RES_TXTATR_AUTOFMT == nWhich ||
    3266             :            RES_TXTATR_CHARFMT == nWhich ) )
    3267             :     {
    3268             :         OSL_ENSURE( nWhich != RES_TXTATR_AUTOFMT ||
    3269             :                 static_cast<const SwFormatAutoFormat&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
    3270             :                 &rNode.GetDoc()->GetAttrPool(),
    3271             :                 "AUTOSTYLES - Pool mismatch" );
    3272             : 
    3273       72441 :         BuildPortions( rNode, *pHint, nMode );
    3274             : 
    3275       72441 :         if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
    3276       46161 :             MergePortions( rNode );
    3277             :     }
    3278             :     else
    3279             :     {
    3280             :         // There may be more than one character style at the current position.
    3281             :         // Take care of the sort number.
    3282             :         // Special case ruby portion: During import, the ruby attribute is set
    3283             :         // multiple times
    3284             :         // Special case hyperlink: During import, the ruby attribute is set
    3285             :         // multiple times
    3286             :         // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
    3287             :         // character attributes directly
    3288        1996 :         if ( ( RES_TXTATR_CHARFMT  == nWhich && !bNoHintAdjustMode ) )
    3289             :         {
    3290          58 :             BuildPortions( rNode, *pHint, nMode );
    3291             :         }
    3292             :         else
    3293             :         {
    3294             :             // #i82989# Check sort numbers in NoHintAdjustMode
    3295        1938 :             if ( RES_TXTATR_CHARFMT == nWhich )
    3296           2 :                 lcl_CheckSortNumber(*this, *static_txtattr_cast<SwTextCharFormat*>(pHint));
    3297             : 
    3298        1938 :             SwpHintsArray::Insert( pHint );
    3299        1938 :             NoteInHistory( pHint, true );
    3300             :         }
    3301             :     }
    3302             : 
    3303             :     // ... und die Abhaengigen benachrichtigen
    3304       76497 :     if ( rNode.HasWriterListeners() )
    3305             :     {
    3306             :         SwUpdateAttr aHint(
    3307             :             nHtStart,
    3308             :             nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd,
    3309       60635 :             nWhich);
    3310             : 
    3311       60635 :         rNode.ModifyNotification( 0, &aHint );
    3312             :     }
    3313             : 
    3314             : #ifdef DBG_UTIL
    3315             :     if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
    3316             :         CHECK;
    3317             : #endif
    3318             : 
    3319       76497 :     return true;
    3320             : }
    3321             : 
    3322       45229 : void SwpHints::DeleteAtPos( const size_t nPos )
    3323             : {
    3324       45229 :     SwTextAttr *pHint = GetTextHint(nPos);
    3325             :     // ChainDelete( pHint );
    3326       45229 :     NoteInHistory( pHint );
    3327       45229 :     SwpHintsArray::DeleteAtPos( nPos );
    3328             : 
    3329       45229 :     if( pHint->Which() == RES_TXTATR_FIELD )
    3330             :     {
    3331          86 :         SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
    3332          86 :         const SwFieldType* pFieldTyp = pTextField->GetFormatField().GetField()->GetTyp();
    3333          86 :         if( RES_DDEFLD == pFieldTyp->Which() )
    3334             :         {
    3335           0 :             const SwTextNode* pNd = pTextField->GetpTextNode();
    3336           0 :             if( pNd && pNd->GetNodes().IsDocNodes() )
    3337           0 :                 const_cast<SwDDEFieldType*>(static_cast<const SwDDEFieldType*>(pFieldTyp))->DecRefCnt();
    3338           0 :             pTextField->ChgTextNode(0);
    3339             :         }
    3340          86 :         else if ( m_bHasHiddenParaField &&
    3341           0 :                  RES_HIDDENPARAFLD == pFieldTyp->Which() )
    3342             :         {
    3343           0 :             m_bCalcHiddenParaField = true;
    3344             :         }
    3345             :     }
    3346       45143 :     else if ( pHint->Which() == RES_TXTATR_ANNOTATION )
    3347             :     {
    3348          19 :         SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
    3349          19 :         const_cast<SwFormatField&>(pTextField->GetFormatField()).Broadcast(
    3350          38 :             SwFormatFieldHint(&pTextField->GetFormatField(), SwFormatFieldHintWhich::REMOVED));
    3351             :     }
    3352             : 
    3353       45229 :     CalcFlags();
    3354             :     CHECK_NOTMERGED; // called from BuildPortions
    3355       45229 : }
    3356             : 
    3357             : // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
    3358             : // Ist er nicht im Array, so gibt es ein OSL_ENSURE(!!
    3359             : 
    3360       41267 : void SwpHints::Delete( SwTextAttr* pTextHt )
    3361             : {
    3362             :     // Attr 2.0: SwpHintsArr::Delete( pTextHt );
    3363       41267 :     const size_t nPos = GetStartOf( pTextHt );
    3364             :     OSL_ENSURE( SAL_MAX_SIZE != nPos, "Attribut nicht im Attribut-Array!" );
    3365       41267 :     if( SAL_MAX_SIZE != nPos )
    3366       41267 :         DeleteAtPos( nPos );
    3367       41267 : }
    3368             : 
    3369           0 : void SwTextNode::ClearSwpHintsArr( bool bDelFields )
    3370             : {
    3371           0 :     if ( HasHints() )
    3372             :     {
    3373           0 :         size_t nPos = 0;
    3374           0 :         while ( nPos < m_pSwpHints->Count() )
    3375             :         {
    3376           0 :             SwTextAttr* pDel = m_pSwpHints->GetTextHint( nPos );
    3377           0 :             bool bDel = false;
    3378             : 
    3379           0 :             switch( pDel->Which() )
    3380             :             {
    3381             :             case RES_TXTATR_FLYCNT:
    3382             :             case RES_TXTATR_FTN:
    3383           0 :                 break;
    3384             : 
    3385             :             case RES_TXTATR_FIELD:
    3386             :             case RES_TXTATR_ANNOTATION:
    3387             :             case RES_TXTATR_INPUTFIELD:
    3388           0 :                 if( bDelFields )
    3389           0 :                     bDel = true;
    3390           0 :                 break;
    3391             :             default:
    3392           0 :                 bDel = true; break;
    3393             :             }
    3394             : 
    3395           0 :             if( bDel )
    3396             :             {
    3397           0 :                 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
    3398           0 :                 DestroyAttr( pDel );
    3399             :             }
    3400             :             else
    3401           0 :                 ++nPos;
    3402             :         }
    3403             :     }
    3404           0 : }
    3405             : 
    3406   188511903 : sal_uInt16 SwTextNode::GetLang( const sal_Int32 nBegin, const sal_Int32 nLen,
    3407             :                            sal_uInt16 nScript ) const
    3408             : {
    3409   188511903 :     sal_uInt16 nRet = LANGUAGE_DONTKNOW;
    3410             : 
    3411   188511903 :     if ( ! nScript )
    3412             :     {
    3413    97176669 :         nScript = g_pBreakIt->GetRealScriptOfText( m_Text, nBegin );
    3414             :     }
    3415             : 
    3416             :     // #i91465# Consider nScript if pSwpHints == 0
    3417   188511903 :     const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
    3418             : 
    3419   188511903 :     if ( HasHints() )
    3420             :     {
    3421    29534994 :         const sal_Int32 nEnd = nBegin + nLen;
    3422    29534994 :         const size_t nSize = m_pSwpHints->Count();
    3423    50648505 :         for ( size_t i = 0; i < nSize; ++i )
    3424             :         {
    3425             :             // ist der Attribut-Anfang schon groesser als der Idx ?
    3426    32568406 :             const SwTextAttr *pHt = m_pSwpHints->operator[](i);
    3427    32568406 :             const sal_Int32 nAttrStart = pHt->GetStart();
    3428    32568406 :             if( nEnd < nAttrStart )
    3429    11454895 :                 break;
    3430             : 
    3431    21113511 :             const sal_uInt16 nWhich = pHt->Which();
    3432             : 
    3433    42232674 :             if( nWhichId == nWhich ||
    3434    42219816 :                     ( ( pHt->IsCharFormatAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFormat::IsItemIncluded( nWhichId, pHt ) ) )
    3435             :             {
    3436        5652 :                 const sal_Int32 *pEndIdx = pHt->End();
    3437             :                 // Ueberlappt das Attribut den Bereich?
    3438             : 
    3439        5652 :                 if( !pEndIdx )
    3440           0 :                     continue;
    3441        5652 :                 if( nLen )
    3442             :                 {
    3443         177 :                     if( nAttrStart >= nEnd || nBegin >= *pEndIdx )
    3444          47 :                         continue;
    3445             :                 }
    3446        5475 :                 else if( nBegin != nAttrStart || ( nAttrStart != *pEndIdx && nBegin ))
    3447             :                 {
    3448        4116 :                     if( nAttrStart >= nBegin )
    3449          63 :                         continue;
    3450        4053 :                     if( pHt->DontExpand() ? nBegin >= *pEndIdx : nBegin > *pEndIdx)
    3451        1869 :                         continue;
    3452             :                 }
    3453        3673 :                 const SfxPoolItem* pItem = CharFormat::GetItem( *pHt, nWhichId );
    3454        3673 :                 const sal_uInt16 nLng = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
    3455             : 
    3456             :                 // Umfasst das Attribut den Bereich komplett?
    3457        3673 :                 if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
    3458        3673 :                     nRet = nLng;
    3459           0 :                 else if( LANGUAGE_DONTKNOW == nRet )
    3460           0 :                     nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
    3461             :             }
    3462             :         }
    3463             :     }
    3464   188511903 :     if( LANGUAGE_DONTKNOW == nRet )
    3465             :     {
    3466   188509315 :         nRet = static_cast<const SvxLanguageItem&>(GetSwAttrSet().Get( nWhichId )).GetLanguage();
    3467   188509315 :         if( LANGUAGE_DONTKNOW == nRet )
    3468        1115 :             nRet = static_cast<sal_uInt16>(GetAppLanguage());
    3469             :     }
    3470   188511903 :     return nRet;
    3471             : }
    3472             : 
    3473        5151 : sal_Unicode GetCharOfTextAttr( const SwTextAttr& rAttr )
    3474             : {
    3475        5151 :     sal_Unicode cRet = CH_TXTATR_BREAKWORD;
    3476        5151 :     switch ( rAttr.Which() )
    3477             :     {
    3478             :         case RES_TXTATR_REFMARK:
    3479             :         case RES_TXTATR_TOXMARK:
    3480         184 :             cRet = CH_TXTATR_INWORD;
    3481         184 :         break;
    3482             : 
    3483             :         case RES_TXTATR_FIELD:
    3484             :         case RES_TXTATR_FLYCNT:
    3485             :         case RES_TXTATR_FTN:
    3486             :         case RES_TXTATR_META:
    3487             :         case RES_TXTATR_METAFIELD:
    3488             :         case RES_TXTATR_ANNOTATION:
    3489             :         {
    3490        4967 :             cRet = CH_TXTATR_BREAKWORD;
    3491             :         }
    3492        4967 :         break;
    3493             : 
    3494             :         default:
    3495             :             OSL_FAIL("GetCharOfTextAttr: unknown attr");
    3496           0 :             break;
    3497             :     }
    3498        5151 :     return cRet;
    3499         177 : }
    3500             : 
    3501             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11