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

Generated by: LCOV version 1.10