LCOV - code coverage report
Current view: top level - editeng/source/editeng - editdoc.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1133 1396 81.2 %
Date: 2015-06-13 12:38:46 Functions: 167 197 84.8 %
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 <comphelper/string.hxx>
      21             : #include <vcl/wrkwin.hxx>
      22             : #include <vcl/dialog.hxx>
      23             : #include <vcl/msgbox.hxx>
      24             : #include <vcl/svapp.hxx>
      25             : 
      26             : #include <editeng/tstpitem.hxx>
      27             : #include <editeng/colritem.hxx>
      28             : #include <editeng/fontitem.hxx>
      29             : #include <editeng/crossedoutitem.hxx>
      30             : #include <editeng/fhgtitem.hxx>
      31             : #include <editeng/flditem.hxx>
      32             : #include <editeng/postitem.hxx>
      33             : #include <editeng/kernitem.hxx>
      34             : #include <editeng/wrlmitem.hxx>
      35             : #include <editeng/wghtitem.hxx>
      36             : #include <editeng/udlnitem.hxx>
      37             : #include <editeng/cmapitem.hxx>
      38             : #include <editeng/contouritem.hxx>
      39             : #include <editeng/escapementitem.hxx>
      40             : #include <editeng/shdditem.hxx>
      41             : #include <editeng/autokernitem.hxx>
      42             : #include <editeng/charsetcoloritem.hxx>
      43             : #include <editeng/langitem.hxx>
      44             : #include <editeng/emphasismarkitem.hxx>
      45             : #include <editeng/charscaleitem.hxx>
      46             : #include <editeng/charreliefitem.hxx>
      47             : #include <editeng/xmlcnitm.hxx>
      48             : #include <editeng/editids.hrc>
      49             : #include "editeng/editdata.hxx"
      50             : #include "editeng/lrspitem.hxx"
      51             : #include "editeng/ulspitem.hxx"
      52             : #include "editeng/lspcitem.hxx"
      53             : 
      54             : #include <editdoc.hxx>
      55             : #include <editdbg.hxx>
      56             : #include <editeng/eerdll.hxx>
      57             : #include <eerdll2.hxx>
      58             : #include <impedit.hxx>
      59             : 
      60             : #include <rtl/ustrbuf.hxx>
      61             : 
      62             : #include <svl/grabbagitem.hxx>
      63             : #include <tools/stream.hxx>
      64             : #include <tools/debug.hxx>
      65             : #include <com/sun/star/i18n/ScriptType.hpp>
      66             : 
      67             : #include <cassert>
      68             : #include <limits>
      69             : 
      70             : #include <boost/bind.hpp>
      71             : 
      72             : using namespace ::com::sun::star;
      73             : 
      74             : 
      75             : 
      76             : 
      77     5349494 : sal_uInt16 GetScriptItemId( sal_uInt16 nItemId, SvtScriptType nScriptType )
      78             : {
      79     5349494 :     sal_uInt16 nId = nItemId;
      80             : 
      81     5349494 :     if ( ( nScriptType == SvtScriptType::ASIAN ) ||
      82             :          ( nScriptType == SvtScriptType::COMPLEX ) )
      83             :     {
      84           0 :         switch ( nItemId )
      85             :         {
      86             :             case EE_CHAR_LANGUAGE:
      87           0 :                 nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL;
      88           0 :             break;
      89             :             case EE_CHAR_FONTINFO:
      90           0 :                 nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL;
      91           0 :             break;
      92             :             case EE_CHAR_FONTHEIGHT:
      93           0 :                 nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL;
      94           0 :             break;
      95             :             case EE_CHAR_WEIGHT:
      96           0 :                 nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL;
      97           0 :             break;
      98             :             case EE_CHAR_ITALIC:
      99           0 :                 nId = ( nScriptType == SvtScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL;
     100           0 :             break;
     101             :         }
     102             :     }
     103             : 
     104     5349494 :     return nId;
     105             : }
     106             : 
     107      519004 : bool IsScriptItemValid( sal_uInt16 nItemId, short nScriptType )
     108             : {
     109      519004 :     bool bValid = true;
     110             : 
     111      519004 :     switch ( nItemId )
     112             :     {
     113             :         case EE_CHAR_LANGUAGE:
     114       11758 :             bValid = nScriptType == i18n::ScriptType::LATIN;
     115       11758 :         break;
     116             :         case EE_CHAR_LANGUAGE_CJK:
     117       10141 :             bValid = nScriptType == i18n::ScriptType::ASIAN;
     118       10141 :         break;
     119             :         case EE_CHAR_LANGUAGE_CTL:
     120       10600 :             bValid = nScriptType == i18n::ScriptType::COMPLEX;
     121       10600 :         break;
     122             :         case EE_CHAR_FONTINFO:
     123       25908 :             bValid = nScriptType == i18n::ScriptType::LATIN;
     124       25908 :         break;
     125             :         case EE_CHAR_FONTINFO_CJK:
     126       18414 :             bValid = nScriptType == i18n::ScriptType::ASIAN;
     127       18414 :         break;
     128             :         case EE_CHAR_FONTINFO_CTL:
     129       17481 :             bValid = nScriptType == i18n::ScriptType::COMPLEX;
     130       17481 :         break;
     131             :         case EE_CHAR_FONTHEIGHT:
     132       36930 :             bValid = nScriptType == i18n::ScriptType::LATIN;
     133       36930 :         break;
     134             :         case EE_CHAR_FONTHEIGHT_CJK:
     135       25129 :             bValid = nScriptType == i18n::ScriptType::ASIAN;
     136       25129 :         break;
     137             :         case EE_CHAR_FONTHEIGHT_CTL:
     138       26588 :             bValid = nScriptType == i18n::ScriptType::COMPLEX;
     139       26588 :         break;
     140             :         case EE_CHAR_WEIGHT:
     141       22022 :             bValid = nScriptType == i18n::ScriptType::LATIN;
     142       22022 :         break;
     143             :         case EE_CHAR_WEIGHT_CJK:
     144       18288 :             bValid = nScriptType == i18n::ScriptType::ASIAN;
     145       18288 :         break;
     146             :         case EE_CHAR_WEIGHT_CTL:
     147       18836 :             bValid = nScriptType == i18n::ScriptType::COMPLEX;
     148       18836 :         break;
     149             :         case EE_CHAR_ITALIC:
     150       17875 :             bValid = nScriptType == i18n::ScriptType::LATIN;
     151       17875 :         break;
     152             :         case EE_CHAR_ITALIC_CJK:
     153       14198 :             bValid = nScriptType == i18n::ScriptType::ASIAN;
     154       14198 :         break;
     155             :         case EE_CHAR_ITALIC_CTL:
     156       13822 :             bValid = nScriptType == i18n::ScriptType::COMPLEX;
     157       13822 :         break;
     158             :     }
     159             : 
     160      519004 :     return bValid;
     161             : }
     162             : 
     163             : const SfxItemInfo aItemInfos[EDITITEMCOUNT] = {
     164             :         { SID_ATTR_FRAMEDIRECTION, SfxItemPoolFlags::POOLABLE },         // EE_PARA_WRITINGDIR
     165             :         { 0, SfxItemPoolFlags::POOLABLE },                               // EE_PARA_XMLATTRIBS
     166             :         { SID_ATTR_PARA_HANGPUNCTUATION, SfxItemPoolFlags::POOLABLE },   // EE_PARA_HANGINGPUNCTUATION
     167             :         { SID_ATTR_PARA_FORBIDDEN_RULES, SfxItemPoolFlags::POOLABLE },
     168             :         { SID_ATTR_PARA_SCRIPTSPACE, SfxItemPoolFlags::POOLABLE },       // EE_PARA_ASIANCJKSPACING
     169             :         { SID_ATTR_NUMBERING_RULE, SfxItemPoolFlags::POOLABLE },         // EE_PARA_NUMBULL
     170             :         { 0, SfxItemPoolFlags::POOLABLE },                               // EE_PARA_HYPHENATE
     171             :         { 0, SfxItemPoolFlags::POOLABLE },                               // EE_PARA_BULLETSTATE
     172             :         { 0, SfxItemPoolFlags::POOLABLE },                               // EE_PARA_OUTLLRSPACE
     173             :         { SID_ATTR_PARA_OUTLLEVEL, SfxItemPoolFlags::POOLABLE },         // EE_PARA_OUTLLEVEL
     174             :         { SID_ATTR_PARA_BULLET, SfxItemPoolFlags::POOLABLE },            // EE_PARA_BULLET
     175             :         { SID_ATTR_LRSPACE, SfxItemPoolFlags::POOLABLE },                // EE_PARA_LRSPACE
     176             :         { SID_ATTR_ULSPACE, SfxItemPoolFlags::POOLABLE },                // EE_PARA_ULSPACE
     177             :         { SID_ATTR_PARA_LINESPACE, SfxItemPoolFlags::POOLABLE },         // EE_PARA_SBL
     178             :         { SID_ATTR_PARA_ADJUST, SfxItemPoolFlags::POOLABLE },            // EE_PARA_JUST
     179             :         { SID_ATTR_TABSTOP, SfxItemPoolFlags::POOLABLE },                // EE_PARA_TABS
     180             :         { SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, SfxItemPoolFlags::POOLABLE }, // EE_PARA_JUST_METHOD
     181             :         { SID_ATTR_ALIGN_VER_JUSTIFY, SfxItemPoolFlags::POOLABLE },      // EE_PARA_VER_JUST
     182             :         { SID_ATTR_CHAR_COLOR, SfxItemPoolFlags::POOLABLE },
     183             :         { SID_ATTR_CHAR_FONT, SfxItemPoolFlags::POOLABLE },
     184             :         { SID_ATTR_CHAR_FONTHEIGHT, SfxItemPoolFlags::POOLABLE },
     185             :         { SID_ATTR_CHAR_SCALEWIDTH, SfxItemPoolFlags::POOLABLE },
     186             :         { SID_ATTR_CHAR_WEIGHT, SfxItemPoolFlags::POOLABLE },
     187             :         { SID_ATTR_CHAR_UNDERLINE, SfxItemPoolFlags::POOLABLE },
     188             :         { SID_ATTR_CHAR_STRIKEOUT, SfxItemPoolFlags::POOLABLE },
     189             :         { SID_ATTR_CHAR_POSTURE, SfxItemPoolFlags::POOLABLE },
     190             :         { SID_ATTR_CHAR_CONTOUR, SfxItemPoolFlags::POOLABLE },
     191             :         { SID_ATTR_CHAR_SHADOWED, SfxItemPoolFlags::POOLABLE },
     192             :         { SID_ATTR_CHAR_ESCAPEMENT, SfxItemPoolFlags::POOLABLE },
     193             :         { SID_ATTR_CHAR_AUTOKERN, SfxItemPoolFlags::POOLABLE },
     194             :         { SID_ATTR_CHAR_KERNING, SfxItemPoolFlags::POOLABLE },
     195             :         { SID_ATTR_CHAR_WORDLINEMODE, SfxItemPoolFlags::POOLABLE },
     196             :         { SID_ATTR_CHAR_LANGUAGE, SfxItemPoolFlags::POOLABLE },
     197             :         { SID_ATTR_CHAR_CJK_LANGUAGE, SfxItemPoolFlags::POOLABLE },
     198             :         { SID_ATTR_CHAR_CTL_LANGUAGE, SfxItemPoolFlags::POOLABLE },
     199             :         { SID_ATTR_CHAR_CJK_FONT, SfxItemPoolFlags::POOLABLE },
     200             :         { SID_ATTR_CHAR_CTL_FONT, SfxItemPoolFlags::POOLABLE },
     201             :         { SID_ATTR_CHAR_CJK_FONTHEIGHT, SfxItemPoolFlags::POOLABLE },
     202             :         { SID_ATTR_CHAR_CTL_FONTHEIGHT, SfxItemPoolFlags::POOLABLE },
     203             :         { SID_ATTR_CHAR_CJK_WEIGHT, SfxItemPoolFlags::POOLABLE },
     204             :         { SID_ATTR_CHAR_CTL_WEIGHT, SfxItemPoolFlags::POOLABLE },
     205             :         { SID_ATTR_CHAR_CJK_POSTURE, SfxItemPoolFlags::POOLABLE },
     206             :         { SID_ATTR_CHAR_CTL_POSTURE, SfxItemPoolFlags::POOLABLE },
     207             :         { SID_ATTR_CHAR_EMPHASISMARK, SfxItemPoolFlags::POOLABLE },
     208             :         { SID_ATTR_CHAR_RELIEF, SfxItemPoolFlags::POOLABLE },
     209             :         { 0, SfxItemPoolFlags::POOLABLE },                           // EE_CHAR_RUBI_DUMMY
     210             :         { 0, SfxItemPoolFlags::POOLABLE },                           // EE_CHAR_XMLATTRIBS
     211             :         { SID_ATTR_CHAR_OVERLINE, SfxItemPoolFlags::POOLABLE },
     212             :         { SID_ATTR_CHAR_CASEMAP, SfxItemPoolFlags::POOLABLE },       // EE_CHAR_CASEMAP
     213             :         { SID_ATTR_CHAR_GRABBAG, SfxItemPoolFlags::POOLABLE },       // EE_CHAR_GRABBAG
     214             :         { SID_ATTR_CHAR_BACK_COLOR, SfxItemPoolFlags::POOLABLE },    // EE_CHAR_BKGCOLOR
     215             :         { 0, SfxItemPoolFlags::POOLABLE },                           // EE_FEATURE_TAB
     216             :         { 0, SfxItemPoolFlags::POOLABLE },                           // EE_FEATURE_LINEBR
     217             :         { SID_ATTR_CHAR_CHARSETCOLOR, SfxItemPoolFlags::POOLABLE },  // EE_FEATURE_NOTCONV
     218             :         { SID_FIELD, SfxItemPoolFlags::POOLABLE }
     219             : };
     220             : 
     221             : const sal_uInt16 aV1Map[] = {
     222             :     3999, 4001, 4002, 4003, 4004, 4005, 4006,
     223             :     4007, 4008, 4009, 4010, 4011, 4012, 4013, 4017, 4018, 4019 // MI: 4019?
     224             : };
     225             : 
     226             : const sal_uInt16 aV2Map[] = {
     227             :     3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009,
     228             :     4010, 4011, 4012, 4013, 4014, 4015, 4016, 4018, 4019, 4020
     229             : };
     230             : 
     231             : const sal_uInt16 aV3Map[] = {
     232             :     3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007,
     233             :     4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019,
     234             :     4020, 4021
     235             : };
     236             : 
     237             : const sal_uInt16 aV4Map[] = {
     238             :     3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
     239             :     4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
     240             :     4014, 4015, 4016, 4017, 4018,
     241             :     /* CJK Items inserted here: EE_CHAR_LANGUAGE - EE_CHAR_XMLATTRIBS */
     242             :     4034, 4035, 4036, 4037
     243             : };
     244             : 
     245             : const sal_uInt16 aV5Map[] = {
     246             :     3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
     247             :     4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
     248             :     4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023,
     249             :     4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033,
     250             :     /* EE_CHAR_OVERLINE inserted here */
     251             :     4035, 4036, 4037, 4038
     252             : };
     253             : 
     254             : const sal_uInt16 aV6Map[] = {
     255             :     3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
     256             :     4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
     257             :     4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023,
     258             :     4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033,
     259             :     4035, 4036, 4037, 4038,
     260             :     /* EE_CHAR_GRABBAG inserted here */
     261             :     4039
     262             : };
     263             : 
     264      258408 : EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, sal_Int32 nS, sal_Int32 nE )
     265             : {
     266             :     // Create a new attribute in the pool
     267      258408 :     const SfxPoolItem& rNew = rPool.Put( rAttr );
     268             : 
     269      258408 :     EditCharAttrib* pNew = 0;
     270      258408 :     switch( rNew.Which() )
     271             :     {
     272             :         case EE_CHAR_LANGUAGE:
     273             :         case EE_CHAR_LANGUAGE_CJK:
     274             :         case EE_CHAR_LANGUAGE_CTL:
     275             :         {
     276       24384 :             pNew = new EditCharAttribLanguage( static_cast<const SvxLanguageItem&>(rNew), nS, nE );
     277             :         }
     278       24384 :         break;
     279             :         case EE_CHAR_COLOR:
     280             :         {
     281       19289 :             pNew = new EditCharAttribColor( static_cast<const SvxColorItem&>(rNew), nS, nE );
     282             :         }
     283       19289 :         break;
     284             :         case EE_CHAR_FONTINFO:
     285             :         case EE_CHAR_FONTINFO_CJK:
     286             :         case EE_CHAR_FONTINFO_CTL:
     287             :         {
     288       35254 :             pNew = new EditCharAttribFont( static_cast<const SvxFontItem&>(rNew), nS, nE );
     289             :         }
     290       35254 :         break;
     291             :         case EE_CHAR_FONTHEIGHT:
     292             :         case EE_CHAR_FONTHEIGHT_CJK:
     293             :         case EE_CHAR_FONTHEIGHT_CTL:
     294             :         {
     295       50122 :             pNew = new EditCharAttribFontHeight( static_cast<const SvxFontHeightItem&>(rNew), nS, nE );
     296             :         }
     297       50122 :         break;
     298             :         case EE_CHAR_FONTWIDTH:
     299             :         {
     300        2150 :             pNew = new EditCharAttribFontWidth( static_cast<const SvxCharScaleWidthItem&>(rNew), nS, nE );
     301             :         }
     302        2150 :         break;
     303             :         case EE_CHAR_WEIGHT:
     304             :         case EE_CHAR_WEIGHT_CJK:
     305             :         case EE_CHAR_WEIGHT_CTL:
     306             :         {
     307       32242 :             pNew = new EditCharAttribWeight( static_cast<const SvxWeightItem&>(rNew), nS, nE );
     308             :         }
     309       32242 :         break;
     310             :         case EE_CHAR_UNDERLINE:
     311             :         {
     312        7950 :             pNew = new EditCharAttribUnderline( static_cast<const SvxUnderlineItem&>(rNew), nS, nE );
     313             :         }
     314        7950 :         break;
     315             :         case EE_CHAR_OVERLINE:
     316             :         {
     317        1636 :             pNew = new EditCharAttribOverline( static_cast<const SvxOverlineItem&>(rNew), nS, nE );
     318             :         }
     319        1636 :         break;
     320             :         case EE_CHAR_EMPHASISMARK:
     321             :         {
     322        2478 :             pNew = new EditCharAttribEmphasisMark( static_cast<const SvxEmphasisMarkItem&>(rNew), nS, nE );
     323             :         }
     324        2478 :         break;
     325             :         case EE_CHAR_RELIEF:
     326             :         {
     327        2155 :             pNew = new EditCharAttribRelief( static_cast<const SvxCharReliefItem&>(rNew), nS, nE );
     328             :         }
     329        2155 :         break;
     330             :         case EE_CHAR_STRIKEOUT:
     331             :         {
     332        6774 :             pNew = new EditCharAttribStrikeout( static_cast<const SvxCrossedOutItem&>(rNew), nS, nE );
     333             :         }
     334        6774 :         break;
     335             :         case EE_CHAR_ITALIC:
     336             :         case EE_CHAR_ITALIC_CJK:
     337             :         case EE_CHAR_ITALIC_CTL:
     338             :         {
     339       18649 :             pNew = new EditCharAttribItalic( static_cast<const SvxPostureItem&>(rNew), nS, nE );
     340             :         }
     341       18649 :         break;
     342             :         case EE_CHAR_OUTLINE:
     343             :         {
     344        2927 :             pNew = new EditCharAttribOutline( static_cast<const SvxContourItem&>(rNew), nS, nE );
     345             :         }
     346        2927 :         break;
     347             :         case EE_CHAR_SHADOW:
     348             :         {
     349        2972 :             pNew = new EditCharAttribShadow( static_cast<const SvxShadowedItem&>(rNew), nS, nE );
     350             :         }
     351        2972 :         break;
     352             :         case EE_CHAR_ESCAPEMENT:
     353             :         {
     354        6879 :             pNew = new EditCharAttribEscapement( static_cast<const SvxEscapementItem&>(rNew), nS, nE );
     355             :         }
     356        6879 :         break;
     357             :         case EE_CHAR_PAIRKERNING:
     358             :         {
     359        2076 :             pNew = new EditCharAttribPairKerning( static_cast<const SvxAutoKernItem&>(rNew), nS, nE );
     360             :         }
     361        2076 :         break;
     362             :         case EE_CHAR_KERNING:
     363             :         {
     364        6018 :             pNew = new EditCharAttribKerning( static_cast<const SvxKerningItem&>(rNew), nS, nE );
     365             :         }
     366        6018 :         break;
     367             :         case EE_CHAR_WLM:
     368             :         {
     369        1983 :             pNew = new EditCharAttribWordLineMode( static_cast<const SvxWordLineModeItem&>(rNew), nS, nE );
     370             :         }
     371        1983 :         break;
     372             :         case EE_CHAR_XMLATTRIBS:
     373             :         {
     374        1605 :             pNew = new EditCharAttrib( rNew, nS, nE );  // Attribute is only for holding XML information...
     375             :         }
     376        1605 :         break;
     377             :         case EE_CHAR_CASEMAP:
     378             :         {
     379        5633 :             pNew = new EditCharAttribCaseMap( static_cast<const SvxCaseMapItem&>(rNew), nS, nE );
     380             :         }
     381        5633 :         break;
     382             :         case EE_CHAR_GRABBAG:
     383             :         {
     384        1545 :             pNew = new EditCharAttribGrabBag( static_cast<const SfxGrabBagItem&>(rNew), nS, nE );
     385             :         }
     386        1545 :         break;
     387             :         case EE_FEATURE_TAB:
     388             :         {
     389         104 :             pNew = new EditCharAttribTab( static_cast<const SfxVoidItem&>(rNew), nS );
     390             :         }
     391         104 :         break;
     392             :         case EE_FEATURE_LINEBR:
     393             :         {
     394         115 :             pNew = new EditCharAttribLineBreak( static_cast<const SfxVoidItem&>(rNew), nS );
     395             :         }
     396         115 :         break;
     397             :         case EE_FEATURE_FIELD:
     398             :         {
     399       21518 :             pNew = new EditCharAttribField( static_cast<const SvxFieldItem&>(rNew), nS );
     400             :         }
     401       21518 :         break;
     402             :         case EE_CHAR_BKGCOLOR:
     403             :         {
     404        1950 :             pNew = new EditCharAttribBackgroundColor( static_cast<const SvxBackgroundColorItem&>(rNew), nS, nE );
     405             :         }
     406        1950 :         break;
     407             :         default:
     408             :         {
     409             :             OSL_FAIL( "Invalid Attribute!" );
     410             :         }
     411             :     }
     412      258408 :     return pNew;
     413             : }
     414             : 
     415      506251 : TextPortionList::TextPortionList()
     416             : {
     417      506251 : }
     418             : 
     419     1007816 : TextPortionList::~TextPortionList()
     420             : {
     421      503908 :     Reset();
     422      503908 : }
     423             : 
     424      563624 : void TextPortionList::Reset()
     425             : {
     426      563624 :     maPortions.clear();
     427      563624 : }
     428             : 
     429      144049 : void TextPortionList::DeleteFromPortion(sal_Int32 nDelFrom)
     430             : {
     431             :     DBG_ASSERT( ( nDelFrom < (sal_Int32)maPortions.size() ) || ( (nDelFrom == 0) && maPortions.empty() ), "DeleteFromPortion: Out of range" );
     432      144049 :     PortionsType::iterator it = maPortions.begin();
     433      144049 :     std::advance(it, nDelFrom);
     434      144049 :     maPortions.erase(it, maPortions.end());
     435      144049 : }
     436             : 
     437     1526854 : sal_Int32 TextPortionList::Count() const
     438             : {
     439     1526854 :     return (sal_Int32)maPortions.size();
     440             : }
     441             : 
     442       60102 : const TextPortion* TextPortionList::operator[](sal_Int32 nPos) const
     443             : {
     444       60102 :     return &maPortions[nPos];
     445             : }
     446             : 
     447     1677123 : TextPortion* TextPortionList::operator[](sal_Int32 nPos)
     448             : {
     449     1677123 :     return &maPortions[nPos];
     450             : }
     451             : 
     452      394515 : void TextPortionList::Append(TextPortion* p)
     453             : {
     454      394515 :     maPortions.push_back(p);
     455      394515 : }
     456             : 
     457       80227 : void TextPortionList::Insert(sal_Int32 nPos, TextPortion* p)
     458             : {
     459       80227 :     maPortions.insert(maPortions.begin()+nPos, p);
     460       80227 : }
     461             : 
     462           0 : void TextPortionList::Remove(sal_Int32 nPos)
     463             : {
     464           0 :     maPortions.erase(maPortions.begin()+nPos);
     465           0 : }
     466             : 
     467             : namespace {
     468             : 
     469             : class FindTextPortionByAddress : std::unary_function<TextPortion, bool>
     470             : {
     471             :     const TextPortion* mp;
     472             : public:
     473           0 :     FindTextPortionByAddress(const TextPortion* p) : mp(p) {}
     474           0 :     bool operator() (const TextPortion& v) const
     475             :     {
     476           0 :         return &v == mp;
     477             :     }
     478             : };
     479             : 
     480             : }
     481             : 
     482           0 : sal_Int32 TextPortionList::GetPos(const TextPortion* p) const
     483             : {
     484             :     PortionsType::const_iterator it =
     485           0 :         std::find_if(maPortions.begin(), maPortions.end(), FindTextPortionByAddress(p));
     486             : 
     487           0 :     if (it == maPortions.end())
     488           0 :         return std::numeric_limits<sal_Int32>::max(); // not found.
     489             : 
     490           0 :     return std::distance(maPortions.begin(), it);
     491             : }
     492             : 
     493        2692 : sal_Int32 TextPortionList::FindPortion(
     494             :     sal_Int32 nCharPos, sal_Int32& nPortionStart, bool bPreferStartingPortion) const
     495             : {
     496             :     // When nCharPos at portion limit, the left portion is found
     497        2692 :     sal_Int32 nTmpPos = 0;
     498        2692 :     sal_Int32 n = maPortions.size();
     499        3873 :     for (sal_Int32 i = 0; i < n; ++i)
     500             :     {
     501        3873 :         const TextPortion& rPortion = maPortions[i];
     502        3873 :         nTmpPos = nTmpPos + rPortion.GetLen();
     503        3873 :         if ( nTmpPos >= nCharPos )
     504             :         {
     505             :             // take this one if we don't prefer the starting portion, or if it's the last one
     506        2692 :             if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( i == n-1 ) )
     507             :             {
     508        2692 :                 nPortionStart = nTmpPos - rPortion.GetLen();
     509        2692 :                 return i;
     510             :             }
     511             :         }
     512             :     }
     513             :     OSL_FAIL( "FindPortion: Not found!" );
     514           0 :     return n - 1;
     515             : }
     516             : 
     517           0 : sal_Int32 TextPortionList::GetStartPos(sal_Int32 nPortion)
     518             : {
     519           0 :     sal_Int32 nPos = 0;
     520           0 :     for (sal_Int32 i = 0; i < nPortion; ++i)
     521             :     {
     522           0 :         const TextPortion& rPortion = maPortions[i];
     523           0 :         nPos = nPos + rPortion.GetLen();
     524             :     }
     525           0 :     return nPos;
     526             : }
     527             : 
     528           0 : ExtraPortionInfo::ExtraPortionInfo()
     529             : : nOrgWidth(0)
     530             : , nWidthFullCompression(0)
     531             : , nPortionOffsetX(0)
     532             : , nMaxCompression100thPercent(0)
     533             : , nAsianCompressionTypes(0)
     534             : , bFirstCharIsRightPunktuation(false)
     535             : , bCompressed(false)
     536             : , pOrgDXArray(NULL)
     537           0 : , lineBreaksList()
     538             : {
     539           0 : }
     540             : 
     541           0 : ExtraPortionInfo::~ExtraPortionInfo()
     542             : {
     543           0 :     delete[] pOrgDXArray;
     544           0 : }
     545             : 
     546           0 : void ExtraPortionInfo::SaveOrgDXArray( const long* pDXArray, sal_Int32 nLen )
     547             : {
     548           0 :     delete[] pOrgDXArray;
     549           0 :     if (pDXArray)
     550             :     {
     551           0 :         pOrgDXArray = new long[nLen];
     552           0 :         memcpy( pOrgDXArray, pDXArray, nLen * sizeof(long) );
     553             :     }
     554             :     else
     555           0 :         pOrgDXArray = NULL;
     556           0 : }
     557             : 
     558      506251 : ParaPortion::ParaPortion( ContentNode* pN )
     559             : {
     560             : 
     561      506251 :     pNode               = pN;
     562      506251 :     bInvalid            = true;
     563      506251 :     bVisible            = true;
     564      506251 :     bSimple             = false;
     565      506251 :     bForceRepaint       = false;
     566      506251 :     nInvalidPosStart    = 0;
     567      506251 :     nInvalidDiff        = 0;
     568      506251 :     nHeight             = 0;
     569      506251 :     nFirstLineOffset    = 0;
     570      506251 :     nBulletX            = 0;
     571      506251 : }
     572             : 
     573      503908 : ParaPortion::~ParaPortion()
     574             : {
     575      503908 : }
     576             : 
     577      281851 : void ParaPortion::MarkInvalid( sal_Int32 nStart, sal_Int32 nDiff )
     578             : {
     579      281851 :     if ( !bInvalid )
     580             :     {
     581             : //      nInvalidPosEnd = nStart;    // ??? => CreateLines
     582       23841 :         nInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff );
     583       23841 :         nInvalidDiff = nDiff;
     584             :     }
     585             :     else
     586             :     {
     587             :         // Simple tap in succession
     588      259989 :         if ( ( nDiff > 0 ) && ( nInvalidDiff > 0 ) &&
     589        1979 :              ( ( nInvalidPosStart+nInvalidDiff ) == nStart ) )
     590             :         {
     591        1978 :             nInvalidDiff = nInvalidDiff + nDiff;
     592             :         }
     593             :         // Simple delete in succession
     594      256032 :         else if ( ( nDiff < 0 ) && ( nInvalidDiff < 0 ) && ( nInvalidPosStart == nStart ) )
     595             :         {
     596           0 :             nInvalidPosStart = nInvalidPosStart + nDiff;
     597           0 :             nInvalidDiff = nInvalidDiff + nDiff;
     598             :         }
     599             :         else
     600             :         {
     601             : //          nInvalidPosEnd = pNode->Len();
     602             :             DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" );
     603      256032 :             nInvalidPosStart = std::min( nInvalidPosStart, ( nDiff < 0 ? nStart+nDiff : nDiff ) );
     604      256032 :             nInvalidDiff = 0;
     605      256032 :             bSimple = false;
     606             :         }
     607             :     }
     608      281851 :     bInvalid = true;
     609      281851 :     aScriptInfos.clear();
     610      281851 :     aWritingDirectionInfos.clear();
     611      281851 : }
     612             : 
     613      989939 : void ParaPortion::MarkSelectionInvalid( sal_Int32 nStart, sal_Int32 /* nEnd */ )
     614             : {
     615      989939 :     if ( !bInvalid )
     616             :     {
     617       88202 :         nInvalidPosStart = nStart;
     618             : //      nInvalidPosEnd = nEnd;
     619             :     }
     620             :     else
     621             :     {
     622      901737 :         nInvalidPosStart = std::min( nInvalidPosStart, nStart );
     623             : //      nInvalidPosEnd = pNode->Len();
     624             :     }
     625      989939 :     nInvalidDiff = 0;
     626      989939 :     bInvalid = true;
     627      989939 :     bSimple = false;
     628      989939 :     aScriptInfos.clear();
     629      989939 :     aWritingDirectionInfos.clear();
     630      989939 : }
     631             : 
     632           8 : sal_Int32 ParaPortion::GetLineNumber( sal_Int32 nIndex ) const
     633             : {
     634             :     DBG_ASSERTWARNING( aLineList.Count(), "Empty ParaPortion in GetLine!" );
     635             :     DBG_ASSERT( bVisible, "Why GetLine() on an invisible paragraph?" );
     636             : 
     637           8 :     for ( sal_Int32 nLine = 0; nLine < aLineList.Count(); nLine++ )
     638             :     {
     639           8 :         if ( aLineList[nLine]->IsIn( nIndex ) )
     640           8 :             return (sal_Int32)nLine;
     641             :     }
     642             : 
     643             :     // Then it should be at the end of the last line!
     644             :     DBG_ASSERT( nIndex == aLineList[ aLineList.Count() - 1 ]->GetEnd(), "Index dead wrong!" );
     645           0 :     return (aLineList.Count()-1);
     646             : }
     647             : 
     648           0 : void ParaPortion::SetVisible( bool bMakeVisible )
     649             : {
     650           0 :     bVisible = bMakeVisible;
     651           0 : }
     652             : 
     653           2 : void ParaPortion::CorrectValuesBehindLastFormattedLine( sal_Int32 nLastFormattedLine )
     654             : {
     655           2 :     sal_Int32 nLines = aLineList.Count();
     656             :     DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Empty Portion?" );
     657           2 :     if ( nLastFormattedLine < ( nLines - 1 ) )
     658             :     {
     659           0 :         const EditLine* pLastFormatted = aLineList[ nLastFormattedLine ];
     660           0 :         const EditLine* pUnformatted = aLineList[ nLastFormattedLine+1 ];
     661           0 :         sal_Int32 nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion();
     662           0 :         sal_Int32 nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd();
     663           0 :         nTextDiff++;    // LastFormatted->GetEnd() was included => 1 deducted too much!
     664             : 
     665             :         // The first unformatted must begin exactly one Portion behind the last
     666             :         // of the formatted:
     667             :         // If the modified line was split into one portion, can
     668             :         // nLastEnd > nNextStart!
     669           0 :         int nPDiff = -( nPortionDiff-1 );
     670           0 :         int nTDiff = -( nTextDiff-1 );
     671           0 :         if ( nPDiff || nTDiff )
     672             :         {
     673           0 :             for ( sal_Int32 nL = nLastFormattedLine+1; nL < nLines; nL++ )
     674             :             {
     675           0 :                 EditLine* pLine = aLineList[ nL ];
     676             : 
     677           0 :                 pLine->GetStartPortion() = pLine->GetStartPortion() + nPDiff;
     678           0 :                 pLine->GetEndPortion() = pLine->GetEndPortion() + nPDiff;
     679             : 
     680           0 :                 pLine->GetStart() = pLine->GetStart() + nTDiff;
     681           0 :                 pLine->GetEnd() = pLine->GetEnd() + nTDiff;
     682             : 
     683           0 :                 pLine->SetValid();
     684             :             }
     685             :         }
     686             :     }
     687             :     DBG_ASSERT( aLineList[ aLineList.Count()-1 ]->GetEnd() == pNode->Len(), "CorrectLines: The end is not right!" );
     688           2 : }
     689             : 
     690             : // Shared reverse lookup acceleration pieces ...
     691             : 
     692             : namespace {
     693             : 
     694             : template<typename _Array, typename _Val>
     695     6013548 : sal_Int32 FastGetPos(const _Array& rArray, const _Val* p, sal_Int32& rLastPos)
     696             : {
     697     6013548 :     sal_Int32 nArrayLen = rArray.size();
     698             : 
     699             :     // Through certain filter code-paths we do a lot of appends, which in
     700             :     // turn call GetPos - creating some N^2 nightmares. If we have a
     701             :     // non-trivially large list, do a few checks from the end first.
     702     6013548 :     if (rLastPos > 16 && nArrayLen > 16)
     703             :     {
     704             :         sal_Int32 nEnd;
     705       14711 :         if (rLastPos > nArrayLen - 2)
     706        6875 :             nEnd = nArrayLen;
     707             :         else
     708        7836 :             nEnd = rLastPos + 2;
     709             : 
     710       46697 :         for (sal_Int32 nIdx = rLastPos - 2; nIdx < nEnd; ++nIdx)
     711             :         {
     712       46624 :             if (&rArray.at(nIdx) == p)
     713             :             {
     714       14638 :                 rLastPos = nIdx;
     715       14638 :                 return nIdx;
     716             :             }
     717             :         }
     718             :     }
     719             :     // The world's lamest linear search from svarray ...
     720     6739014 :     for (sal_Int32 nIdx = 0; nIdx < nArrayLen; ++nIdx)
     721     6739011 :         if (&rArray.at(nIdx) == p)
     722     5998907 :             return rLastPos = nIdx;
     723             : 
     724             :     // XXX "not found" condition for sal_Int32 indexes
     725           3 :     return EE_PARA_NOT_FOUND;
     726             : }
     727             : 
     728             : }
     729             : 
     730       42102 : ParaPortionList::ParaPortionList() : nLastCache( 0 )
     731             : {
     732       42102 : }
     733             : 
     734       39771 : ParaPortionList::~ParaPortionList()
     735             : {
     736       39771 : }
     737             : 
     738     1031803 : sal_Int32 ParaPortionList::GetPos(const ParaPortion* p) const
     739             : {
     740     1031803 :     return FastGetPos(maPortions, p, nLastCache);
     741             : }
     742             : 
     743     2812394 : ParaPortion* ParaPortionList::operator [](sal_Int32 nPos)
     744             : {
     745     2812394 :     return 0 <= nPos && nPos < (sal_Int32)maPortions.size() ? &maPortions[nPos] : NULL;
     746             : }
     747             : 
     748           0 : const ParaPortion* ParaPortionList::operator [](sal_Int32 nPos) const
     749             : {
     750           0 :     return 0 <= nPos && nPos < (sal_Int32)maPortions.size() ? &maPortions[nPos] : NULL;
     751             : }
     752             : 
     753           0 : ParaPortion* ParaPortionList::Release(sal_Int32 nPos)
     754             : {
     755           0 :     if (nPos < 0 || (sal_Int32)maPortions.size() <= nPos)
     756             :     {
     757             :         SAL_WARN( "editeng", "ParaPortionList::Release - out of bounds pos " << nPos);
     758           0 :         return NULL;
     759             :     }
     760           0 :     return maPortions.release(maPortions.begin()+nPos).release();
     761             : }
     762             : 
     763        2445 : void ParaPortionList::Remove(sal_Int32 nPos)
     764             : {
     765        2445 :     if (nPos < 0 || (sal_Int32)maPortions.size() <= nPos)
     766             :     {
     767             :         SAL_WARN( "editeng", "ParaPortionList::Remove - out of bounds pos " << nPos);
     768        2445 :         return;
     769             :     }
     770        2445 :     maPortions.erase(maPortions.begin()+nPos);
     771             : }
     772             : 
     773      506251 : void ParaPortionList::Insert(sal_Int32 nPos, ParaPortion* p)
     774             : {
     775      506251 :     if (nPos < 0 || (sal_Int32)maPortions.size() < nPos)
     776             :     {
     777             :         SAL_WARN( "editeng", "ParaPortionList::Insert - out of bounds pos " << nPos);
     778      506251 :         return;
     779             :     }
     780      506251 :     maPortions.insert(maPortions.begin()+nPos, p);
     781             : }
     782             : 
     783           0 : void ParaPortionList::Append(ParaPortion* p)
     784             : {
     785           0 :     maPortions.push_back(p);
     786           0 : }
     787             : 
     788     2574856 : sal_Int32 ParaPortionList::Count() const
     789             : {
     790     2574856 :     size_t nSize = maPortions.size();
     791     2574856 :     if (nSize > SAL_MAX_INT32)
     792             :     {
     793             :         SAL_WARN( "editeng", "ParaPortionList::Count - overflow " << nSize);
     794           0 :         return SAL_MAX_INT32;
     795             :     }
     796     2574856 :     return nSize;
     797             : }
     798             : 
     799      487397 : void ParaPortionList::Reset()
     800             : {
     801      487397 :     maPortions.clear();
     802      487397 : }
     803             : 
     804         190 : long ParaPortionList::GetYOffset(const ParaPortion* pPPortion) const
     805             : {
     806         190 :     long nHeight = 0;
     807         190 :     for (sal_Int32 i = 0, n = maPortions.size(); i < n; ++i)
     808             :     {
     809         190 :         const ParaPortion* pTmpPortion = &maPortions[i];
     810         190 :         if ( pTmpPortion == pPPortion )
     811         190 :             return nHeight;
     812           0 :         nHeight += pTmpPortion->GetHeight();
     813             :     }
     814             :     OSL_FAIL( "GetYOffset: Portion not found" );
     815           0 :     return nHeight;
     816             : }
     817             : 
     818           3 : sal_Int32 ParaPortionList::FindParagraph(long nYOffset) const
     819             : {
     820           3 :     long nY = 0;
     821           3 :     for (size_t i = 0, n = maPortions.size(); i < n; ++i)
     822             :     {
     823           3 :         nY += maPortions[i].GetHeight(); // should also be correct even in bVisible!
     824           3 :         if ( nY > nYOffset )
     825           3 :             return i <= SAL_MAX_INT32 ? static_cast<sal_Int32>(i) : SAL_MAX_INT32;
     826             :     }
     827           0 :     return EE_PARA_NOT_FOUND;
     828             : }
     829             : 
     830     1263472 : const ParaPortion* ParaPortionList::SafeGetObject(sal_Int32 nPos) const
     831             : {
     832     1263472 :     return 0 <= nPos && nPos < (sal_Int32)maPortions.size() ? &maPortions[nPos] : NULL;
     833             : }
     834             : 
     835     1586452 : ParaPortion* ParaPortionList::SafeGetObject(sal_Int32 nPos)
     836             : {
     837     1586452 :     return 0 <= nPos && nPos < (sal_Int32)maPortions.size() ? &maPortions[nPos] : NULL;
     838             : }
     839             : 
     840             : #if OSL_DEBUG_LEVEL > 0
     841             : void
     842             : ParaPortionList::DbgCheck(ParaPortionList const& rParas, EditDoc const& rDoc)
     843             : {
     844             :     assert(rParas.Count() == rDoc.Count());
     845             :     for (sal_Int32 i = 0; i < rParas.Count(); ++i)
     846             :     {
     847             :         assert(rParas.SafeGetObject(i) != nullptr);
     848             :         assert(rParas.SafeGetObject(i)->GetNode() != nullptr);
     849             :         assert(rParas.SafeGetObject(i)->GetNode() == rDoc.GetObject(i));
     850             :     }
     851             : }
     852             : #endif
     853             : 
     854        6316 : ContentAttribsInfo::ContentAttribsInfo( const SfxItemSet& rParaAttribs ) :
     855        6316 :         aPrevParaAttribs( rParaAttribs)
     856             : {
     857        6316 : }
     858             : 
     859        6299 : void ContentAttribsInfo::RemoveAllCharAttribsFromPool(SfxItemPool& rPool) const
     860             : {
     861        6299 :     CharAttribsType::const_iterator it = aPrevCharAttribs.begin(), itEnd = aPrevCharAttribs.end();
     862       47235 :     for (; it != itEnd; ++it)
     863       40936 :         rPool.Remove(*it->GetItem());
     864        6299 : }
     865             : 
     866       41049 : void ContentAttribsInfo::AppendCharAttrib(EditCharAttrib* pNew)
     867             : {
     868       41049 :     aPrevCharAttribs.push_back(pNew);
     869       41049 : }
     870             : 
     871           4 : void ConvertItem( SfxPoolItem& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit )
     872             : {
     873             :     DBG_ASSERT( eSourceUnit != eDestUnit, "ConvertItem - Why?!" );
     874             : 
     875           4 :     switch ( rPoolItem.Which() )
     876             :     {
     877             :         case EE_PARA_LRSPACE:
     878             :         {
     879             :             DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLRSpaceItem ) ), "ConvertItem: invalid Item!" );
     880           0 :             SvxLRSpaceItem& rItem = static_cast<SvxLRSpaceItem&>(rPoolItem);
     881           0 :             rItem.SetTextFirstLineOfst( sal::static_int_cast< short >( OutputDevice::LogicToLogic( rItem.GetTextFirstLineOfst(), eSourceUnit, eDestUnit ) ) );
     882           0 :             rItem.SetTextLeft( OutputDevice::LogicToLogic( rItem.GetTextLeft(), eSourceUnit, eDestUnit ) );
     883           0 :             rItem.SetRight( OutputDevice::LogicToLogic( rItem.GetRight(), eSourceUnit, eDestUnit ) );
     884             :         }
     885           0 :         break;
     886             :         case EE_PARA_ULSPACE:
     887             :         {
     888             :             DBG_ASSERT( rPoolItem.IsA( TYPE( SvxULSpaceItem ) ), "ConvertItem: Invalid Item!" );
     889           0 :             SvxULSpaceItem& rItem = static_cast<SvxULSpaceItem&>(rPoolItem);
     890           0 :             rItem.SetUpper( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetUpper(), eSourceUnit, eDestUnit ) ) );
     891           0 :             rItem.SetLower( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetLower(), eSourceUnit, eDestUnit ) ) );
     892             :         }
     893           0 :         break;
     894             :         case EE_PARA_SBL:
     895             :         {
     896             :             DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLineSpacingItem ) ), "ConvertItem: Invalid Item!" );
     897           0 :             SvxLineSpacingItem& rItem = static_cast<SvxLineSpacingItem&>(rPoolItem);
     898             :             // SetLineHeight changes also eLineSpace!
     899           0 :             if ( rItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN )
     900           0 :                 rItem.SetLineHeight( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetLineHeight(), eSourceUnit, eDestUnit ) ) );
     901             :         }
     902           0 :         break;
     903             :         case EE_PARA_TABS:
     904             :         {
     905             :             DBG_ASSERT( rPoolItem.IsA( TYPE( SvxTabStopItem ) ), "ConvertItem: Invalid Item!" );
     906           0 :             SvxTabStopItem& rItem = static_cast<SvxTabStopItem&>(rPoolItem);
     907           0 :             SvxTabStopItem aNewItem( EE_PARA_TABS );
     908           0 :             for ( sal_uInt16 i = 0; i < rItem.Count(); i++ )
     909             :             {
     910           0 :                 const SvxTabStop& rTab = rItem[i];
     911           0 :                 SvxTabStop aNewStop( OutputDevice::LogicToLogic( rTab.GetTabPos(), eSourceUnit, eDestUnit ), rTab.GetAdjustment(), rTab.GetDecimal(), rTab.GetFill() );
     912           0 :                 aNewItem.Insert( aNewStop );
     913             :             }
     914           0 :             rItem = aNewItem;
     915             :         }
     916           0 :         break;
     917             :         case EE_CHAR_FONTHEIGHT:
     918             :         case EE_CHAR_FONTHEIGHT_CJK:
     919             :         case EE_CHAR_FONTHEIGHT_CTL:
     920             :         {
     921             :             DBG_ASSERT( rPoolItem.IsA( TYPE( SvxFontHeightItem ) ), "ConvertItem: Invalid Item!" );
     922           0 :             SvxFontHeightItem& rItem = static_cast<SvxFontHeightItem&>(rPoolItem);
     923           0 :             rItem.SetHeight( OutputDevice::LogicToLogic( rItem.GetHeight(), eSourceUnit, eDestUnit ) );
     924             :         }
     925           0 :         break;
     926             :     }
     927           4 : }
     928             : 
     929           4 : void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit, const MapUnit* pDestUnit )
     930             : {
     931           4 :     const SfxItemPool* pSourcePool = rSource.GetPool();
     932           4 :     const SfxItemPool* pDestPool = rDest.GetPool();
     933             : 
     934         208 :     for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
     935             :     {
     936             :         // If possible go through SlotID ...
     937             : 
     938         204 :         sal_uInt16 nSourceWhich = nWhich;
     939         204 :         sal_uInt16 nSlot = pDestPool->GetTrueSlotId( nWhich );
     940         204 :         if ( nSlot )
     941             :         {
     942         180 :             sal_uInt16 nW = pSourcePool->GetTrueWhich( nSlot );
     943         180 :             if ( nW )
     944         180 :                 nSourceWhich = nW;
     945             :         }
     946             : 
     947         204 :         if ( rSource.GetItemState( nSourceWhich, false ) == SfxItemState::SET )
     948             :         {
     949           0 :             MapUnit eSourceUnit = pSourceUnit ? *pSourceUnit : (MapUnit)pSourcePool->GetMetric( nSourceWhich );
     950           0 :             MapUnit eDestUnit = pDestUnit ? *pDestUnit : (MapUnit)pDestPool->GetMetric( nWhich );
     951           0 :             if ( eSourceUnit != eDestUnit )
     952             :             {
     953           0 :                 SfxPoolItem* pItem = rSource.Get( nSourceWhich ).Clone();
     954             : //              pItem->SetWhich( nWhich );
     955           0 :                 ConvertItem( *pItem, eSourceUnit, eDestUnit );
     956           0 :                 rDest.Put( *pItem, nWhich );
     957           0 :                 delete pItem;
     958             :             }
     959             :             else
     960             :             {
     961           0 :                 rDest.Put( rSource.Get( nSourceWhich ), nWhich );
     962             :             }
     963             :         }
     964             :     }
     965           4 : }
     966             : 
     967      462685 : EditLine::EditLine() :
     968             :     bHangingPunctuation(false),
     969      462685 :     bInvalid(true)
     970             : {
     971             : 
     972      462685 :     nStart = nEnd = 0;
     973      462685 :     nStartPortion = 0;  // to be able to tell the difference between a line
     974             :                         // without Ptorions form one with the Portion number 0
     975      462685 :     nEndPortion = 0;
     976      462685 :     nHeight = 0;
     977      462685 :     nStartPosX = 0;
     978      462685 :     nTxtHeight = 0;
     979      462685 :     nTxtWidth = 0;
     980      462685 :     nCrsrHeight = 0;
     981      462685 :     nMaxAscent = 0;
     982      462685 : }
     983             : 
     984      144052 : EditLine::EditLine( const EditLine& r ) :
     985             :     bHangingPunctuation(r.bHangingPunctuation),
     986      144052 :     bInvalid(true)
     987             : {
     988             : 
     989      144052 :     nEnd = r.nEnd;
     990      144052 :     nStart = r.nStart;
     991      144052 :     nStartPortion = r.nStartPortion;
     992      144052 :     nEndPortion = r.nEndPortion;
     993             : 
     994      144052 :     nHeight = 0;
     995      144052 :     nStartPosX = 0;
     996      144052 :     nTxtHeight = 0;
     997      144052 :     nTxtWidth = 0;
     998      144052 :     nCrsrHeight = 0;
     999      144052 :     nMaxAscent = 0;
    1000      144052 : }
    1001             : 
    1002      604443 : EditLine::~EditLine()
    1003             : {
    1004      604443 : }
    1005             : 
    1006             : 
    1007             : 
    1008           0 : EditLine* EditLine::Clone() const
    1009             : {
    1010           0 :     EditLine* pL = new EditLine;
    1011           0 :     pL->aPositions = aPositions;
    1012           0 :     pL->nStartPosX      = nStartPosX;
    1013           0 :     pL->nStart          = nStart;
    1014           0 :     pL->nEnd            = nEnd;
    1015           0 :     pL->nStartPortion   = nStartPortion;
    1016           0 :     pL->nEndPortion     = nEndPortion;
    1017           0 :     pL->nHeight         = nHeight;
    1018           0 :     pL->nTxtWidth       = nTxtWidth;
    1019           0 :     pL->nTxtHeight      = nTxtHeight;
    1020           0 :     pL->nCrsrHeight     = nCrsrHeight;
    1021           0 :     pL->nMaxAscent      = nMaxAscent;
    1022             : 
    1023           0 :     return pL;
    1024             : }
    1025             : 
    1026           0 : bool operator == ( const EditLine& r1,  const EditLine& r2  )
    1027             : {
    1028           0 :     if ( r1.nStart != r2.nStart )
    1029           0 :         return false;
    1030             : 
    1031           0 :     if ( r1.nEnd != r2.nEnd )
    1032           0 :         return false;
    1033             : 
    1034           0 :     if ( r1.nStartPortion != r2.nStartPortion )
    1035           0 :         return false;
    1036             : 
    1037           0 :     if ( r1.nEndPortion != r2.nEndPortion )
    1038           0 :         return false;
    1039             : 
    1040           0 :     return true;
    1041             : }
    1042             : 
    1043       80658 : EditLine& EditLine::operator = ( const EditLine& r )
    1044             : {
    1045       80658 :     nEnd = r.nEnd;
    1046       80658 :     nStart = r.nStart;
    1047       80658 :     nEndPortion = r.nEndPortion;
    1048       80658 :     nStartPortion = r.nStartPortion;
    1049       80658 :     return *this;
    1050             : }
    1051             : 
    1052             : 
    1053           0 : bool operator != ( const EditLine& r1,  const EditLine& r2  )
    1054             : {
    1055           0 :     return !( r1 == r2 );
    1056             : }
    1057             : 
    1058      490589 : void EditLine::SetHeight( sal_uInt16 nH, sal_uInt16 nTxtH, sal_uInt16 nCrsrH )
    1059             : {
    1060      490589 :     nHeight = nH;
    1061      490589 :     nTxtHeight = ( nTxtH ? nTxtH : nH );
    1062      490589 :     nCrsrHeight = ( nCrsrH ? nCrsrH : nTxtHeight );
    1063      490589 : }
    1064             : 
    1065      468127 : void EditLine::SetStartPosX( long start )
    1066             : {
    1067      468127 :     if (start > 0)
    1068       32421 :         nStartPosX = start;
    1069             :     else
    1070      435706 :         nStartPosX = 0;
    1071      468127 : }
    1072             : 
    1073      224710 : Size EditLine::CalcTextSize( ParaPortion& rParaPortion )
    1074             : {
    1075      224710 :     Size aSz;
    1076      224710 :     Size aTmpSz;
    1077             :     TextPortion* pPortion;
    1078             : 
    1079             :     DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize before CreatePortions !" );
    1080             : 
    1081      456048 :     for ( sal_Int32 n = nStartPortion; n <= nEndPortion; n++ )
    1082             :     {
    1083      231338 :         pPortion = rParaPortion.GetTextPortions()[n];
    1084      231338 :         switch ( pPortion->GetKind() )
    1085             :         {
    1086             :             case PortionKind::TEXT:
    1087             :             case PortionKind::FIELD:
    1088             :             case PortionKind::HYPHENATOR:
    1089             :             {
    1090      231206 :                 aTmpSz = pPortion->GetSize();
    1091      231206 :                 aSz.Width() += aTmpSz.Width();
    1092      231206 :                 if ( aSz.Height() < aTmpSz.Height() )
    1093      224720 :                     aSz.Height() = aTmpSz.Height();
    1094             :             }
    1095      231206 :             break;
    1096             :             case PortionKind::TAB:
    1097             :             {
    1098          12 :                 aSz.Width() += pPortion->GetSize().Width();
    1099             :             }
    1100          12 :             break;
    1101         120 :             case PortionKind::LINEBREAK: break;
    1102             :         }
    1103             :     }
    1104             : 
    1105      224710 :     SetHeight( (sal_uInt16)aSz.Height() );
    1106      224710 :     return aSz;
    1107             : }
    1108             : 
    1109      506251 : EditLineList::EditLineList()
    1110             : {
    1111      506251 : }
    1112             : 
    1113     1007816 : EditLineList::~EditLineList()
    1114             : {
    1115      503908 :     Reset();
    1116      503908 : }
    1117             : 
    1118      563624 : void EditLineList::Reset()
    1119             : {
    1120      563624 :     maLines.clear();
    1121      563624 : }
    1122             : 
    1123           2 : void EditLineList::DeleteFromLine(sal_Int32 nDelFrom)
    1124             : {
    1125             :     DBG_ASSERT( nDelFrom <= ((sal_Int32)maLines.size() - 1), "DeleteFromLine: Out of range" );
    1126           2 :     LinesType::iterator it = maLines.begin();
    1127           2 :     std::advance(it, nDelFrom);
    1128           2 :     maLines.erase(it, maLines.end());
    1129           2 : }
    1130             : 
    1131         120 : sal_Int32 EditLineList::FindLine(sal_Int32 nChar, bool bInclEnd)
    1132             : {
    1133         120 :     sal_Int32 n = maLines.size();
    1134         159 :     for (sal_Int32 i = 0; i < n; ++i)
    1135             :     {
    1136         142 :         const EditLine& rLine = maLines[i];
    1137         224 :         if ( (bInclEnd && (rLine.GetEnd() >= nChar)) ||
    1138          82 :              (rLine.GetEnd() > nChar) )
    1139             :         {
    1140         103 :             return i;
    1141             :         }
    1142             :     }
    1143             : 
    1144             :     DBG_ASSERT( !bInclEnd, "Line not found: FindLine" );
    1145          17 :     return n - 1;
    1146             : }
    1147             : 
    1148     3700973 : sal_Int32 EditLineList::Count() const
    1149             : {
    1150     3700973 :     return maLines.size();
    1151             : }
    1152             : 
    1153       27621 : const EditLine* EditLineList::operator[](sal_Int32 nPos) const
    1154             : {
    1155       27621 :     return &maLines[nPos];
    1156             : }
    1157             : 
    1158     1696930 : EditLine* EditLineList::operator[](sal_Int32 nPos)
    1159             : {
    1160     1696930 :     return &maLines[nPos];
    1161             : }
    1162             : 
    1163      382159 : void EditLineList::Append(EditLine* p)
    1164             : {
    1165      382159 :     maLines.push_back(p);
    1166      382159 : }
    1167             : 
    1168       80526 : void EditLineList::Insert(sal_Int32 nPos, EditLine* p)
    1169             : {
    1170       80526 :     maLines.insert(maLines.begin()+nPos, p);
    1171       80526 : }
    1172             : 
    1173     2904065 : EditPaM::EditPaM() : pNode(NULL), nIndex(0) {}
    1174     2195209 : EditPaM::EditPaM(const EditPaM& r) : pNode(r.pNode), nIndex(r.nIndex) {}
    1175     2674056 : EditPaM::EditPaM(ContentNode* p, sal_Int32 n) : pNode(p), nIndex(n) {}
    1176             : 
    1177             : 
    1178             : 
    1179      144808 : void EditPaM::SetNode(ContentNode* p)
    1180             : {
    1181      144808 :     pNode = p;
    1182      144808 : }
    1183             : 
    1184           0 : bool EditPaM::DbgIsBuggy( EditDoc& rDoc )
    1185             : {
    1186           0 :     return !pNode ||
    1187           0 :            rDoc.GetPos( pNode ) >= rDoc.Count() ||
    1188           0 :            nIndex > pNode->Len();
    1189             : }
    1190             : 
    1191           0 : bool EditSelection::DbgIsBuggy( EditDoc& rDoc )
    1192             : {
    1193           0 :     return aStartPaM.DbgIsBuggy( rDoc ) || aEndPaM.DbgIsBuggy( rDoc );
    1194             : }
    1195             : 
    1196      266902 : EditSelection::EditSelection()
    1197             : {
    1198      266902 : }
    1199             : 
    1200      227458 : EditSelection::EditSelection( const EditPaM& rStartAndAnd )
    1201             : {
    1202             :     // could still be optimized!
    1203             :     // do no first call the Def-constructor from PaM!
    1204      227458 :     aStartPaM = rStartAndAnd;
    1205      227458 :     aEndPaM = rStartAndAnd;
    1206      227458 : }
    1207             : 
    1208      915942 : EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd )
    1209             : {
    1210             :     // could still be optimized!
    1211      915942 :     aStartPaM = rStart;
    1212      915942 :     aEndPaM = rEnd;
    1213      915942 : }
    1214             : 
    1215        3586 : EditSelection& EditSelection::operator = ( const EditPaM& rPaM )
    1216             : {
    1217        3586 :     aStartPaM = rPaM;
    1218        3586 :     aEndPaM = rPaM;
    1219        3586 :     return *this;
    1220             : }
    1221             : 
    1222      500711 : void EditSelection::Adjust( const EditDoc& rNodes )
    1223             : {
    1224             :     DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index out of range in Adjust(1)" );
    1225             :     DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index out of range in Adjust(2)" );
    1226             : 
    1227      500711 :     const ContentNode* pStartNode = aStartPaM.GetNode();
    1228      500711 :     const ContentNode* pEndNode = aEndPaM.GetNode();
    1229             : 
    1230      500711 :     sal_Int32 nStartNode = rNodes.GetPos( pStartNode );
    1231      500711 :     sal_Int32 nEndNode = rNodes.GetPos( pEndNode );
    1232             : 
    1233             :     DBG_ASSERT( nStartNode != SAL_MAX_INT32, "Node out of range in Adjust(1)" );
    1234             :     DBG_ASSERT( nEndNode != SAL_MAX_INT32, "Node out of range in Adjust(2)" );
    1235             : 
    1236      500711 :     const bool bSwap = ( nStartNode > nEndNode ) ||
    1237      487463 :                        ( ( nStartNode == nEndNode ) &&
    1238      988174 :                          ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) );
    1239             : 
    1240      500711 :     if ( bSwap )
    1241             :     {
    1242           0 :         EditPaM aTmpPaM( aStartPaM );
    1243           0 :         aStartPaM = aEndPaM;
    1244           0 :         aEndPaM = aTmpPaM;
    1245             :     }
    1246      500711 : }
    1247             : 
    1248      310086 : bool operator == ( const EditPaM& r1, const EditPaM& r2 )
    1249             : {
    1250      616549 :     return ( r1.GetNode() == r2.GetNode() ) &&
    1251      616549 :            ( r1.GetIndex() == r2.GetIndex() );
    1252             : }
    1253             : 
    1254     3396268 : EditPaM& EditPaM::operator = ( const EditPaM& rPaM )
    1255             : {
    1256     3396268 :     nIndex = rPaM.nIndex;
    1257     3396268 :     pNode = rPaM.pNode;
    1258     3396268 :     return *this;
    1259             : }
    1260             : 
    1261      310074 : bool operator != ( const EditPaM& r1, const EditPaM& r2 )
    1262             : {
    1263      310074 :     return !( r1 == r2 );
    1264             : }
    1265             : 
    1266      499814 : ContentNode::ContentNode( SfxItemPool& rPool ) : aContentAttribs( rPool )
    1267             : {
    1268      499814 : }
    1269             : 
    1270        6437 : ContentNode::ContentNode( const OUString& rStr, const ContentAttribs& rContentAttribs ) :
    1271        6437 :     maString(rStr), aContentAttribs(rContentAttribs)
    1272             : {
    1273        6437 : }
    1274             : 
    1275      503908 : ContentNode::~ContentNode()
    1276             : {
    1277      503908 : }
    1278             : 
    1279      274475 : void ContentNode::ExpandAttribs( sal_Int32 nIndex, sal_Int32 nNew, SfxItemPool& rItemPool )
    1280             : {
    1281      274475 :     if ( !nNew )
    1282      289631 :         return;
    1283             : 
    1284             : #if OSL_DEBUG_LEVEL > 0
    1285             :     CharAttribList::DbgCheckAttribs(aCharAttribList);
    1286             : #endif
    1287             : 
    1288             :     // Since features are treated differently than normal character attributes,
    1289             :     // can also the order of the start list be change!
    1290             :     // In every if ...,  in the next (n) opportunities due to bFeature or
    1291             :     // an existing special case, must (n-1) opportunities be provided with
    1292             :     // bResort. The most likely possibility receives no bResort, so that is
    1293             :     // not sorted anew when all attributes are the same.
    1294      259319 :     bool bResort = false;
    1295      259319 :     bool bExpandedEmptyAtIndexNull = false;
    1296             : 
    1297      259319 :     sal_Int32 nAttr = 0;
    1298      259319 :     CharAttribList::AttribsType& rAttribs = aCharAttribList.GetAttribs();
    1299      259319 :     EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
    1300      546628 :     while ( pAttrib )
    1301             :     {
    1302       27990 :         if ( pAttrib->GetEnd() >= nIndex )
    1303             :         {
    1304             :             // Move all attributes behind the insertion point...
    1305       26909 :             if ( pAttrib->GetStart() > nIndex )
    1306             :             {
    1307        1839 :                 pAttrib->MoveForward( nNew );
    1308             :             }
    1309             :             // 0: Expand empty attribute, if at insertion point
    1310       25070 :             else if ( pAttrib->IsEmpty() )
    1311             :             {
    1312             :                 // Do not check Index, a empty one could only be there
    1313             :                 // When later checking it anyhow:
    1314             :                 //   Special caase: Start == 0; AbsLen == 1, nNew = 1
    1315             :                 // => Expand, because of paragraph break!
    1316             :                 // Start <= nIndex, End >= nIndex => Start=End=nIndex!
    1317             : //              if ( pAttrib->GetStart() == nIndex )
    1318       16924 :                 pAttrib->Expand( nNew );
    1319       16924 :                 bResort = true;
    1320       16924 :                 if ( pAttrib->GetStart() == 0 )
    1321       16857 :                     bExpandedEmptyAtIndexNull = true;
    1322             :             }
    1323             :             // 1: Attribute starts before, goes to index ...
    1324        8146 :             else if ( pAttrib->GetEnd() == nIndex ) // Start must be before
    1325             :             {
    1326             :                 // Only expand when there is no feature
    1327             :                 // and if not in exclude list!
    1328             :                 // Otherwise, a UL will go on until a new ULDB, expaning both
    1329             : //              if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( pAttrib->Which() ) )
    1330        8116 :                 if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
    1331             :                 {
    1332        7320 :                     if ( !pAttrib->IsEdge() )
    1333        7320 :                         pAttrib->Expand( nNew );
    1334             :                 }
    1335             :                 else
    1336         796 :                     bResort = true;
    1337             :             }
    1338             :             // 2: Attribute starts before, goes past the Index...
    1339          30 :             else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
    1340             :             {
    1341             :                 DBG_ASSERT( !pAttrib->IsFeature(), "Large Feature?!" );
    1342           0 :                 pAttrib->Expand( nNew );
    1343             :             }
    1344             :             // 3: Attribute starts on index...
    1345          30 :             else if ( pAttrib->GetStart() == nIndex )
    1346             :             {
    1347          30 :                 if ( pAttrib->IsFeature() )
    1348             :                 {
    1349           3 :                     pAttrib->MoveForward( nNew );
    1350           3 :                     bResort = true;
    1351             :                 }
    1352             :                 else
    1353             :                 {
    1354          27 :                     bool bExpand = false;
    1355          27 :                     if ( nIndex == 0 )
    1356             :                     {
    1357          27 :                         bExpand = true;
    1358          27 :                         if( bExpandedEmptyAtIndexNull )
    1359             :                         {
    1360             :                             // Check if this kind of attribute was empty and expanded here...
    1361           0 :                             sal_uInt16 nW = pAttrib->GetItem()->Which();
    1362           0 :                             for ( sal_Int32 nA = 0; nA < nAttr; nA++ )
    1363             :                             {
    1364           0 :                                 const EditCharAttrib& r = aCharAttribList.GetAttribs()[nA];
    1365           0 :                                 if ( ( r.GetStart() == 0 ) && ( r.GetItem()->Which() == nW ) )
    1366             :                                 {
    1367           0 :                                     bExpand = false;
    1368           0 :                                     break;
    1369             :                                 }
    1370             :                             }
    1371             : 
    1372             :                         }
    1373             :                     }
    1374          27 :                     if ( bExpand )
    1375             :                     {
    1376          27 :                         pAttrib->Expand( nNew );
    1377          27 :                         bResort = true;
    1378             :                     }
    1379             :                     else
    1380             :                     {
    1381           0 :                         pAttrib->MoveForward( nNew );
    1382             :                     }
    1383             :                 }
    1384             :             }
    1385             :         }
    1386             : 
    1387       27990 :         if ( pAttrib->IsEdge() )
    1388           0 :             pAttrib->SetEdge(false);
    1389             : 
    1390             :         DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" );
    1391             : 
    1392             :         DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribute distorted!" );
    1393             :         DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attribute larger than paragraph!" );
    1394       27990 :         if ( pAttrib->IsEmpty() )
    1395             :         {
    1396             :             OSL_FAIL( "Empty Attribute after ExpandAttribs?" );
    1397           0 :             bResort = true;
    1398           0 :             rItemPool.Remove( *pAttrib->GetItem() );
    1399           0 :             rAttribs.erase(rAttribs.begin()+nAttr);
    1400           0 :             --nAttr;
    1401             :         }
    1402       27990 :         ++nAttr;
    1403       27990 :         pAttrib = GetAttrib(rAttribs, nAttr);
    1404             :     }
    1405             : 
    1406      259319 :     if ( bResort )
    1407        1831 :         aCharAttribList.ResortAttribs();
    1408             : 
    1409      259319 :     if (mpWrongList)
    1410             :     {
    1411       58973 :         bool bSep = ( maString[ nIndex ] == ' ' ) || IsFeature( nIndex );
    1412       58973 :         mpWrongList->TextInserted( nIndex, nNew, bSep );
    1413             :     }
    1414             : 
    1415             : #if OSL_DEBUG_LEVEL > 0
    1416             :     CharAttribList::DbgCheckAttribs(aCharAttribList);
    1417             : #endif
    1418             : }
    1419             : 
    1420        5823 : void ContentNode::CollapsAttribs( sal_Int32 nIndex, sal_Int32 nDeleted, SfxItemPool& rItemPool )
    1421             : {
    1422        5823 :     if ( !nDeleted )
    1423       10662 :         return;
    1424             : 
    1425             : #if OSL_DEBUG_LEVEL > 0
    1426             :     CharAttribList::DbgCheckAttribs(aCharAttribList);
    1427             : #endif
    1428             : 
    1429             :     // Since features are treated differently than normal character attributes,
    1430             :     // can also the order of the start list be change!
    1431         984 :     bool bResort = false;
    1432         984 :     sal_Int32 nEndChanges = nIndex+nDeleted;
    1433             : 
    1434         984 :     sal_Int32 nAttr = 0;
    1435         984 :     CharAttribList::AttribsType& rAttribs = aCharAttribList.GetAttribs();
    1436         984 :     EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
    1437        3284 :     while ( pAttrib )
    1438             :     {
    1439        1316 :         bool bDelAttr = false;
    1440        1316 :         if ( pAttrib->GetEnd() >= nIndex )
    1441             :         {
    1442             :             // Move all Attribute behind the insert point...
    1443        1316 :             if ( pAttrib->GetStart() >= nEndChanges )
    1444             :             {
    1445         191 :                 pAttrib->MoveBackward( nDeleted );
    1446             :             }
    1447             :             // 1. Delete Internal attributes...
    1448        1125 :             else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
    1449             :             {
    1450             :                 // Special case: Attribute covers the area exactly
    1451             :                 // => keep as empty Attribute.
    1452         797 :                 if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
    1453             :                 {
    1454          84 :                     pAttrib->GetEnd() = nIndex; // empty
    1455          84 :                     bResort = true;
    1456             :                 }
    1457             :                 else
    1458         713 :                     bDelAttr = true;
    1459             :             }
    1460             :             // 2. Attribute starts earlier, ends inside or behind it ...
    1461         328 :             else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
    1462             :             {
    1463             :                 DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" );
    1464         295 :                 if ( pAttrib->GetEnd() <= nEndChanges ) // ends inside
    1465           9 :                     pAttrib->GetEnd() = nIndex;
    1466             :                 else
    1467         286 :                     pAttrib->Collaps( nDeleted );       // ends behind
    1468             :             }
    1469             :             // 3. Attribute starts inside, ending behind ...
    1470          33 :             else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) )
    1471             :             {
    1472             :                 // Features not allowed to expand!
    1473          15 :                 if ( pAttrib->IsFeature() )
    1474             :                 {
    1475           0 :                     pAttrib->MoveBackward( nDeleted );
    1476           0 :                     bResort = true;
    1477             :                 }
    1478             :                 else
    1479             :                 {
    1480          15 :                     pAttrib->GetStart() = nEndChanges;
    1481          15 :                     pAttrib->MoveBackward( nDeleted );
    1482             :                 }
    1483             :             }
    1484             :         }
    1485             :         DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" );
    1486             : 
    1487             :         DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut distorted!" );
    1488             :         DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collaps: Attribute larger than paragraph!" );
    1489        1316 :         if ( bDelAttr )
    1490             :         {
    1491         713 :             bResort = true;
    1492         713 :             rItemPool.Remove( *pAttrib->GetItem() );
    1493         713 :             rAttribs.erase(rAttribs.begin()+nAttr);
    1494         713 :             nAttr--;
    1495             :         }
    1496         603 :         else if ( pAttrib->IsEmpty() )
    1497          84 :             aCharAttribList.SetHasEmptyAttribs(true);
    1498             : 
    1499        1316 :         nAttr++;
    1500        1316 :         pAttrib = GetAttrib(rAttribs, nAttr);
    1501             :     }
    1502             : 
    1503         984 :     if ( bResort )
    1504         630 :         aCharAttribList.ResortAttribs();
    1505             : 
    1506         984 :     if (mpWrongList)
    1507          84 :         mpWrongList->TextDeleted(nIndex, nDeleted);
    1508             : 
    1509             : #if OSL_DEBUG_LEVEL > 0
    1510             :     CharAttribList::DbgCheckAttribs(aCharAttribList);
    1511             : #endif
    1512             : }
    1513             : 
    1514        6437 : void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, bool bKeepEndingAttribs )
    1515             : {
    1516             :     DBG_ASSERT( pPrevNode, "Copy of attributes to a null pointer?" );
    1517             : 
    1518             : #if OSL_DEBUG_LEVEL > 0
    1519             :     CharAttribList::DbgCheckAttribs(aCharAttribList);
    1520             :     CharAttribList::DbgCheckAttribs(pPrevNode->aCharAttribList);
    1521             : #endif
    1522             : 
    1523        6437 :     sal_Int32 nCut = pPrevNode->Len();
    1524             : 
    1525        6437 :     sal_Int32 nAttr = 0;
    1526        6437 :     CharAttribList::AttribsType& rPrevAttribs = pPrevNode->GetCharAttribs().GetAttribs();
    1527        6437 :     EditCharAttrib* pAttrib = GetAttrib(rPrevAttribs, nAttr);
    1528       25405 :     while ( pAttrib )
    1529             :     {
    1530       12531 :         if ( pAttrib->GetEnd() < nCut )
    1531             :         {
    1532             :             // remain unchanged ....
    1533             :             ;
    1534             :         }
    1535       11327 :         else if ( pAttrib->GetEnd() == nCut )
    1536             :         {
    1537             :             // must be copied as an empty attributes.
    1538       11326 :             if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) )
    1539             :             {
    1540       10157 :                 EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 );
    1541             :                 DBG_ASSERT( pNewAttrib, "MakeCharAttrib failed!" );
    1542       10157 :                 aCharAttribList.InsertAttrib( pNewAttrib );
    1543             :             }
    1544             :         }
    1545           1 :         else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() && !pAttrib->IsFeature() ) )
    1546             :         {
    1547             :             // If cut is done right at the front then the attribute must be
    1548             :             // kept! Has to be copied and changed.
    1549           0 :             EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut );
    1550             :             DBG_ASSERT( pNewAttrib, "MakeCharAttrib failed!" );
    1551           0 :             aCharAttribList.InsertAttrib( pNewAttrib );
    1552           0 :             pAttrib->GetEnd() = nCut;
    1553             :         }
    1554             :         else
    1555             :         {
    1556             :             // Move all attributes in the current node (this)
    1557           1 :             CharAttribList::AttribsType::iterator it = rPrevAttribs.begin() + nAttr;
    1558           1 :             aCharAttribList.InsertAttrib(rPrevAttribs.release(it).release());
    1559           1 :             pAttrib->MoveBackward( nCut );
    1560           1 :             nAttr--;
    1561             :         }
    1562       12531 :         nAttr++;
    1563       12531 :         pAttrib = GetAttrib(rPrevAttribs, nAttr);
    1564             :     }
    1565             : 
    1566             : #if OSL_DEBUG_LEVEL > 0
    1567             :     CharAttribList::DbgCheckAttribs(aCharAttribList);
    1568             :     CharAttribList::DbgCheckAttribs(pPrevNode->aCharAttribList);
    1569             : #endif
    1570        6437 : }
    1571             : 
    1572        2429 : void ContentNode::AppendAttribs( ContentNode* pNextNode )
    1573             : {
    1574             :     DBG_ASSERT( pNextNode, "Copy of attributes to a null pointer?" );
    1575             : 
    1576        2429 :     sal_Int32 nNewStart = maString.getLength();
    1577             : 
    1578             : #if OSL_DEBUG_LEVEL > 0
    1579             :     CharAttribList::DbgCheckAttribs(aCharAttribList);
    1580             :     CharAttribList::DbgCheckAttribs(pNextNode->aCharAttribList);
    1581             : #endif
    1582             : 
    1583        2429 :     sal_Int32 nAttr = 0;
    1584        2429 :     CharAttribList::AttribsType& rNextAttribs = pNextNode->GetCharAttribs().GetAttribs();
    1585        2429 :     EditCharAttrib* pAttrib = GetAttrib(rNextAttribs, nAttr);
    1586        5178 :     while ( pAttrib )
    1587             :     {
    1588             :         // Move all attributes in the current node (this)
    1589         320 :         bool bMelted = false;
    1590         320 :         if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) )
    1591             :         {
    1592             :             // Attributes can possibly be summarized as:
    1593         320 :             sal_Int32 nTmpAttr = 0;
    1594         320 :             EditCharAttrib* pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr );
    1595        1110 :             while ( !bMelted && pTmpAttrib )
    1596             :             {
    1597         470 :                 if ( pTmpAttrib->GetEnd() == nNewStart )
    1598             :                 {
    1599         470 :                     if (pTmpAttrib->Which() == pAttrib->Which())
    1600             :                     {
    1601             :                         // prevent adding 2 0-length attributes at same position
    1602         630 :                         if ((*(pTmpAttrib->GetItem()) == *(pAttrib->GetItem()))
    1603         315 :                                 || (0 == pAttrib->GetLen()))
    1604             :                         {
    1605         315 :                             pTmpAttrib->GetEnd() =
    1606         315 :                                 pTmpAttrib->GetEnd() + pAttrib->GetLen();
    1607         315 :                             rNextAttribs.erase(rNextAttribs.begin()+nAttr);
    1608             :                             // Unsubscribe from the pool?!
    1609         315 :                             bMelted = true;
    1610             :                         }
    1611           0 :                         else if (0 == pTmpAttrib->GetLen())
    1612             :                         {
    1613           0 :                             aCharAttribList.Remove(nTmpAttr);
    1614           0 :                             --nTmpAttr; // to cancel later increment...
    1615             :                         }
    1616             :                     }
    1617             :                 }
    1618         470 :                 ++nTmpAttr;
    1619         470 :                 pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr );
    1620             :             }
    1621             :         }
    1622             : 
    1623         320 :         if ( !bMelted )
    1624             :         {
    1625           5 :             pAttrib->GetStart() = pAttrib->GetStart() + nNewStart;
    1626           5 :             pAttrib->GetEnd() = pAttrib->GetEnd() + nNewStart;
    1627           5 :             CharAttribList::AttribsType::iterator it = rNextAttribs.begin() + nAttr;
    1628           5 :             aCharAttribList.InsertAttrib(rNextAttribs.release(it).release());
    1629             :         }
    1630         320 :         pAttrib = GetAttrib(rNextAttribs, nAttr);
    1631             :     }
    1632             :     // For the Attributes that just moved over:
    1633        2429 :     rNextAttribs.clear();
    1634             : 
    1635             : #if OSL_DEBUG_LEVEL > 0
    1636             :     CharAttribList::DbgCheckAttribs(aCharAttribList);
    1637             :     CharAttribList::DbgCheckAttribs(pNextNode->aCharAttribList);
    1638             : #endif
    1639        2429 : }
    1640             : 
    1641      623220 : void ContentNode::CreateDefFont()
    1642             : {
    1643             :     // First use the information from the style ...
    1644      623220 :     SfxStyleSheet* pS = aContentAttribs.GetStyleSheet();
    1645      623220 :     if ( pS )
    1646      139741 :         CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() );
    1647             : 
    1648             :     // ... then iron out the hard paragraph formatting...
    1649      623220 :     CreateFont( GetCharAttribs().GetDefFont(),
    1650     1246440 :         GetContentAttribs().GetItems(), pS == NULL );
    1651      623220 : }
    1652             : 
    1653           0 : void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle )
    1654             : {
    1655           0 :     aContentAttribs.SetStyleSheet( pS );
    1656             : 
    1657             : 
    1658             :     // First use the information from the style ...
    1659           0 :     GetCharAttribs().GetDefFont() = rFontFromStyle;
    1660             :     // ... then iron out the hard paragraph formatting...
    1661           0 :     CreateFont( GetCharAttribs().GetDefFont(),
    1662           0 :         GetContentAttribs().GetItems(), pS == NULL );
    1663           0 : }
    1664             : 
    1665      294501 : void ContentNode::SetStyleSheet( SfxStyleSheet* pS, bool bRecalcFont )
    1666             : {
    1667      294501 :     aContentAttribs.SetStyleSheet( pS );
    1668      294501 :     if ( bRecalcFont )
    1669       67065 :         CreateDefFont();
    1670      294501 : }
    1671             : 
    1672       58828 : bool ContentNode::IsFeature( sal_Int32 nPos ) const
    1673             : {
    1674       58828 :     return maString[nPos] == CH_FEATURE;
    1675             : }
    1676             : 
    1677     9167717 : sal_Int32 ContentNode::Len() const
    1678             : {
    1679     9167717 :     return maString.getLength();
    1680             : }
    1681             : 
    1682        1644 : sal_uLong ContentNode::GetExpandedLen() const
    1683             : {
    1684        1644 :     sal_uLong nLen = maString.getLength();
    1685             : 
    1686             :     // Fields can be longer than the placeholder in the Node
    1687        1644 :     const CharAttribList::AttribsType& rAttrs = GetCharAttribs().GetAttribs();
    1688       19669 :     for (sal_Int32 nAttr = rAttrs.size(); nAttr; )
    1689             :     {
    1690       16381 :         const EditCharAttrib& rAttr = rAttrs[--nAttr];
    1691       16381 :         if (rAttr.Which() == EE_FEATURE_FIELD)
    1692             :         {
    1693          27 :             nLen += static_cast<const EditCharAttribField&>(rAttr).GetFieldValue().getLength();
    1694          27 :             --nLen; // Standalone, to avoid corner cases when previous getLength() returns 0
    1695             :         }
    1696             :     }
    1697             : 
    1698        1644 :     return nLen;
    1699             : }
    1700             : 
    1701       36299 : OUString ContentNode::GetExpandedText(sal_Int32 nStartPos, sal_Int32 nEndPos, bool bResolveFields) const
    1702             : {
    1703       36299 :     if ( nEndPos < 0 || nEndPos > Len() )
    1704       31048 :         nEndPos = Len();
    1705             : 
    1706             :     DBG_ASSERT( nStartPos <= nEndPos, "Start and End reversed?" );
    1707             : 
    1708       36299 :     sal_Int32 nIndex = nStartPos;
    1709       36299 :     OUString aStr;
    1710       36299 :     const EditCharAttrib* pNextFeature = GetCharAttribs().FindFeature( nIndex );
    1711       80868 :     while ( nIndex < nEndPos )
    1712             :     {
    1713        8270 :         sal_Int32 nEnd = nEndPos;
    1714        8270 :         if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) )
    1715        1339 :             nEnd = pNextFeature->GetStart();
    1716             :         else
    1717        6931 :             pNextFeature = 0;   // Feature does not interest the below
    1718             : 
    1719             :         DBG_ASSERT( nEnd >= nIndex, "End in front of the index?" );
    1720             :         //!! beware of sub string length  of -1
    1721        8270 :         if (nEnd > nIndex)
    1722        7117 :             aStr += GetString().copy(nIndex, nEnd - nIndex);
    1723             : 
    1724        8270 :         if ( pNextFeature )
    1725             :         {
    1726        1339 :             switch ( pNextFeature->GetItem()->Which() )
    1727             :             {
    1728           0 :                 case EE_FEATURE_TAB:    aStr += "\t";
    1729           0 :                 break;
    1730          28 :                 case EE_FEATURE_LINEBR: aStr += "\x0A";
    1731          28 :                 break;
    1732             :                 case EE_FEATURE_FIELD:
    1733        1311 :                     if ( bResolveFields )
    1734        1311 :                         aStr += static_cast<const EditCharAttribField*>(pNextFeature)->GetFieldValue();
    1735        1311 :                 break;
    1736             :                 default:    OSL_FAIL( "What feature?" );
    1737             :             }
    1738        1339 :             pNextFeature = GetCharAttribs().FindFeature( ++nEnd );
    1739             :         }
    1740        8270 :         nIndex = nEnd;
    1741             :     }
    1742       36299 :     return aStr;
    1743             : }
    1744             : 
    1745         166 : void ContentNode::UnExpandPosition( sal_Int32 &rPos, bool bBiasStart )
    1746             : {
    1747         166 :     sal_Int32 nOffset = 0;
    1748             : 
    1749         166 :     const CharAttribList::AttribsType& rAttrs = GetCharAttribs().GetAttribs();
    1750         242 :     for (size_t nAttr = 0; nAttr < rAttrs.size(); ++nAttr )
    1751             :     {
    1752         158 :         const EditCharAttrib& rAttr = rAttrs[nAttr];
    1753             :         assert (!(nAttr < rAttrs.size() - 1) ||
    1754             :                 rAttrs[nAttr].GetStart() <= rAttrs[nAttr + 1].GetStart());
    1755             : 
    1756         158 :         nOffset = rAttr.GetStart();
    1757             : 
    1758         158 :         if (nOffset >= rPos) // happens after the position
    1759          59 :             return;
    1760             : 
    1761          99 :         sal_Int32 nChunk = 0;
    1762          99 :         if (rAttr.Which() == EE_FEATURE_FIELD)
    1763             :         {
    1764          93 :             nChunk += static_cast<const EditCharAttribField&>(rAttr).GetFieldValue().getLength();
    1765          93 :             nChunk--; // Character representing the field in the string
    1766             : 
    1767          93 :             if (nOffset + nChunk >= rPos) // we're inside the field
    1768             :             {
    1769          23 :                 if (bBiasStart)
    1770          11 :                     rPos = rAttr.GetStart();
    1771             :                 else
    1772          12 :                     rPos = rAttr.GetEnd();
    1773          23 :                 return;
    1774             :             }
    1775             :             // Adjust for the position
    1776          70 :             rPos -= nChunk;
    1777             :         }
    1778             :     }
    1779             :     assert (rPos <= Len());
    1780             : }
    1781             : 
    1782             : /*
    1783             :  * Fields are represented by a single character in the underlying string
    1784             :  * and/or selection, however, they can be expanded to the full value of
    1785             :  * the field. When we're dealing with selection / offsets however we need
    1786             :  * to deal in character positions inside the real (unexpanded) string.
    1787             :  * This method maps us back to character offsets.
    1788             :  */
    1789          83 : void ContentNode::UnExpandPositions( sal_Int32 &rStartPos, sal_Int32 &rEndPos )
    1790             : {
    1791          83 :     UnExpandPosition( rStartPos, true );
    1792          83 :     UnExpandPosition( rEndPos, false );
    1793          83 : }
    1794             : 
    1795           0 : void ContentNode::SetChar(sal_Int32 nPos, sal_Unicode c)
    1796             : {
    1797           0 :     maString = maString.replaceAt(nPos, 1, OUString(c));
    1798           0 : }
    1799             : 
    1800      274475 : void ContentNode::Insert(const OUString& rStr, sal_Int32 nPos)
    1801             : {
    1802      274475 :     maString = maString.replaceAt(nPos, 0, rStr);
    1803      274475 : }
    1804             : 
    1805        2429 : void ContentNode::Append(const OUString& rStr)
    1806             : {
    1807        2429 :     maString += rStr;
    1808        2429 : }
    1809             : 
    1810        6437 : void ContentNode::Erase(sal_Int32 nPos)
    1811             : {
    1812        6437 :     maString = maString.copy(0, nPos);
    1813        6437 : }
    1814             : 
    1815        5823 : void ContentNode::Erase(sal_Int32 nPos, sal_Int32 nCount)
    1816             : {
    1817        5823 :     maString = maString.replaceAt(nPos, nCount, "");
    1818        5823 : }
    1819             : 
    1820        6437 : OUString ContentNode::Copy(sal_Int32 nPos) const
    1821             : {
    1822        6437 :     return maString.copy(nPos);
    1823             : }
    1824             : 
    1825      139478 : OUString ContentNode::Copy(sal_Int32 nPos, sal_Int32 nCount) const
    1826             : {
    1827      139478 :     return maString.copy(nPos, nCount);
    1828             : }
    1829             : 
    1830      204347 : sal_Unicode ContentNode::GetChar(sal_Int32 nPos) const
    1831             : {
    1832      204347 :     return maString[nPos];
    1833             : }
    1834             : 
    1835         985 : void ContentNode::EnsureWrongList()
    1836             : {
    1837         985 :     if (!mpWrongList)
    1838           0 :         CreateWrongList();
    1839         985 : }
    1840             : 
    1841      191700 : WrongList* ContentNode::GetWrongList()
    1842             : {
    1843      191700 :     return mpWrongList.get();
    1844             : }
    1845             : 
    1846           5 : const WrongList* ContentNode::GetWrongList() const
    1847             : {
    1848           5 :     return mpWrongList.get();
    1849             : }
    1850             : 
    1851       48864 : void ContentNode::SetWrongList( WrongList* p )
    1852             : {
    1853       48864 :     mpWrongList.reset(p);
    1854       48864 : }
    1855             : 
    1856      116675 : void ContentNode::CreateWrongList()
    1857             : {
    1858             :     SAL_WARN_IF( mpWrongList && !mpWrongList->empty(), "editeng", "WrongList already exist!");
    1859      116675 :     if (!mpWrongList || !mpWrongList->empty())
    1860      116529 :         mpWrongList.reset(new WrongList);
    1861      116675 : }
    1862             : 
    1863         229 : void ContentNode::DestroyWrongList()
    1864             : {
    1865         229 :     mpWrongList.reset();
    1866         229 : }
    1867             : 
    1868      499814 : ContentAttribs::ContentAttribs( SfxItemPool& rPool )
    1869             : : pStyle(0)
    1870      499814 : , aAttribSet( rPool, EE_PARA_START, EE_CHAR_END )
    1871             : {
    1872      499814 : }
    1873             : 
    1874       12874 : ContentAttribs::ContentAttribs( const ContentAttribs& rRef )
    1875             : : pStyle(rRef.pStyle)
    1876       12874 : , aAttribSet( rRef.aAttribSet )
    1877             : {
    1878       12874 : }
    1879             : 
    1880      510345 : ContentAttribs::~ContentAttribs()
    1881             : {
    1882      510345 : }
    1883             : 
    1884          12 : SvxTabStop ContentAttribs::FindTabStop( sal_Int32 nCurPos, sal_uInt16 nDefTab )
    1885             : {
    1886          12 :     const SvxTabStopItem& rTabs = static_cast<const SvxTabStopItem&>( GetItem( EE_PARA_TABS ) );
    1887          21 :     for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ )
    1888             :     {
    1889          14 :         const SvxTabStop& rTab = rTabs[i];
    1890          14 :         if ( rTab.GetTabPos() > nCurPos  )
    1891           5 :             return rTab;
    1892             :     }
    1893             : 
    1894             :     // Determine DefTab ...
    1895           7 :     SvxTabStop aTabStop;
    1896           7 :     const sal_Int32 x = nCurPos / nDefTab + 1;
    1897           7 :     aTabStop.GetTabPos() = nDefTab * x;
    1898           7 :     return aTabStop;
    1899             : }
    1900             : 
    1901      294501 : void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS )
    1902             : {
    1903      294501 :     bool bStyleChanged = ( pStyle != pS );
    1904      294501 :     pStyle = pS;
    1905             :     // Only when other style sheet, not when current style sheet modified
    1906      294501 :     if ( pStyle && bStyleChanged )
    1907             :     {
    1908             :         // Selectively remove the attributes from the paragraph formatting
    1909             :         // which are specified in the style, so that the attributes of the
    1910             :         // style can have an affect.
    1911       67065 :         const SfxItemSet& rStyleAttribs = pStyle->GetItemSet();
    1912     3487380 :         for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
    1913             :         {
    1914             :             // Don't change bullet on/off
    1915     3420315 :             if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SfxItemState::SET ) )
    1916     1597794 :                 aAttribSet.ClearItem( nWhich );
    1917             :         }
    1918             :     }
    1919      294501 : }
    1920             : 
    1921     6683636 : const SfxPoolItem& ContentAttribs::GetItem( sal_uInt16 nWhich ) const
    1922             : {
    1923             :     // Hard paragraph attributes take precedence!
    1924     6683636 :     const SfxItemSet* pTakeFrom = &aAttribSet;
    1925     6683636 :     if ( pStyle && ( aAttribSet.GetItemState( nWhich, false ) != SfxItemState::SET  ) )
    1926     1005880 :         pTakeFrom = &pStyle->GetItemSet();
    1927             : 
    1928     6683636 :     return pTakeFrom->Get( nWhich );
    1929             : }
    1930             : 
    1931       14405 : bool ContentAttribs::HasItem( sal_uInt16 nWhich ) const
    1932             : {
    1933       14405 :     bool bHasItem = false;
    1934       14405 :     if ( aAttribSet.GetItemState( nWhich, false ) == SfxItemState::SET  )
    1935           0 :         bHasItem = true;
    1936       14405 :     else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SfxItemState::SET )
    1937           0 :         bHasItem = true;
    1938             : 
    1939       14405 :     return bHasItem;
    1940             : }
    1941             : 
    1942             : 
    1943           0 : ItemList::ItemList() : CurrentItem( 0 )
    1944             : {
    1945           0 : }
    1946             : 
    1947           0 : const SfxPoolItem* ItemList::First()
    1948             : {
    1949           0 :     CurrentItem = 0;
    1950           0 :     return aItemPool.empty() ? NULL : aItemPool[ 0 ];
    1951             : }
    1952             : 
    1953           0 : const SfxPoolItem* ItemList::Next()
    1954             : {
    1955           0 :     if ( CurrentItem + 1 < (sal_Int32)aItemPool.size() )
    1956             :     {
    1957           0 :         ++CurrentItem;
    1958           0 :         return aItemPool[ CurrentItem ];
    1959             :     }
    1960           0 :     return NULL;
    1961             : }
    1962             : 
    1963           0 : void ItemList::Insert( const SfxPoolItem* pItem )
    1964             : {
    1965           0 :     aItemPool.push_back( pItem );
    1966           0 :     CurrentItem = aItemPool.size() - 1;
    1967           0 : }
    1968             : 
    1969             : 
    1970       42102 : EditDoc::EditDoc( SfxItemPool* pPool ) :
    1971             :     nLastCache(0),
    1972          22 :     pItemPool(pPool ? pPool : new EditEngineItemPool(false)),
    1973             :     nDefTab(DEFTAB),
    1974             :     bIsVertical(false),
    1975             :     bIsFixedCellHeight(false),
    1976       42102 :     bOwnerOfPool(pPool == nullptr),
    1977       84226 :     bModified(false)
    1978             : {
    1979             :     // Don't create a empty node, Clear() will be called in EditEngine-CTOR
    1980       42102 : };
    1981             : 
    1982       79542 : EditDoc::~EditDoc()
    1983             : {
    1984       39771 :     ImplDestroyContents();
    1985       39771 :     if ( bOwnerOfPool )
    1986          21 :         SfxItemPool::Free(pItemPool);
    1987       39771 : }
    1988             : 
    1989             : namespace {
    1990             : 
    1991             : class RemoveEachItemFromPool : std::unary_function<ContentNode, void>
    1992             : {
    1993             :     EditDoc& mrDoc;
    1994             : public:
    1995      527168 :     RemoveEachItemFromPool(EditDoc& rDoc) : mrDoc(rDoc) {}
    1996      501463 :     void operator() (const ContentNode& rNode)
    1997             :     {
    1998      501463 :         mrDoc.RemoveItemsFromPool(rNode);
    1999      501463 :     }
    2000             : };
    2001             : 
    2002             : struct ClearSpellErrorsHandler : std::unary_function<ContentNode, void>
    2003             : {
    2004           0 :     void operator() (ContentNode& rNode)
    2005             :     {
    2006           0 :         rNode.DestroyWrongList();
    2007           0 :     }
    2008             : };
    2009             : 
    2010             : }
    2011             : 
    2012      527168 : void EditDoc::ImplDestroyContents()
    2013             : {
    2014      527168 :     std::for_each(maContents.begin(), maContents.end(), RemoveEachItemFromPool(*this));
    2015      527168 :     maContents.clear();
    2016      527168 : }
    2017             : 
    2018      503892 : void EditDoc::RemoveItemsFromPool(const ContentNode& rNode)
    2019             : {
    2020      702226 :     for (sal_Int32 nAttr = 0; nAttr < rNode.GetCharAttribs().Count(); ++nAttr)
    2021             :     {
    2022      198334 :         const EditCharAttrib& rAttr = rNode.GetCharAttribs().GetAttribs()[nAttr];
    2023      198334 :         GetItemPool().Remove(*rAttr.GetItem());
    2024             :     }
    2025      503892 : }
    2026             : 
    2027     1026502 : void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent, SvtScriptType nScriptType )
    2028             : {
    2029     1026502 :     vcl::Font aPrevFont( rFont );
    2030     1026502 :     rFont.SetAlign( ALIGN_BASELINE );
    2031     1026502 :     rFont.SetTransparent( true );
    2032             : 
    2033     1026502 :     sal_uInt16 nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
    2034     1026502 :     sal_uInt16 nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType );
    2035     1026502 :     sal_uInt16 nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType );
    2036     1026502 :     sal_uInt16 nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType );
    2037     1026502 :     sal_uInt16 nWhich_Italic = GetScriptItemId( EE_CHAR_ITALIC, nScriptType );
    2038             : 
    2039     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontInfo ) == SfxItemState::SET ) )
    2040             :     {
    2041      887076 :         const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>(rSet.Get( nWhich_FontInfo ));
    2042      887076 :         rFont.SetName( rFontItem.GetFamilyName() );
    2043      887076 :         rFont.SetFamily( rFontItem.GetFamily() );
    2044      887076 :         rFont.SetPitch( rFontItem.GetPitch() );
    2045      887076 :         rFont.SetCharSet( rFontItem.GetCharSet() );
    2046             :     }
    2047     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( nWhich_Language ) == SfxItemState::SET ) )
    2048      886972 :         rFont.SetLanguage( static_cast<const SvxLanguageItem&>(rSet.Get( nWhich_Language )).GetLanguage() );
    2049     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_COLOR ) == SfxItemState::SET ) )
    2050      886979 :         rFont.SetColor( static_cast<const SvxColorItem&>(rSet.Get( EE_CHAR_COLOR )).GetValue() );
    2051     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_BKGCOLOR ) == SfxItemState::SET ) )
    2052      887017 :         rFont.SetFillColor( static_cast<const SvxBackgroundColorItem&>(rSet.Get( EE_CHAR_BKGCOLOR )).GetValue() );
    2053     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontHeight ) == SfxItemState::SET ) )
    2054      898140 :         rFont.SetSize( Size( rFont.GetSize().Width(), static_cast<const SvxFontHeightItem&>(rSet.Get( nWhich_FontHeight ) ).GetHeight() ) );
    2055     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( nWhich_Weight ) == SfxItemState::SET ) )
    2056      887010 :         rFont.SetWeight( static_cast<const SvxWeightItem&>(rSet.Get( nWhich_Weight )).GetWeight() );
    2057     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_UNDERLINE ) == SfxItemState::SET ) )
    2058      887077 :         rFont.SetUnderline( static_cast<const SvxUnderlineItem&>(rSet.Get( EE_CHAR_UNDERLINE )).GetLineStyle() );
    2059     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OVERLINE ) == SfxItemState::SET ) )
    2060      887080 :         rFont.SetOverline( static_cast<const SvxOverlineItem&>(rSet.Get( EE_CHAR_OVERLINE )).GetLineStyle() );
    2061     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_STRIKEOUT ) == SfxItemState::SET ) )
    2062      887090 :         rFont.SetStrikeout( static_cast<const SvxCrossedOutItem&>(rSet.Get( EE_CHAR_STRIKEOUT )).GetStrikeout() );
    2063     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_CASEMAP ) == SfxItemState::SET ) )
    2064      886999 :         rFont.SetCaseMap( static_cast<const SvxCaseMapItem&>(rSet.Get( EE_CHAR_CASEMAP )).GetCaseMap() );
    2065     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( nWhich_Italic ) == SfxItemState::SET ) )
    2066      887023 :         rFont.SetItalic( static_cast<const SvxPostureItem&>(rSet.Get( nWhich_Italic )).GetPosture() );
    2067     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OUTLINE ) == SfxItemState::SET ) )
    2068      887087 :         rFont.SetOutline( static_cast<const SvxContourItem&>(rSet.Get( EE_CHAR_OUTLINE )).GetValue() );
    2069     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_SHADOW ) == SfxItemState::SET ) )
    2070      886990 :         rFont.SetShadow( static_cast<const SvxShadowedItem&>(rSet.Get( EE_CHAR_SHADOW )).GetValue() );
    2071     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_ESCAPEMENT ) == SfxItemState::SET ) )
    2072             :     {
    2073      887005 :         const SvxEscapementItem& rEsc = static_cast<const SvxEscapementItem&>( rSet.Get( EE_CHAR_ESCAPEMENT ) );
    2074             : 
    2075      887005 :         sal_uInt16 nProp = rEsc.GetProp();
    2076      887005 :         rFont.SetPropr( (sal_uInt8)nProp );
    2077             : 
    2078      887005 :         short nEsc = rEsc.GetEsc();
    2079      887005 :         if ( nEsc == DFLT_ESC_AUTO_SUPER )
    2080           0 :             nEsc = 100 - nProp;
    2081      887005 :         else if ( nEsc == DFLT_ESC_AUTO_SUB )
    2082           0 :             nEsc = sal::static_int_cast< short >( -( 100 - nProp ) );
    2083      887005 :         rFont.SetEscapement( nEsc );
    2084             :     }
    2085     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_PAIRKERNING ) == SfxItemState::SET ) )
    2086      886953 :         rFont.SetKerning( static_cast<const SvxAutoKernItem&>(rSet.Get( EE_CHAR_PAIRKERNING )).GetValue() ? FontKerning::FontSpecific : FontKerning::NONE );
    2087     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_KERNING ) == SfxItemState::SET ) )
    2088      886959 :         rFont.SetFixKerning( static_cast<const SvxKerningItem&>(rSet.Get( EE_CHAR_KERNING )).GetValue() );
    2089     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_WLM ) == SfxItemState::SET ) )
    2090      886977 :         rFont.SetWordLineMode( static_cast<const SvxWordLineModeItem&>(rSet.Get( EE_CHAR_WLM )).GetValue() );
    2091     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_EMPHASISMARK ) == SfxItemState::SET ) )
    2092      886993 :         rFont.SetEmphasisMark( static_cast<const SvxEmphasisMarkItem&>(rSet.Get( EE_CHAR_EMPHASISMARK )).GetValue() );
    2093     1026502 :     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) == SfxItemState::SET ) )
    2094      886761 :         rFont.SetRelief( (FontRelief)static_cast<const SvxCharReliefItem&>(rSet.Get( EE_CHAR_RELIEF )).GetValue() );
    2095             : 
    2096             :     // If comparing the entire font, or if checking before each alteration
    2097             :     // whether the value changes, remains relatively the same thing.
    2098             :     // So possible one MakeUniqFont more in the font, but as a result a quicker
    2099             :     // abortion of the query, or one must each time check bChanged.
    2100     1026502 :     if ( rFont == aPrevFont  )
    2101      753360 :         rFont = aPrevFont;  // => The same ImpPointer for IsSameInstance
    2102     1026502 : }
    2103             : 
    2104      259965 : void EditDoc::CreateDefFont( bool bUseStyles )
    2105             : {
    2106      259965 :     SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END );
    2107      259965 :     CreateFont( aDefFont, aTmpSet );
    2108      259965 :     aDefFont.SetVertical( IsVertical() );
    2109      259965 :     aDefFont.SetOrientation( IsVertical() ? 2700 : 0 );
    2110             : 
    2111      519930 :     for ( sal_Int32 nNode = 0; nNode < Count(); nNode++ )
    2112             :     {
    2113      259965 :         ContentNode* pNode = GetObject( nNode );
    2114      259965 :         pNode->GetCharAttribs().GetDefFont() = aDefFont;
    2115      259965 :         if ( bUseStyles )
    2116           4 :             pNode->CreateDefFont();
    2117      259965 :     }
    2118      259965 : }
    2119             : 
    2120     4981745 : sal_Int32 EditDoc::GetPos(const ContentNode* p) const
    2121             : {
    2122     4981745 :     return FastGetPos(maContents, p, nLastCache);
    2123             : }
    2124             : 
    2125     3744572 : const ContentNode* EditDoc::GetObject(sal_Int32 nPos) const
    2126             : {
    2127     3744572 :     return 0 <= nPos && nPos < (sal_Int32)maContents.size() ? &maContents[nPos] : NULL;
    2128             : }
    2129             : 
    2130     4857606 : ContentNode* EditDoc::GetObject(sal_Int32 nPos)
    2131             : {
    2132     4857606 :     return 0 <= nPos && nPos < (sal_Int32)maContents.size() ? &maContents[nPos] : NULL;
    2133             : }
    2134             : 
    2135           0 : const ContentNode* EditDoc::operator[](sal_Int32 nPos) const
    2136             : {
    2137           0 :     return GetObject(nPos);
    2138             : }
    2139             : 
    2140      798887 : ContentNode* EditDoc::operator[](sal_Int32 nPos)
    2141             : {
    2142      798887 :     return GetObject(nPos);
    2143             : }
    2144             : 
    2145      506251 : void EditDoc::Insert(sal_Int32 nPos, ContentNode* p)
    2146             : {
    2147      506251 :     if (nPos < 0 || nPos == SAL_MAX_INT32)
    2148             :     {
    2149             :         SAL_WARN( "editeng", "EditDoc::Insert - overflow pos " << nPos);
    2150      506251 :         return;
    2151             :     }
    2152      506251 :     maContents.insert(maContents.begin()+nPos, p);
    2153             : }
    2154             : 
    2155        2429 : void EditDoc::Remove(sal_Int32 nPos)
    2156             : {
    2157        2429 :     if (nPos < 0 || nPos >= (sal_Int32)maContents.size())
    2158             :     {
    2159             :         SAL_WARN( "editeng", "EditDoc::Remove - out of bounds pos " << nPos);
    2160        2429 :         return;
    2161             :     }
    2162        2429 :     maContents.erase(maContents.begin() + nPos);
    2163             : }
    2164             : 
    2165          16 : void EditDoc::Release(sal_Int32 nPos)
    2166             : {
    2167          16 :     if (nPos < 0 || nPos >= (sal_Int32)maContents.size())
    2168             :     {
    2169             :         SAL_WARN( "editeng", "EditDoc::Release - out of bounds pos " << nPos);
    2170          16 :         return;
    2171             :     }
    2172          16 :     maContents.release(maContents.begin() + nPos).release();
    2173             : }
    2174             : 
    2175     1298907 : sal_Int32 EditDoc::Count() const
    2176             : {
    2177     1298907 :     size_t nSize = maContents.size();
    2178     1298907 :     if (nSize > SAL_MAX_INT32)
    2179             :     {
    2180             :         SAL_WARN( "editeng", "EditDoc::Count - overflow " << nSize);
    2181           0 :         return SAL_MAX_INT32;
    2182             :     }
    2183     1298907 :     return nSize;
    2184             : }
    2185             : 
    2186        6139 : OUString EditDoc::GetSepStr( LineEnd eEnd )
    2187             : {
    2188        6139 :     if ( eEnd == LINEEND_CR )
    2189           0 :         return OUString("\015"); // 0x0d
    2190        6139 :     if ( eEnd == LINEEND_LF )
    2191        6139 :         return OUString("\012"); // 0x0a
    2192           0 :     return OUString("\015\012"); // 0x0d, 0x0a
    2193             : }
    2194             : 
    2195        1303 : OUString EditDoc::GetText( LineEnd eEnd ) const
    2196             : {
    2197        1303 :     const sal_Int32 nNodes = Count();
    2198        1303 :     if (nNodes == 0)
    2199           0 :         return OUString();
    2200             : 
    2201        1303 :     const OUString aSep = EditDoc::GetSepStr( eEnd );
    2202        1303 :     const sal_Int32 nSepSize = aSep.getLength();
    2203        1303 :     const sal_uInt32 nLen = GetTextLen() + (nNodes - 1)*nSepSize;
    2204             : 
    2205        2606 :     OUStringBuffer aBuffer(nLen + 16); // leave some slack
    2206             : 
    2207        2858 :     for ( sal_Int32 nNode = 0; nNode < nNodes; nNode++ )
    2208             :     {
    2209        1555 :         if ( nSepSize && nNode>0 )
    2210             :         {
    2211         252 :             aBuffer.append(aSep);
    2212             :         }
    2213        1555 :         aBuffer.append(GetParaAsString( GetObject(nNode) ));
    2214             :     }
    2215             : 
    2216        2606 :     return aBuffer.makeStringAndClear();
    2217             : }
    2218             : 
    2219       29447 : OUString EditDoc::GetParaAsString( sal_Int32 nNode ) const
    2220             : {
    2221       29447 :     return GetParaAsString( GetObject( nNode ) );
    2222             : }
    2223             : 
    2224       36253 : OUString EditDoc::GetParaAsString(
    2225             :     const ContentNode* pNode, sal_Int32 nStartPos, sal_Int32 nEndPos,
    2226             :     bool bResolveFields)
    2227             : {
    2228       36253 :     return pNode->GetExpandedText(nStartPos, nEndPos, bResolveFields);
    2229             : }
    2230             : 
    2231      902310 : EditPaM EditDoc::GetStartPaM() const
    2232             : {
    2233      902310 :     ContentNode* p = const_cast<ContentNode*>(GetObject(0));
    2234      902310 :     return EditPaM(p, 0);
    2235             : }
    2236             : 
    2237       16042 : EditPaM EditDoc::GetEndPaM() const
    2238             : {
    2239       16042 :     ContentNode* pLastNode = const_cast<ContentNode*>(GetObject(Count()-1));
    2240       16042 :     return EditPaM( pLastNode, pLastNode->Len() );
    2241             : }
    2242             : 
    2243        1346 : sal_uLong EditDoc::GetTextLen() const
    2244             : {
    2245        1346 :     sal_uLong nLen = 0;
    2246        2944 :     for ( sal_Int32 nNode = 0; nNode < Count(); nNode++ )
    2247             :     {
    2248        1598 :         const ContentNode* pNode = GetObject( nNode );
    2249        1598 :         nLen += pNode->GetExpandedLen();
    2250             :     }
    2251        1346 :     return nLen;
    2252             : }
    2253             : 
    2254      259961 : EditPaM EditDoc::Clear()
    2255             : {
    2256      259961 :     ImplDestroyContents();
    2257             : 
    2258      259961 :     ContentNode* pNode = new ContentNode( GetItemPool() );
    2259      259961 :     Insert(0, pNode);
    2260             : 
    2261      259961 :     CreateDefFont(false);
    2262             : 
    2263      259961 :     SetModified(false);
    2264             : 
    2265      259961 :     return EditPaM( pNode, 0 );
    2266             : }
    2267             : 
    2268           0 : void EditDoc::ClearSpellErrors()
    2269             : {
    2270           0 :     std::for_each(maContents.begin(), maContents.end(), ClearSpellErrorsHandler());
    2271           0 : }
    2272             : 
    2273     1586557 : void EditDoc::SetModified( bool b )
    2274             : {
    2275     1586557 :     bModified = b;
    2276     1586557 :     if ( bModified )
    2277             :     {
    2278     1326424 :         aModifyHdl.Call( NULL );
    2279             :     }
    2280     1586557 : }
    2281             : 
    2282      227436 : EditPaM EditDoc::RemoveText()
    2283             : {
    2284             :     // Keep the old ItemSet, to keep the chart Font.
    2285      227436 :     ContentNode* pPrevFirstNode = GetObject(0);
    2286      227436 :     SfxStyleSheet* pPrevStyle = pPrevFirstNode->GetStyleSheet();
    2287      227436 :     SfxItemSet aPrevSet( pPrevFirstNode->GetContentAttribs().GetItems() );
    2288      454872 :     vcl::Font aPrevFont( pPrevFirstNode->GetCharAttribs().GetDefFont() );
    2289             : 
    2290      227436 :     ImplDestroyContents();
    2291             : 
    2292      227436 :     ContentNode* pNode = new ContentNode( GetItemPool() );
    2293      227436 :     Insert(0, pNode);
    2294             : 
    2295      227436 :     pNode->SetStyleSheet(pPrevStyle, false);
    2296      227436 :     pNode->GetContentAttribs().GetItems().Set( aPrevSet );
    2297      227436 :     pNode->GetCharAttribs().GetDefFont() = aPrevFont;
    2298             : 
    2299      227436 :     SetModified(true);
    2300             : 
    2301      454872 :     return EditPaM( pNode, 0 );
    2302             : }
    2303             : 
    2304      265040 : EditPaM EditDoc::InsertText( EditPaM aPaM, const OUString& rStr )
    2305             : {
    2306             :     DBG_ASSERT( rStr.indexOf( 0x0A ) == -1, "EditDoc::InsertText: Newlines prohibited in paragraph!" );
    2307             :     DBG_ASSERT( rStr.indexOf( 0x0D ) == -1, "EditDoc::InsertText: Newlines prohibited in paragraph!" );
    2308             :     DBG_ASSERT( rStr.indexOf( '\t' ) == -1, "EditDoc::InsertText: Newlines prohibited in paragraph!" );
    2309             :     DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertText1" );
    2310             : 
    2311      265040 :     aPaM.GetNode()->Insert( rStr, aPaM.GetIndex() );
    2312      265040 :     aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), rStr.getLength(), GetItemPool() );
    2313      265040 :     aPaM.SetIndex( aPaM.GetIndex() + rStr.getLength() );
    2314             : 
    2315      265040 :     SetModified( true );
    2316             : 
    2317      265040 :     return aPaM;
    2318             : }
    2319             : 
    2320        6437 : EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, bool bKeepEndingAttribs )
    2321             : {
    2322             :     DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" );
    2323        6437 :     ContentNode* pCurNode = aPaM.GetNode();
    2324        6437 :     sal_Int32 nPos = GetPos( pCurNode );
    2325        6437 :     OUString aStr = aPaM.GetNode()->Copy( aPaM.GetIndex() );
    2326        6437 :     aPaM.GetNode()->Erase( aPaM.GetIndex() );
    2327             : 
    2328             :     // the paragraph attributes...
    2329       12874 :     ContentAttribs aContentAttribs( aPaM.GetNode()->GetContentAttribs() );
    2330             : 
    2331             :     // for a new paragraph we like to have the bullet/numbering visible by default
    2332        6437 :     aContentAttribs.GetItems().Put( SfxBoolItem( EE_PARA_BULLETSTATE, true), EE_PARA_BULLETSTATE );
    2333             : 
    2334             :     // ContenNode constructor copies also the paragraph attributes
    2335        6437 :     ContentNode* pNode = new ContentNode( aStr, aContentAttribs );
    2336             : 
    2337             :     // Copy the Default Font
    2338        6437 :     pNode->GetCharAttribs().GetDefFont() = aPaM.GetNode()->GetCharAttribs().GetDefFont();
    2339        6437 :     SfxStyleSheet* pStyle = aPaM.GetNode()->GetStyleSheet();
    2340        6437 :     if ( pStyle )
    2341             :     {
    2342        4157 :         OUString aFollow( pStyle->GetFollow() );
    2343        4157 :         if ( !aFollow.isEmpty() && ( aFollow != pStyle->GetName() ) )
    2344             :         {
    2345           0 :             SfxStyleSheetBase* pNext = pStyle->GetPool().Find( aFollow, pStyle->GetFamily() );
    2346           0 :             pNode->SetStyleSheet( static_cast<SfxStyleSheet*>(pNext) );
    2347        4157 :         }
    2348             :     }
    2349             : 
    2350             :     // Character attributes may need to be copied or trimmed:
    2351        6437 :     pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs );
    2352             : 
    2353        6437 :     Insert(nPos+1, pNode);
    2354             : 
    2355        6437 :     SetModified(true);
    2356             : 
    2357        6437 :     aPaM.SetNode( pNode );
    2358        6437 :     aPaM.SetIndex( 0 );
    2359       12874 :     return aPaM;
    2360             : }
    2361             : 
    2362        9435 : EditPaM EditDoc::InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem  )
    2363             : {
    2364             :     DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertFeature" );
    2365             : 
    2366        9435 :     aPaM.GetNode()->Insert( OUString(CH_FEATURE), aPaM.GetIndex() );
    2367        9435 :     aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), 1, GetItemPool() );
    2368             : 
    2369             :     // Create a feature-attribute for the feature...
    2370        9435 :     EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 );
    2371             :     DBG_ASSERT( pAttrib, "Why can not the feature be created?" );
    2372        9435 :     aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib );
    2373             : 
    2374        9435 :     SetModified( true );
    2375             : 
    2376        9435 :     aPaM.SetIndex( aPaM.GetIndex() + 1 );
    2377        9435 :     return aPaM;
    2378             : }
    2379             : 
    2380        2429 : EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight )
    2381             : {
    2382        2429 :     const EditPaM aPaM( pLeft, pLeft->Len() );
    2383             : 
    2384             :     // First the attributes, otherwise nLen will not be correct!
    2385        2429 :     pLeft->AppendAttribs( pRight );
    2386             :     // then the Text...
    2387        2429 :     pLeft->Append(pRight->GetString());
    2388             : 
    2389             :     // the one to the right disappears.
    2390        2429 :     RemoveItemsFromPool(*pRight);
    2391        2429 :     sal_Int32 nRight = GetPos( pRight );
    2392        2429 :     Remove( nRight );
    2393             : 
    2394        2429 :     SetModified(true);
    2395             : 
    2396        2429 :     return aPaM;
    2397             : }
    2398             : 
    2399        5823 : EditPaM EditDoc::RemoveChars( EditPaM aPaM, sal_Int32 nChars )
    2400             : {
    2401             :     // Maybe remove Features!
    2402        5823 :     aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars );
    2403        5823 :     aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() );
    2404             : 
    2405        5823 :     SetModified( true );
    2406             : 
    2407        5823 :     return aPaM;
    2408             : }
    2409             : 
    2410       43076 : void EditDoc::InsertAttribInSelection( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, const SfxPoolItem& rPoolItem )
    2411             : {
    2412             :     DBG_ASSERT( pNode, "What to do with the attribute?" );
    2413             :     DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribute to large!" );
    2414             : 
    2415             :     // for Optimization:
    2416             :     // This ends at the beginning of the selection => can be expanded
    2417       43076 :     EditCharAttrib* pEndingAttrib = 0;
    2418             :     // This starts at the end of the selection => can be expanded
    2419       43076 :     EditCharAttrib* pStartingAttrib = 0;
    2420             : 
    2421             :     DBG_ASSERT( nStart <= nEnd, "Small miscalculations in InsertAttribInSelection" );
    2422             : 
    2423       43076 :     RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() );
    2424             : 
    2425       43141 :     if ( pStartingAttrib && pEndingAttrib &&
    2426       43078 :          ( *(pStartingAttrib->GetItem()) == rPoolItem ) &&
    2427           0 :          ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
    2428             :     {
    2429             :         // Will become a large Attribute.
    2430           0 :         pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd();
    2431           0 :         GetItemPool().Remove( *(pStartingAttrib->GetItem()) );
    2432           0 :         pNode->GetCharAttribs().Remove(pStartingAttrib);
    2433             :     }
    2434       43076 :     else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) )
    2435          60 :         pStartingAttrib->GetStart() = nStart;
    2436       43016 :     else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
    2437        9463 :         pEndingAttrib->GetEnd() = nEnd;
    2438             :     else
    2439       33553 :         InsertAttrib( rPoolItem, pNode, nStart, nEnd );
    2440             : 
    2441       43076 :     if ( pStartingAttrib )
    2442          63 :         pNode->GetCharAttribs().ResortAttribs();
    2443             : 
    2444       43076 :     SetModified(true);
    2445       43076 : }
    2446             : 
    2447         969 : bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, sal_uInt16 nWhich )
    2448             : {
    2449             :     EditCharAttrib* pStarting;
    2450             :     EditCharAttrib* pEnding;
    2451         969 :     return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich );
    2452             : }
    2453             : 
    2454       44045 : bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, sal_uInt16 nWhich )
    2455             : {
    2456             : 
    2457             :     DBG_ASSERT( pNode, "What to do with the attribute?" );
    2458             :     DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribute to large!" );
    2459             : 
    2460             :     // This ends at the beginning of the selection => can be expanded
    2461       44045 :     rpEnding = 0;
    2462             :     // This starts at the end of the selection => can be expanded
    2463       44045 :     rpStarting = 0;
    2464             : 
    2465       44045 :     bool bChanged = false;
    2466             : 
    2467             :     DBG_ASSERT( nStart <= nEnd, "Small miscalculations in InsertAttribInSelection" );
    2468             : 
    2469             : #if OSL_DEBUG_LEVEL > 0
    2470             :     CharAttribList::DbgCheckAttribs(pNode->GetCharAttribs());
    2471             : #endif
    2472             : 
    2473             :     // iterate over the attributes ...
    2474       44045 :     sal_Int32 nAttr = 0;
    2475       44045 :     CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
    2476       44045 :     EditCharAttrib* pAttr = GetAttrib(rAttribs, nAttr);
    2477      445168 :     while ( pAttr )
    2478             :     {
    2479      357190 :         bool bRemoveAttrib = false;
    2480      357190 :         sal_uInt16 nAttrWhich = pAttr->Which();
    2481      357190 :         if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) )
    2482             :         {
    2483             :             // Attribute starts in Selection
    2484       15983 :             if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) )
    2485             :             {
    2486        2940 :                 bChanged = true;
    2487        2940 :                 if ( pAttr->GetEnd() > nEnd )
    2488             :                 {
    2489          63 :                     pAttr->GetStart() = nEnd;   // then it starts after this
    2490          63 :                     rpStarting = pAttr;
    2491          63 :                     if ( nWhich )
    2492          63 :                         break;  // There can be no further attributes here
    2493             :                 }
    2494        2877 :                 else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
    2495             :                 {
    2496             :                     // Delete feature only if on the exact spot
    2497        2877 :                     bRemoveAttrib = true;
    2498             :                 }
    2499             :             }
    2500             : 
    2501             :             // Attribute ends in Selection
    2502       13043 :             else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) )
    2503             :             {
    2504       11029 :                 bChanged = true;
    2505       11029 :                 if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() )
    2506             :                 {
    2507       11029 :                     pAttr->GetEnd() = nStart;   // then it ends here
    2508       11029 :                     rpEnding = pAttr;
    2509             :                 }
    2510           0 :                 else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
    2511             :                 {
    2512             :                     // Delete feature only if on the exact spot
    2513           0 :                     bRemoveAttrib = true;
    2514             :                 }
    2515             :             }
    2516             :             // Attribute overlaps the selection
    2517        2014 :             else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
    2518             :             {
    2519          49 :                 bChanged = true;
    2520          49 :                 if ( pAttr->GetStart() == nStart )
    2521             :                 {
    2522           0 :                     pAttr->GetStart() = nEnd;
    2523           0 :                     rpStarting = pAttr;
    2524           0 :                     if ( nWhich )
    2525           0 :                         break;  // There can be further attributes!
    2526             :                 }
    2527          49 :                 else if ( pAttr->GetEnd() == nEnd )
    2528             :                 {
    2529           0 :                     pAttr->GetEnd() = nStart;
    2530           0 :                     rpEnding = pAttr;
    2531           0 :                     if ( nWhich )
    2532           0 :                         break;  // There can be further attributes!
    2533             :                 }
    2534             :                 else // Attribute must be split ...
    2535             :                 {
    2536          49 :                     sal_Int32 nOldEnd = pAttr->GetEnd();
    2537          49 :                     pAttr->GetEnd() = nStart;
    2538          49 :                     rpEnding = pAttr;
    2539          49 :                     InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd );
    2540          49 :                     if ( nWhich )
    2541          49 :                         break;  // There can be further attributes!
    2542             :                 }
    2543             :             }
    2544             :         }
    2545      357078 :         if ( bRemoveAttrib )
    2546             :         {
    2547             :             DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Delete and retain the same attribute?" );
    2548             :             DBG_ASSERT( !pAttr->IsFeature(), "RemoveAttribs: Remove a feature?!" );
    2549        2877 :             GetItemPool().Remove( *pAttr->GetItem() );
    2550        2877 :             rAttribs.erase(rAttribs.begin()+nAttr);
    2551        2877 :             nAttr--;
    2552             :         }
    2553      357078 :         nAttr++;
    2554      357078 :         pAttr = GetAttrib(rAttribs, nAttr);
    2555             :     }
    2556             : 
    2557       44045 :     if ( bChanged )
    2558             :     {
    2559             :         // char attributes need to be sorted by start again
    2560       13722 :         pNode->GetCharAttribs().ResortAttribs();
    2561       13722 :         SetModified(true);
    2562             :     }
    2563             : 
    2564             : #if OSL_DEBUG_LEVEL > 0
    2565             :     CharAttribList::DbgCheckAttribs(pNode->GetCharAttribs());
    2566             : #endif
    2567             : 
    2568       44045 :     return bChanged;
    2569             : }
    2570             : 
    2571       59898 : void EditDoc::InsertAttrib( const SfxPoolItem& rPoolItem, ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd )
    2572             : {
    2573             :     // This method no longer checks whether a corresponding attribute already
    2574             :     // exists at this place!
    2575       59898 :     EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd );
    2576             :     DBG_ASSERT( pAttrib, "MakeCharAttrib failed!" );
    2577       59898 :     pNode->GetCharAttribs().InsertAttrib( pAttrib );
    2578             : 
    2579       59898 :     SetModified( true );
    2580       59898 : }
    2581             : 
    2582       76623 : void EditDoc::InsertAttrib( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, const SfxPoolItem& rPoolItem )
    2583             : {
    2584       76623 :     if ( nStart != nEnd )
    2585             :     {
    2586       43076 :         InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem );
    2587             :     }
    2588             :     else
    2589             :     {
    2590             :         // Check whether already a new attribute with WhichId exists at this place:
    2591       33547 :         CharAttribList& rAttrList = pNode->GetCharAttribs();
    2592       33547 :         EditCharAttrib* pAttr = rAttrList.FindEmptyAttrib( rPoolItem.Which(), nStart );
    2593       33547 :         if ( pAttr )
    2594             :         {
    2595             :             // Remove attribute....
    2596        8197 :             rAttrList.Release(pAttr);
    2597             :         }
    2598             : 
    2599             :         // check whether 'the same' attribute exist at this place.
    2600       33547 :         pAttr = rAttrList.FindAttrib( rPoolItem.Which(), nStart );
    2601       33547 :         if ( pAttr )
    2602             :         {
    2603        7327 :             if ( pAttr->IsInside( nStart ) )    // split
    2604             :             {
    2605             :                 // check again if really splitting, or return !
    2606           0 :                 sal_Int32 nOldEnd = pAttr->GetEnd();
    2607           0 :                 pAttr->GetEnd() = nStart;
    2608           0 :                 EditCharAttrib* pNew = MakeCharAttrib( GetItemPool(), *(pAttr->GetItem()), nStart, nOldEnd );
    2609           0 :                 rAttrList.InsertAttrib(pNew);
    2610             :             }
    2611        7327 :             else if ( pAttr->GetEnd() == nStart )
    2612             :             {
    2613             :                 DBG_ASSERT( !pAttr->IsEmpty(), "Still an empty attribute?" );
    2614             :                 // Check if exactly the same attribute
    2615        7327 :                 if ( *(pAttr->GetItem()) == rPoolItem )
    2616       83874 :                     return;
    2617             :             }
    2618             :         }
    2619       26296 :         InsertAttrib( rPoolItem, pNode, nStart, nStart );
    2620             :     }
    2621             : 
    2622       69372 :     SetModified( true );
    2623             : }
    2624             : 
    2625        5054 : void EditDoc::FindAttribs( ContentNode* pNode, sal_Int32 nStartPos, sal_Int32 nEndPos, SfxItemSet& rCurSet )
    2626             : {
    2627             :     DBG_ASSERT( pNode, "Where to search?" );
    2628             :     DBG_ASSERT( nStartPos <= nEndPos, "Invalid region!" );
    2629             : 
    2630        5054 :     sal_uInt16 nAttr = 0;
    2631        5054 :     EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
    2632             :     // No Selection...
    2633        5054 :     if ( nStartPos == nEndPos )
    2634             :     {
    2635       18865 :         while ( pAttr && ( pAttr->GetStart() <= nEndPos) )
    2636             :         {
    2637       10745 :             const SfxPoolItem* pItem = 0;
    2638             :             // Attribute is about...
    2639       10745 :             if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
    2640           0 :                 pItem = pAttr->GetItem();
    2641             :             // Attribute ending here is not empty
    2642       10745 :             else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
    2643             :             {
    2644           0 :                 if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) )
    2645           0 :                     pItem = pAttr->GetItem();
    2646             :             }
    2647             :             // Attribute ending here is empty
    2648       10745 :             else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
    2649             :             {
    2650        5080 :                 pItem = pAttr->GetItem();
    2651             :             }
    2652             :             // Attribute starts here
    2653        5665 :             else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
    2654             :             {
    2655        5665 :                 if ( nStartPos == 0 )   // special case
    2656        5665 :                     pItem = pAttr->GetItem();
    2657             :             }
    2658             : 
    2659       10745 :             if ( pItem )
    2660             :             {
    2661       10745 :                 sal_uInt16 nWhich = pItem->Which();
    2662       10745 :                 if ( rCurSet.GetItemState( nWhich ) == SfxItemState::DEFAULT )
    2663             :                 {
    2664        6703 :                     rCurSet.Put( *pItem );
    2665             :                 }
    2666        4042 :                 else if ( rCurSet.GetItemState( nWhich ) == SfxItemState::SET )
    2667             :                 {
    2668        4042 :                     const SfxPoolItem& rItem = rCurSet.Get( nWhich );
    2669        4042 :                     if ( rItem != *pItem )
    2670             :                     {
    2671           0 :                         rCurSet.InvalidateItem( nWhich );
    2672             :                     }
    2673             :                 }
    2674             :             }
    2675       10745 :             nAttr++;
    2676       10745 :             pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
    2677             :         }
    2678             :     }
    2679             :     else    // Selection
    2680             :     {
    2681       18945 :         while ( pAttr && ( pAttr->GetStart() < nEndPos) )
    2682             :         {
    2683       16957 :             const SfxPoolItem* pItem = 0;
    2684             :             // Attribut is about...
    2685       16957 :             if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) )
    2686       16952 :                 pItem = pAttr->GetItem();
    2687             :             // Attribute starts right in the middle ...
    2688           5 :             else if ( pAttr->GetStart() >= nStartPos )
    2689             :             {
    2690             :                 // !!! pItem = pAttr->GetItem();
    2691             :                 // PItem is simply not enough, since one for example in case
    2692             :                 // of Shadow, would never find an unequal item, since such a
    2693             :                 // item represents its presence by absence!
    2694             :                 // If (...)
    2695             :                 // It needs to be examined on exactly the same attribute at the
    2696             :                 // breaki point, which is quite expensive.
    2697             :                 // Since optimazation is done when inserting the  attributes
    2698             :                 // this case does not appear so fast ...
    2699             :                 // So based on the need for speed:
    2700           1 :                 rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
    2701             : 
    2702             :             }
    2703             :             // Attribute ends in the middle of it ...
    2704           4 :             else if ( pAttr->GetEnd() > nStartPos )
    2705             :             {
    2706           0 :                 rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
    2707             :             }
    2708             : 
    2709       16957 :             if ( pItem )
    2710             :             {
    2711       16952 :                 sal_uInt16 nWhich = pItem->Which();
    2712       16952 :                 if ( rCurSet.GetItemState( nWhich ) == SfxItemState::DEFAULT )
    2713             :                 {
    2714        8868 :                     rCurSet.Put( *pItem );
    2715             :                 }
    2716        8084 :                 else if ( rCurSet.GetItemState( nWhich ) == SfxItemState::SET )
    2717             :                 {
    2718        8084 :                     const SfxPoolItem& rItem = rCurSet.Get( nWhich );
    2719        8084 :                     if ( rItem != *pItem )
    2720             :                     {
    2721           0 :                         rCurSet.InvalidateItem( nWhich );
    2722             :                     }
    2723             :                 }
    2724             :             }
    2725       16957 :             nAttr++;
    2726       16957 :             pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
    2727             :         }
    2728             :     }
    2729        5054 : }
    2730             : 
    2731             : namespace {
    2732             : 
    2733             : struct LessByStart : std::binary_function<EditCharAttrib, EditCharAttrib, bool>
    2734             : {
    2735      448595 :     bool operator() (const EditCharAttrib& left, const EditCharAttrib& right) const
    2736             :     {
    2737      448595 :         return left.GetStart() < right.GetStart();
    2738             :     }
    2739             : };
    2740             : 
    2741             : }
    2742             : 
    2743      506251 : CharAttribList::CharAttribList()
    2744             : : aAttribs()
    2745             : , aDefFont()
    2746      506251 : , bHasEmptyAttribs(false)
    2747             : {
    2748      506251 : }
    2749             : 
    2750      503908 : CharAttribList::~CharAttribList()
    2751             : {
    2752      503908 : }
    2753             : 
    2754      217365 : void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib )
    2755             : {
    2756             : // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    2757             : // optimize: binary search?    !
    2758             : // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    2759             : 
    2760             :     // Maybe just simply iterate backwards:
    2761             :     // The most common and critical case: Attributes are already sorted
    2762             :     // (InsertBinTextObject!) binary search would not be optimal here.
    2763             :     // => Would bring something!
    2764             : 
    2765      217365 :     const sal_Int32 nStart = pAttrib->GetStart(); // may be better for Comp.Opt.
    2766             : 
    2767             : #if OSL_DEBUG_LEVEL > 0
    2768             :     CharAttribList::DbgCheckAttribs(*this);
    2769             : #endif
    2770             : 
    2771      217365 :     if ( pAttrib->IsEmpty() )
    2772       49081 :         bHasEmptyAttribs = true;
    2773             : 
    2774      217365 :     bool bInsert(true);
    2775     1837722 :     for (sal_Int32 i = 0, n = aAttribs.size(); i < n; ++i)
    2776             :     {
    2777     1623918 :         const EditCharAttrib& rCurAttrib = aAttribs[i];
    2778     1623918 :         if (rCurAttrib.GetStart() > nStart)
    2779             :         {
    2780        3561 :             aAttribs.insert(aAttribs.begin()+i, pAttrib);
    2781        3561 :             bInsert = false;
    2782        3561 :             break;
    2783             :         }
    2784             :     }
    2785             : 
    2786      217365 :     if (bInsert) aAttribs.push_back(pAttrib);
    2787             : 
    2788             : #if OSL_DEBUG_LEVEL > 0
    2789             :     CharAttribList::DbgCheckAttribs(*this);
    2790             : #endif
    2791      217365 : }
    2792             : 
    2793       16246 : void CharAttribList::ResortAttribs()
    2794             : {
    2795       16246 :     aAttribs.sort(LessByStart());
    2796             : 
    2797             : #if OSL_DEBUG_LEVEL > 0
    2798             :     CharAttribList::DbgCheckAttribs(*this);
    2799             : #endif
    2800       16246 : }
    2801             : 
    2802       26701 : void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool )
    2803             : {
    2804             : #if OSL_DEBUG_LEVEL > 0
    2805             :     CharAttribList::DbgCheckAttribs(*this);
    2806             : #endif
    2807      190328 :     for (sal_Int32 i = 0; i < (sal_Int32)aAttribs.size(); ++i)
    2808             :     {
    2809      163627 :         EditCharAttrib& rAttr = aAttribs[i];
    2810     1621785 :         for (sal_Int32 nNext = i+1; nNext < (sal_Int32)aAttribs.size(); ++nNext)
    2811             :         {
    2812     1461393 :             EditCharAttrib& rNext = aAttribs[nNext];
    2813     1461393 :             if (!rAttr.IsFeature() && rNext.GetStart() == rAttr.GetEnd() && rNext.Which() == rAttr.Which())
    2814             :             {
    2815         668 :                 if (*rNext.GetItem() == *rAttr.GetItem())
    2816             :                 {
    2817          49 :                     rAttr.GetEnd() = rNext.GetEnd();
    2818          49 :                     rItemPool.Remove(*rNext.GetItem());
    2819          49 :                     aAttribs.erase(aAttribs.begin()+nNext);
    2820             :                 }
    2821         668 :                 break;  // only 1 attr with same which can start here.
    2822             :             }
    2823     1460725 :             else if (rNext.GetStart() > rAttr.GetEnd())
    2824             :             {
    2825        2567 :                 break;
    2826             :             }
    2827             :         }
    2828             :     }
    2829             : #if OSL_DEBUG_LEVEL > 0
    2830             :     CharAttribList::DbgCheckAttribs(*this);
    2831             : #endif
    2832       26701 : }
    2833             : 
    2834      987293 : sal_Int32 CharAttribList::Count() const
    2835             : {
    2836      987293 :     return aAttribs.size();
    2837             : }
    2838             : 
    2839      216984 : const EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_Int32 nPos ) const
    2840             : {
    2841             :     // Backwards, if one ends where the next starts.
    2842             :     // => The starting one is the valid one ...
    2843      216984 :     AttribsType::const_reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
    2844      395229 :     for (; it != itEnd; ++it)
    2845             :     {
    2846      183759 :         const EditCharAttrib& rAttr = *it;
    2847      183759 :         if (rAttr.Which() == nWhich && rAttr.IsIn(nPos))
    2848        5514 :             return &rAttr;
    2849             :     }
    2850      211470 :     return NULL;
    2851             : }
    2852             : 
    2853       59902 : EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_Int32 nPos )
    2854             : {
    2855             :     // Backwards, if one ends where the next starts.
    2856             :     // => The starting one is the valid one ...
    2857       59902 :     AttribsType::reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
    2858      492861 :     for (; it != itEnd; ++it)
    2859             :     {
    2860      440872 :         EditCharAttrib& rAttr = *it;
    2861      440872 :         if (rAttr.Which() == nWhich && rAttr.IsIn(nPos))
    2862        7913 :             return &rAttr;
    2863             :     }
    2864       51989 :     return NULL;
    2865             : }
    2866             : 
    2867      283291 : const EditCharAttrib* CharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_Int32 nFromPos ) const
    2868             : {
    2869             :     DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
    2870      283291 :     AttribsType::const_iterator it = aAttribs.begin(), itEnd = aAttribs.end();
    2871      505898 :     for (; it != itEnd; ++it)
    2872             :     {
    2873      247141 :         const EditCharAttrib& rAttr = *it;
    2874      247141 :         if (rAttr.GetStart() >= nFromPos && rAttr.Which() == nWhich)
    2875       24534 :             return &rAttr;
    2876             :     }
    2877      258757 :     return NULL;
    2878             : }
    2879             : 
    2880           0 : bool CharAttribList::HasAttrib( sal_Int32 nStartPos, sal_Int32 nEndPos ) const
    2881             : {
    2882           0 :     AttribsType::const_reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
    2883           0 :     for (; it != itEnd; ++it)
    2884             :     {
    2885           0 :         const EditCharAttrib& rAttr = *it;
    2886           0 :         if (rAttr.GetStart() < nEndPos && rAttr.GetEnd() > nStartPos)
    2887           0 :             return true;
    2888             :     }
    2889           0 :     return false;
    2890             : }
    2891             : 
    2892             : 
    2893             : 
    2894             : namespace {
    2895             : 
    2896             : class FindByAddress : std::unary_function<EditCharAttrib, bool>
    2897             : {
    2898             :     const EditCharAttrib* mpAttr;
    2899             : public:
    2900        8197 :     FindByAddress(const EditCharAttrib* p) : mpAttr(p) {}
    2901       16262 :     bool operator() (const EditCharAttrib& r) const
    2902             :     {
    2903       16262 :         return &r == mpAttr;
    2904             :     }
    2905             : };
    2906             : 
    2907             : }
    2908             : 
    2909           0 : void CharAttribList::Remove(const EditCharAttrib* p)
    2910             : {
    2911           0 :     AttribsType::iterator it = std::find_if(aAttribs.begin(), aAttribs.end(), FindByAddress(p));
    2912           0 :     if (it != aAttribs.end())
    2913           0 :         aAttribs.erase(it);
    2914           0 : }
    2915             : 
    2916        2056 : void CharAttribList::Remove(sal_Int32 nPos)
    2917             : {
    2918        2056 :     if (nPos >= (sal_Int32)aAttribs.size())
    2919        2056 :         return;
    2920             : 
    2921        2056 :     aAttribs.erase(aAttribs.begin()+nPos);
    2922             : }
    2923             : 
    2924        8197 : void CharAttribList::Release(const EditCharAttrib* p)
    2925             : {
    2926        8197 :     AttribsType::iterator it = std::find_if(aAttribs.begin(), aAttribs.end(), FindByAddress(p));
    2927        8197 :     if (it != aAttribs.end())
    2928        8197 :         aAttribs.release(it).release();
    2929        8197 : }
    2930             : 
    2931          84 : void CharAttribList::SetHasEmptyAttribs(bool b)
    2932             : {
    2933          84 :     bHasEmptyAttribs = b;
    2934          84 : }
    2935             : 
    2936           0 : bool CharAttribList::HasBoundingAttrib( sal_Int32 nBound ) const
    2937             : {
    2938             :     // Backwards, if one ends where the next starts.
    2939             :     // => The starting one is the valid one ...
    2940           0 :     AttribsType::const_reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
    2941           0 :     for (; it != itEnd; ++it)
    2942             :     {
    2943           0 :         const EditCharAttrib& rAttr = *it;
    2944           0 :         if (rAttr.GetEnd() < nBound)
    2945           0 :             return false;
    2946             : 
    2947           0 :         if (rAttr.GetStart() == nBound || rAttr.GetEnd() == nBound)
    2948           0 :             return true;
    2949             :     }
    2950           0 :     return false;
    2951             : }
    2952             : 
    2953           0 : const EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_Int32 nPos ) const
    2954             : {
    2955           0 :     if ( !bHasEmptyAttribs )
    2956           0 :         return NULL;
    2957             : 
    2958           0 :     AttribsType::const_iterator it = aAttribs.begin(), itEnd = aAttribs.end();
    2959           0 :     for (; it != itEnd; ++it)
    2960             :     {
    2961           0 :         const EditCharAttrib& rAttr = *it;
    2962           0 :         if (rAttr.GetStart() == nPos && rAttr.GetEnd() == nPos && rAttr.Which() == nWhich)
    2963           0 :             return &rAttr;
    2964             :     }
    2965           0 :     return NULL;
    2966             : }
    2967             : 
    2968       40909 : EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_Int32 nPos )
    2969             : {
    2970       40909 :     if ( !bHasEmptyAttribs )
    2971        1774 :         return NULL;
    2972             : 
    2973       39135 :     AttribsType::iterator it = aAttribs.begin(), itEnd = aAttribs.end();
    2974      431787 :     for (; it != itEnd; ++it)
    2975             :     {
    2976      400891 :         EditCharAttrib& rAttr = *it;
    2977      400891 :         if (rAttr.GetStart() == nPos && rAttr.GetEnd() == nPos && rAttr.Which() == nWhich)
    2978        8239 :             return &rAttr;
    2979             :     }
    2980       30896 :     return NULL;
    2981             : }
    2982             : 
    2983             : namespace {
    2984             : 
    2985             : class FindByStartPos : std::unary_function<EditCharAttrib, bool>
    2986             : {
    2987             :     sal_Int32 mnPos;
    2988             : public:
    2989      274601 :     FindByStartPos(sal_Int32 nPos) : mnPos(nPos) {}
    2990      135606 :     bool operator() (const EditCharAttrib& r) const
    2991             :     {
    2992      135606 :         return r.GetStart() >= mnPos;
    2993             :     }
    2994             : };
    2995             : 
    2996             : }
    2997             : 
    2998      274601 : const EditCharAttrib* CharAttribList::FindFeature( sal_Int32 nPos ) const
    2999             : {
    3000             :     // First, find the first attribute that starts at or after specified position.
    3001             :     AttribsType::const_iterator it =
    3002      274601 :         std::find_if(aAttribs.begin(), aAttribs.end(), FindByStartPos(nPos));
    3003             : 
    3004      274601 :     if (it == aAttribs.end())
    3005             :         // All attributes are before the specified position.
    3006      248147 :         return NULL;
    3007             : 
    3008             :     // And find the first attribute with feature.
    3009       26454 :     it = std::find_if(it, aAttribs.end(), boost::bind(&EditCharAttrib::IsFeature, _1) == true);
    3010       26454 :     return it == aAttribs.end() ? NULL : &(*it);
    3011             : }
    3012             : 
    3013             : namespace {
    3014             : 
    3015             : class RemoveEmptyAttrItem : std::unary_function<EditCharAttrib, void>
    3016             : {
    3017             :     SfxItemPool& mrItemPool;
    3018             : public:
    3019         633 :     RemoveEmptyAttrItem(SfxItemPool& rPool) : mrItemPool(rPool) {}
    3020        8913 :     void operator() (const EditCharAttrib& r)
    3021             :     {
    3022        8913 :         if (r.IsEmpty())
    3023          16 :             mrItemPool.Remove(*r.GetItem());
    3024        8913 :     }
    3025             : };
    3026             : 
    3027             : }
    3028             : 
    3029         633 : void CharAttribList::DeleteEmptyAttribs( SfxItemPool& rItemPool )
    3030             : {
    3031         633 :     std::for_each(aAttribs.begin(), aAttribs.end(), RemoveEmptyAttrItem(rItemPool));
    3032         633 :     aAttribs.erase_if(boost::bind(&EditCharAttrib::IsEmpty, _1) == true);
    3033         633 :     bHasEmptyAttribs = false;
    3034         633 : }
    3035             : 
    3036             : #if OSL_DEBUG_LEVEL > 0
    3037             : void CharAttribList::DbgCheckAttribs(CharAttribList const& rAttribs)
    3038             : {
    3039             :     AttribsType::const_iterator it = rAttribs.aAttribs.begin();
    3040             :     AttribsType::const_iterator itEnd = rAttribs.aAttribs.end();
    3041             :     std::set<std::pair<sal_Int32, sal_uInt16>> zero_set;
    3042             :     for (; it != itEnd; ++it)
    3043             :     {
    3044             :         const EditCharAttrib& rAttr = *it;
    3045             :         assert(rAttr.GetStart() <= rAttr.GetEnd());
    3046             :         assert(!rAttr.IsFeature() || rAttr.GetLen() == 1);
    3047             :         if (0 == rAttr.GetLen())
    3048             :         {
    3049             :             // not sure if 0-length attributes allowed at all in non-empty para?
    3050             :             assert(zero_set.insert(std::make_pair(rAttr.GetStart(), rAttr.Which())).second && "duplicate 0-length attribute detected");
    3051             :         }
    3052             :     }
    3053             :     CheckOrderedList(rAttribs.GetAttribs(), true);
    3054             : //    CheckOrderedList(rAttribs.GetAttribs(), false); // this does not work - need 2nd array to sort by ends?
    3055             : }
    3056             : #endif
    3057             : 
    3058             : 
    3059       56134 : EditEngineItemPool::EditEngineItemPool( bool bPersistenRefCounts )
    3060             :     : SfxItemPool( "EditEngineItemPool", EE_ITEMS_START, EE_ITEMS_END,
    3061       56134 :                     aItemInfos, 0, bPersistenRefCounts )
    3062             : {
    3063       56134 :     SetVersionMap( 1, 3999, 4015, aV1Map );
    3064       56134 :     SetVersionMap( 2, 3999, 4019, aV2Map );
    3065       56134 :     SetVersionMap( 3, 3997, 4020, aV3Map );
    3066       56134 :     SetVersionMap( 4, 3994, 4022, aV4Map );
    3067       56134 :     SetVersionMap( 5, 3994, 4037, aV5Map );
    3068       56134 :     SetVersionMap( 6, 3994, 4038, aV6Map );
    3069             : 
    3070       56134 :     SfxPoolItem** ppDefItems = EE_DLL().GetGlobalData()->GetDefItems();
    3071       56134 :     SetDefaults( ppDefItems );
    3072       56134 : }
    3073             : 
    3074       95100 : EditEngineItemPool::~EditEngineItemPool()
    3075             : {
    3076       95100 : }
    3077             : 
    3078        6366 : SvStream& EditEngineItemPool::Store( SvStream& rStream ) const
    3079             : {
    3080             :     // for a 3.1 export a hack has to be installed, as in there is a BUG in
    3081             :     // SfxItemSet::Load, but not subsequently after 3.1.
    3082             : 
    3083             :     // The selected range must be kept after Store, because itemsets are not
    3084             :     // stored until then...
    3085             : 
    3086        6366 :     long nVersion = rStream.GetVersion();
    3087        6366 :     bool b31Format = nVersion && ( nVersion <= SOFFICE_FILEFORMAT_31 );
    3088             : 
    3089        6366 :     EditEngineItemPool* pThis = const_cast<EditEngineItemPool*>(this);
    3090        6366 :     if ( b31Format )
    3091           0 :         pThis->SetStoringRange( 3997, 4022 );
    3092             :     else
    3093        6366 :         pThis->SetStoringRange( EE_ITEMS_START, EE_ITEMS_END );
    3094             : 
    3095        6366 :     return SfxItemPool::Store( rStream );
    3096         444 : }
    3097             : 
    3098             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11