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

Generated by: LCOV version 1.10