LCOV - code coverage report
Current view: top level - libreoffice/sw/source/core/text - porlay.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 489 960 50.9 %
Date: 2012-12-27 Functions: 37 57 64.9 %
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             : 
      21             : #include "porlay.hxx"
      22             : #include "itrform2.hxx"
      23             : #include "porglue.hxx"
      24             : #include "porexp.hxx"   // SwQuoVadisPortion
      25             : #include "blink.hxx"    // pBlink
      26             : #include "redlnitr.hxx" // SwRedlineItr
      27             : #include "porfly.hxx"   // SwFlyCntPortion
      28             : #include <porrst.hxx>   // SwHangingPortion
      29             : #include <pormulti.hxx> // SwMultiPortion
      30             : #include <breakit.hxx>
      31             : #include <unicode/uchar.h>
      32             : #include <com/sun/star/i18n/ScriptType.hpp>
      33             : #include <com/sun/star/i18n/CTLScriptType.hpp>
      34             : #include <com/sun/star/i18n/WordType.hpp>
      35             : #include <paratr.hxx>
      36             : #include <editeng/adjitem.hxx>
      37             : #include <editeng/scripttypeitem.hxx>
      38             : #include <editeng/charhiddenitem.hxx>
      39             : #include <vcl/outdev.hxx>
      40             : #include <editeng/blnkitem.hxx>
      41             : #include <tools/multisel.hxx>
      42             : #include <unotools/charclass.hxx>
      43             : #include <i18npool/mslangid.hxx>
      44             : #include <charfmt.hxx>
      45             : #include <fchrfmt.hxx>
      46             : #include <docary.hxx>   // SwRedlineTbl
      47             : #include <redline.hxx>  // SwRedline
      48             : #include <section.hxx>
      49             : #include <switerator.hxx>
      50             : #include <IDocumentRedlineAccess.hxx>
      51             : #include <IDocumentSettingAccess.hxx>
      52             : #include <IDocumentContentOperations.hxx>
      53             : 
      54             : using namespace ::com::sun::star;
      55             : using namespace i18n::ScriptType;
      56             : 
      57             : #include <unicode/ubidi.h>
      58             : #include <i18nutil/scripttypedetector.hxx>
      59             : #include <i18nutil/unicode.hxx>
      60             : 
      61             : #define IS_JOINING_GROUP(c, g) ( u_getIntPropertyValue( (c), UCHAR_JOINING_GROUP ) == U_JG_##g )
      62             : #define isAinChar(c)        IS_JOINING_GROUP((c), AIN)
      63             : #define isAlefChar(c)       IS_JOINING_GROUP((c), ALEF)
      64             : #define isBaaChar(c)        IS_JOINING_GROUP((c), BEH)
      65             : #define isDalChar(c)        IS_JOINING_GROUP((c), DAL)
      66             : #define isFehChar(c)        IS_JOINING_GROUP((c), FEH)
      67             : #define isGafChar(c)        IS_JOINING_GROUP((c), GAF)
      68             : #define isHahChar(c)        IS_JOINING_GROUP((c), HAH)
      69             : #define isKafChar(c)        IS_JOINING_GROUP((c), KAF)
      70             : #define isLamChar(c)        IS_JOINING_GROUP((c), LAM)
      71             : #define isQafChar(c)        IS_JOINING_GROUP((c), QAF)
      72             : #define isRehChar(c)        IS_JOINING_GROUP((c), REH)
      73             : #define isTehMarbutaChar(c) IS_JOINING_GROUP((c), TEH_MARBUTA)
      74             : #define isWawChar(c)        IS_JOINING_GROUP((c), WAW)
      75             : #if ( (U_ICU_VERSION_MAJOR_NUM > 4 ) || ((U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM >= 4)) )
      76             : #define isYehChar(c)        (IS_JOINING_GROUP((c), YEH) || IS_JOINING_GROUP((c), FARSI_YEH))
      77             : #else
      78             : #define isYehChar(c)        (c == 0x626 || c == 0x649 || c == 0x64A || c == 0x678 || c == 0x6CC || c == 0x6CE || c == 0x6D0 || c == 0x6D1)
      79             : #endif
      80             : #define isSeenOrSadChar(c)  (IS_JOINING_GROUP((c), SAD) || IS_JOINING_GROUP((c), SEEN))
      81             : 
      82           0 : bool isTransparentChar ( sal_Unicode cCh )
      83             : {
      84           0 :     return u_getIntPropertyValue( cCh, UCHAR_JOINING_TYPE ) == U_JT_TRANSPARENT;
      85             : }
      86             : 
      87             : /*************************************************************************
      88             :  * lcl_IsLigature
      89             :  *
      90             :  * Checks if cCh + cNectCh builds a ligature (used for Kashidas)
      91             :  *************************************************************************/
      92             : 
      93           0 : static bool lcl_IsLigature( sal_Unicode cCh, sal_Unicode cNextCh )
      94             : {
      95             :             // Lam + Alef
      96           0 :     return ( isLamChar ( cCh ) && isAlefChar ( cNextCh ));
      97             : }
      98             : 
      99             : /*************************************************************************
     100             :  * lcl_ConnectToPrev
     101             :  *
     102             :  * Checks if cCh is connectable to cPrevCh (used for Kashidas)
     103             :  *************************************************************************/
     104             : 
     105           0 : static bool lcl_ConnectToPrev( sal_Unicode cCh, sal_Unicode cPrevCh )
     106             : {
     107           0 :     const int32_t nJoiningType = u_getIntPropertyValue( cPrevCh, UCHAR_JOINING_TYPE );
     108           0 :     bool bRet = nJoiningType != U_JT_RIGHT_JOINING && nJoiningType != U_JT_NON_JOINING;
     109             : 
     110             :     // check for ligatures cPrevChar + cChar
     111           0 :     if( bRet )
     112           0 :         bRet = !lcl_IsLigature( cPrevCh, cCh );
     113             : 
     114           0 :     return bRet;
     115             : }
     116             : 
     117             : /*************************************************************************
     118             :  * lcl_HasStrongLTR
     119             :  *************************************************************************/
     120           0 : static  bool lcl_HasStrongLTR ( const String& rTxt, xub_StrLen nStart, xub_StrLen nEnd )
     121             :  {
     122           0 :      for ( xub_StrLen nCharIdx = nStart; nCharIdx < nEnd; ++nCharIdx )
     123             :      {
     124           0 :          const UCharDirection nCharDir = u_charDirection ( rTxt.GetChar ( nCharIdx ));
     125           0 :          if ( nCharDir == U_LEFT_TO_RIGHT ||
     126             :               nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
     127             :               nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
     128           0 :              return true;
     129             :      }
     130           0 :      return false;
     131             :  }
     132             : 
     133             : /*************************************************************************
     134             :  * SwLineLayout::~SwLineLayout()
     135             :  *
     136             :  * class SwLineLayout: This is the layout of a single line, which is made
     137             :  * up of it's dimension, the character count and the word spacing in the
     138             :  * line.
     139             :  * Line objects are managed in an own pool, in order to store them continuously
     140             :  * in memory so that they are paged out together and don't fragment memory.
     141             :  *************************************************************************/
     142             : 
     143        1569 : SwLineLayout::~SwLineLayout()
     144             : {
     145         744 :     Truncate();
     146         744 :     delete pNext;
     147         744 :     if( pBlink )
     148           0 :         pBlink->Delete( this );
     149         744 :     delete pLLSpaceAdd;
     150         744 :     delete pKanaComp;
     151         825 : }
     152             : 
     153         251 : SwLinePortion *SwLineLayout::Insert( SwLinePortion *pIns )
     154             : {
     155             :    // First attribute change: copy mass and length from *pIns into the first
     156             :    // text portion
     157         251 :     if( !pPortion )
     158             :     {
     159         251 :         if( GetLen() )
     160             :         {
     161          45 :             pPortion = new SwTxtPortion( *(SwLinePortion*)this );
     162          45 :             if( IsBlinking() && pBlink )
     163             :             {
     164           0 :                 SetBlinking( sal_False );
     165           0 :                 pBlink->Replace( this, pPortion );
     166             :             }
     167             :         }
     168             :         else
     169             :         {
     170         206 :             SetPortion( pIns );
     171         206 :             return pIns;
     172             :         }
     173             :     }
     174             :     // Call with scope or we'll end up with recursion!
     175          45 :     return pPortion->SwLinePortion::Insert( pIns );
     176             : }
     177             : 
     178           0 : SwLinePortion *SwLineLayout::Append( SwLinePortion *pIns )
     179             : {
     180             :     // First attribute change: copy mass and length from *pIns into the first
     181             :     // text portion
     182           0 :     if( !pPortion )
     183           0 :         pPortion = new SwTxtPortion( *(SwLinePortion*)this );
     184             :     // Call with scope or we'll end up with recursion!
     185           0 :     return pPortion->SwLinePortion::Append( pIns );
     186             : }
     187             : 
     188             : // For special treatment of empty lines
     189             : 
     190         481 : sal_Bool SwLineLayout::Format( SwTxtFormatInfo &rInf )
     191             : {
     192         481 :     if( GetLen() )
     193         481 :         return SwTxtPortion::Format( rInf );
     194             :     else
     195             :     {
     196           0 :         Height( rInf.GetTxtHeight() );
     197           0 :         return sal_True;
     198             :     }
     199             : }
     200             : 
     201             : /*************************************************************************
     202             :  * SwLineLayout::CalcLeftMargin()
     203             :  *
     204             :  * We collect all FlyPortions at the beginning of the line and make that a
     205             :  * MarginPortion.
     206             :  *************************************************************************/
     207             : 
     208          19 : SwMarginPortion *SwLineLayout::CalcLeftMargin()
     209             : {
     210          23 :     SwMarginPortion *pLeft = (GetPortion() && GetPortion()->IsMarginPortion()) ?
     211          23 :         (SwMarginPortion *)GetPortion() : 0;
     212          19 :     if( !GetPortion() )
     213          15 :          SetPortion( new SwTxtPortion( *(SwLinePortion*)this ) );
     214          19 :     if( !pLeft )
     215             :     {
     216          19 :         pLeft = new SwMarginPortion( 0 );
     217          19 :         pLeft->SetPortion( GetPortion() );
     218          19 :         SetPortion( pLeft );
     219             :     }
     220             :     else
     221             :     {
     222           0 :         pLeft->Height( 0 );
     223           0 :         pLeft->Width( 0 );
     224           0 :         pLeft->SetLen( 0 );
     225           0 :         pLeft->SetAscent( 0 );
     226           0 :         pLeft->SetPortion( NULL );
     227           0 :         pLeft->SetFixWidth(0);
     228             :     }
     229             : 
     230          19 :     SwLinePortion *pPos = pLeft->GetPortion();
     231          57 :     while( pPos )
     232             :     {
     233          19 :         if( pPos->IsFlyPortion() )
     234             :         {
     235             :             // The FlyPortion get's sucked out ...
     236           1 :             pLeft->Join( (SwGluePortion*)pPos );
     237           1 :             pPos = pLeft->GetPortion();
     238           1 :             if( GetpKanaComp() && !GetKanaComp().empty() )
     239           0 :                 GetKanaComp().pop_front();
     240             :         }
     241             :         else
     242          18 :             pPos = 0;
     243             :     }
     244          19 :     return pLeft;
     245             : }
     246             : 
     247           2 : void SwLineLayout::InitSpaceAdd()
     248             : {
     249           2 :     if ( !pLLSpaceAdd )
     250           2 :         CreateSpaceAdd();
     251             :     else
     252           0 :         SetLLSpaceAdd( 0, 0 );
     253           2 : }
     254             : 
     255           2 : void SwLineLayout::CreateSpaceAdd( const long nInit )
     256             : {
     257           2 :     pLLSpaceAdd = new std::vector<long>;
     258           2 :     SetLLSpaceAdd( nInit, 0 );
     259           2 : }
     260             : 
     261             : /*************************************************************************
     262             :  * Local helper function. Returns true if there are only blanks
     263             :  * in [nStt, nEnd[
     264             :  *************************************************************************/
     265             : 
     266         282 : static bool lcl_HasOnlyBlanks( const XubString& rTxt, xub_StrLen nStt, xub_StrLen nEnd )
     267             : {
     268         282 :     bool bBlankOnly = true;
     269         571 :     while ( nStt < nEnd )
     270             :     {
     271         261 :         const sal_Unicode cChar = rTxt.GetChar( nStt++ );
     272         261 :         if ( ' ' != cChar && 0x3000 != cChar )
     273             :         {
     274         254 :             bBlankOnly = false;
     275         254 :             break;
     276             :         }
     277             :     }
     278         282 :     return bBlankOnly;
     279             : }
     280             : 
     281             : /*************************************************************************
     282             :  * SwLineLayout::CalcLine()
     283             :  *
     284             :  * Swapped out from FormatLine()
     285             :  *************************************************************************/
     286             : 
     287         885 : void SwLineLayout::CalcLine( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
     288             : {
     289         885 :     const KSHORT nLineWidth = rInf.RealWidth();
     290             : 
     291         885 :     KSHORT nFlyAscent = 0;
     292         885 :     KSHORT nFlyHeight = 0;
     293         885 :     KSHORT nFlyDescent = 0;
     294         885 :     bool bOnlyPostIts = true;
     295         885 :     SetHanging( sal_False );
     296             : 
     297         885 :     sal_Bool bTmpDummy = ( 0 == GetLen() );
     298         885 :     SwFlyCntPortion* pFlyCnt = 0;
     299         885 :     if( bTmpDummy )
     300             :     {
     301         274 :         nFlyAscent = 0;
     302         274 :         nFlyHeight = 0;
     303         274 :         nFlyDescent = 0;
     304             :     }
     305             : 
     306             :     // #i3952#
     307             :     const bool bIgnoreBlanksAndTabsForLineHeightCalculation =
     308         885 :             rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION);
     309             : 
     310         885 :     bool bHasBlankPortion = false;
     311         885 :     bool bHasOnlyBlankPortions = true;
     312             : 
     313         885 :     if( pPortion )
     314             :     {
     315         381 :         SetCntnt( sal_False );
     316         381 :         if( pPortion->IsBreakPortion() )
     317             :         {
     318           0 :             SetLen( pPortion->GetLen() );
     319           0 :             if( GetLen() )
     320           0 :                 bTmpDummy = sal_False;
     321             :         }
     322             :         else
     323             :         {
     324         381 :             KSHORT nLineHeight = Height();
     325         381 :             Init( GetPortion() );
     326         381 :             SwLinePortion *pPos = pPortion;
     327         381 :             SwLinePortion *pLast = this;
     328         381 :             KSHORT nMaxDescent = 0;
     329             : 
     330             :             // A group is a segment in the portion chain of pCurr or a fixed
     331             :             // portion spanning to the end or the next fixed portion
     332        1505 :             while( pPos )
     333             :             {
     334             :                 SAL_WARN_IF( POR_LIN == pPos->GetWhichPor(),
     335             :                         "sw.core", "SwLineLayout::CalcLine: don't use SwLinePortions !" );
     336             : 
     337             :                 // Null portions are eliminated. They can form if two FlyFrms
     338             :                 // overlap.
     339         743 :                 if( !pPos->Compress() )
     340             :                 {
     341             :                     // Only take over Height and Ascent if the rest of the line
     342             :                     // is empty.
     343          60 :                     if( !pPos->GetPortion() )
     344             :                     {
     345           2 :                         if( !Height() )
     346           0 :                             Height( pPos->Height() );
     347           2 :                         if( !GetAscent() )
     348           0 :                             SetAscent( pPos->GetAscent() );
     349             :                     }
     350          60 :                     delete pLast->Cut( pPos );
     351          60 :                     pPos = pLast->GetPortion();
     352          60 :                     continue;
     353             :                 }
     354             : 
     355         683 :                 const xub_StrLen nPorSttIdx = rInf.GetLineStart() + nLineLength;
     356         683 :                 nLineLength = nLineLength + pPos->GetLen();
     357         683 :                 AddPrtWidth( pPos->Width() );
     358             : 
     359             :                 // #i3952#
     360         683 :                 if ( bIgnoreBlanksAndTabsForLineHeightCalculation )
     361             :                 {
     362         688 :                     if ( pPos->InTabGrp() || pPos->IsHolePortion() ||
     363         296 :                             ( pPos->IsTextPortion() &&
     364          70 :                               lcl_HasOnlyBlanks( rInf.GetTxt(), nPorSttIdx, nPorSttIdx + pPos->GetLen() ) ) )
     365             :                     {
     366          29 :                         pLast = pPos;
     367          29 :                         pPos = pPos->GetPortion();
     368          29 :                         bHasBlankPortion = true;
     369          29 :                         continue;
     370             :                     }
     371             :                 }
     372             : 
     373         654 :                 bHasOnlyBlankPortions = false;
     374             : 
     375             :                 // We had an attribute change: Sum up/build maxima of length and mass
     376             : 
     377         654 :                 KSHORT nPosHeight = pPos->Height();
     378         654 :                 KSHORT nPosAscent = pPos->GetAscent();
     379             : 
     380             :                 SAL_WARN_IF( nPosHeight < nPosAscent,
     381             :                         "sw.core", "SwLineLayout::CalcLine: bad ascent or height" );
     382             : 
     383         654 :                 if( pPos->IsHangingPortion() )
     384             :                 {
     385           0 :                     SetHanging( sal_True );
     386           0 :                     rInf.GetParaPortion()->SetMargin( sal_True );
     387             :                 }
     388             : 
     389             :                 // To prevent that a paragraph-end-character does not change
     390             :                 // the line height through a Descent and thus causing the line
     391             :                 // to reformat.
     392         654 :                 if ( !pPos->IsBreakPortion() || !Height() )
     393             :                 {
     394         653 :                     if (!pPos->IsPostItsPortion()) bOnlyPostIts = false;
     395             : 
     396         653 :                     if( bTmpDummy && !nLineLength )
     397             :                     {
     398          71 :                         if( pPos->IsFlyPortion() )
     399             :                         {
     400           8 :                             if( nFlyHeight < nPosHeight )
     401           8 :                                 nFlyHeight = nPosHeight;
     402           8 :                             if( nFlyAscent < nPosAscent )
     403           8 :                                 nFlyAscent = nPosAscent;
     404           8 :                             if( nFlyDescent < nPosHeight - nPosAscent )
     405           8 :                                 nFlyDescent = nPosHeight - nPosAscent;
     406             :                         }
     407             :                         else
     408             :                         {
     409          63 :                             if( pPos->InNumberGrp() )
     410             :                             {
     411             :                                 KSHORT nTmp = rInf.GetFont()->GetAscent(
     412          63 :                                                 rInf.GetVsh(), *rInf.GetOut() );
     413          63 :                                 if( nTmp > nPosAscent )
     414             :                                 {
     415           2 :                                     nPosHeight += nTmp - nPosAscent;
     416           2 :                                     nPosAscent = nTmp;
     417             :                                 }
     418             :                                 nTmp = rInf.GetFont()->GetHeight( rInf.GetVsh(),
     419          63 :                                                                  *rInf.GetOut() );
     420          63 :                                 if( nTmp > nPosHeight )
     421           2 :                                     nPosHeight = nTmp;
     422             :                             }
     423          63 :                             Height( nPosHeight );
     424          63 :                             nAscent = nPosAscent;
     425          63 :                             nMaxDescent = nPosHeight - nPosAscent;
     426          71 :                         }
     427             :                     }
     428         582 :                     else if( !pPos->IsFlyPortion() )
     429             :                     {
     430         582 :                         if( Height() < nPosHeight )
     431             :                         {
     432             :                             // Height is set to 0 when Init() is called.
     433         314 :                             if (bIgnoreBlanksAndTabsForLineHeightCalculation && pPos->GetWhichPor() == POR_FLYCNT)
     434             :                                 // Compat flag set: take the line height, if it's larger.
     435         128 :                                 Height(std::max(nPosHeight, nLineHeight));
     436             :                             else
     437             :                                 // Just care about the portion height.
     438         186 :                                 Height(nPosHeight);
     439             :                         }
     440         583 :                         if( pPos->IsFlyCntPortion() || ( pPos->IsMultiPortion()
     441           1 :                             && ((SwMultiPortion*)pPos)->HasFlyInCntnt() ) )
     442         328 :                             rLine.SetFlyInCntBase();
     443         910 :                         if( pPos->IsFlyCntPortion() &&
     444         328 :                             ((SwFlyCntPortion*)pPos)->GetAlign() )
     445             :                         {
     446           0 :                             ((SwFlyCntPortion*)pPos)->SetMax( sal_False );
     447           0 :                             if( !pFlyCnt || pPos->Height() > pFlyCnt->Height() )
     448           0 :                                 pFlyCnt = (SwFlyCntPortion*)pPos;
     449             :                         }
     450             :                         else
     451             :                         {
     452         582 :                             if( nAscent < nPosAscent )
     453         318 :                                 nAscent = nPosAscent;
     454         582 :                             if( nMaxDescent < nPosHeight - nPosAscent )
     455         314 :                                 nMaxDescent = nPosHeight - nPosAscent;
     456             :                         }
     457             :                     }
     458             :                 }
     459           1 :                 else if( pPos->GetLen() )
     460           1 :                     bTmpDummy = sal_False;
     461             : 
     462         654 :                 if( !HasCntnt() && !pPos->InNumberGrp() )
     463             :                 {
     464         491 :                     if ( pPos->InExpGrp() )
     465             :                     {
     466           1 :                         XubString aTxt;
     467           1 :                         if( pPos->GetExpTxt( rInf, aTxt ) && aTxt.Len() )
     468           1 :                             SetCntnt( sal_True );
     469             :                     }
     470         602 :                     else if( ( pPos->InTxtGrp() || pPos->IsMultiPortion() ) &&
     471         112 :                              pPos->GetLen() )
     472         112 :                         SetCntnt( sal_True );
     473             :                 }
     474             : 
     475         206 :                 bTmpDummy = bTmpDummy && !HasCntnt() &&
     476         860 :                             ( !pPos->Width() || pPos->IsFlyPortion() );
     477             : 
     478         654 :                 pLast = pPos;
     479         654 :                 pPos = pPos->GetPortion();
     480             :             }
     481             : 
     482         381 :             if( pFlyCnt )
     483             :             {
     484           0 :                 if( pFlyCnt->Height() == Height() )
     485             :                 {
     486           0 :                     pFlyCnt->SetMax( sal_True );
     487           0 :                     if( Height() > nMaxDescent + nAscent )
     488             :                     {
     489           0 :                         if( 3 == pFlyCnt->GetAlign() ) // Bottom
     490           0 :                             nAscent = Height() - nMaxDescent;
     491           0 :                         else if( 2 == pFlyCnt->GetAlign() ) // Center
     492           0 :                             nAscent = ( Height() + nAscent - nMaxDescent ) / 2;
     493             :                     }
     494           0 :                     pFlyCnt->SetAscent( nAscent );
     495             :                 }
     496             :             }
     497             : 
     498         381 :             if( bTmpDummy && nFlyHeight )
     499             :             {
     500           8 :                 nAscent = nFlyAscent;
     501          16 :                 if( nFlyDescent > nFlyHeight - nFlyAscent )
     502           0 :                     Height( nFlyHeight + nFlyDescent );
     503             :                 else
     504           8 :                     Height( nFlyHeight );
     505             :             }
     506         373 :             else if( nMaxDescent > Height() - nAscent )
     507           7 :                 Height( nMaxDescent + nAscent );
     508             : 
     509         381 :             if( bOnlyPostIts && !( bHasBlankPortion && bHasOnlyBlankPortions ) )
     510             :             {
     511           0 :                 Height( rInf.GetFont()->GetHeight( rInf.GetVsh(), *rInf.GetOut() ) );
     512           0 :                 nAscent = rInf.GetFont()->GetAscent( rInf.GetVsh(), *rInf.GetOut() );
     513             :             }
     514             :         }
     515             :     }
     516             :     else
     517             :     {
     518         504 :         SetCntnt( !bTmpDummy );
     519             : 
     520             :         // #i3952#
     521         716 :         if ( bIgnoreBlanksAndTabsForLineHeightCalculation &&
     522         212 :              lcl_HasOnlyBlanks( rInf.GetTxt(), rInf.GetLineStart(), rInf.GetLineStart() + GetLen() ) )
     523             :         {
     524          25 :             bHasBlankPortion = true;
     525             :         }
     526             :     }
     527             : 
     528             :     // #i3952#
     529         885 :     if ( bHasBlankPortion && bHasOnlyBlankPortions )
     530             :     {
     531          25 :         sal_uInt16 nTmpAscent = GetAscent();
     532          25 :         sal_uInt16 nTmpHeight = Height();
     533          25 :         rLine.GetAttrHandler().GetDefaultAscentAndHeight( rInf.GetVsh(), *rInf.GetOut(), nTmpAscent, nTmpHeight );
     534          25 :         SetAscent( nTmpAscent );
     535          25 :         Height( nTmpHeight );
     536             :     }
     537             : 
     538             :     // Robust:
     539         885 :     if( nLineWidth < Width() )
     540           1 :         Width( nLineWidth );
     541             :     SAL_WARN_IF( nLineWidth < Width(), "sw.core", "SwLineLayout::CalcLine: line is bursting" );
     542         885 :     SetDummy( bTmpDummy );
     543         885 :     SetRedline( rLine.GetRedln() &&
     544         885 :         rLine.GetRedln()->CheckLine( rLine.GetStart(), rLine.GetEnd() ) );
     545         885 : }
     546             : 
     547             : // #i47162# - add optional parameter <_bNoFlyCntPorAndLinePor>
     548             : // to control, if the fly content portions and line portion are considered.
     549        1906 : void SwLineLayout::MaxAscentDescent( SwTwips& _orAscent,
     550             :                                      SwTwips& _orDescent,
     551             :                                      SwTwips& _orObjAscent,
     552             :                                      SwTwips& _orObjDescent,
     553             :                                      const SwLinePortion* _pDontConsiderPortion,
     554             :                                      const bool _bNoFlyCntPorAndLinePor ) const
     555             : {
     556        1906 :     _orAscent = 0;
     557        1906 :     _orDescent = 0;
     558        1906 :     _orObjAscent = 0;
     559        1906 :     _orObjDescent = 0;
     560             : 
     561        1906 :     const SwLinePortion* pTmpPortion = this;
     562        1906 :     if ( !pTmpPortion->GetLen() && pTmpPortion->GetPortion() )
     563             :     {
     564          43 :         pTmpPortion = pTmpPortion->GetPortion();
     565             :     }
     566             : 
     567        7538 :     while ( pTmpPortion )
     568             :     {
     569       12657 :         if ( !pTmpPortion->IsBreakPortion() && !pTmpPortion->IsFlyPortion() &&
     570        3717 :              ( !_bNoFlyCntPorAndLinePor ||
     571        1223 :                ( !pTmpPortion->IsFlyCntPortion() &&
     572        1603 :                  !(pTmpPortion == this && pTmpPortion->GetPortion() ) ) ) )
     573             :         {
     574        3084 :             SwTwips nPortionAsc = static_cast<SwTwips>(pTmpPortion->GetAscent());
     575        3084 :             SwTwips nPortionDesc = static_cast<SwTwips>(pTmpPortion->Height()) -
     576        3084 :                                    nPortionAsc;
     577             : 
     578        3084 :             const sal_Bool bFlyCmp = pTmpPortion->IsFlyCntPortion() ?
     579             :                                      static_cast<const SwFlyCntPortion*>(pTmpPortion)->IsMax() :
     580        3084 :                                      !( pTmpPortion == _pDontConsiderPortion );
     581             : 
     582        3084 :             if ( bFlyCmp )
     583             :             {
     584        2028 :                 _orObjAscent = Max( _orObjAscent, nPortionAsc );
     585        2028 :                 _orObjDescent = Max( _orObjDescent, nPortionDesc );
     586             :             }
     587             : 
     588        3084 :             if ( !pTmpPortion->IsFlyCntPortion() && !pTmpPortion->IsGrfNumPortion() )
     589             :             {
     590        2028 :                 _orAscent = Max( _orAscent, nPortionAsc );
     591        2028 :                 _orDescent = Max( _orDescent, nPortionDesc );
     592             :             }
     593             :         }
     594        3726 :         pTmpPortion = pTmpPortion->GetPortion();
     595             :     }
     596        1906 : }
     597             : 
     598         145 : SwCharRange &SwCharRange::operator+=(const SwCharRange &rRange)
     599             : {
     600         145 :     if(0 != rRange.nLen ) {
     601         145 :         if(0 == nLen) {
     602          23 :             nStart = rRange.nStart;
     603          23 :             nLen = rRange.nLen ;
     604             :         }
     605             :         else {
     606         122 :             if(rRange.nStart + rRange.nLen > nStart + nLen) {
     607         122 :                 nLen = rRange.nStart + rRange.nLen - nStart;
     608             :             }
     609         122 :             if(rRange.nStart < nStart) {
     610           0 :                 nLen += nStart - rRange.nStart;
     611           0 :                 nStart = rRange.nStart;
     612             :             }
     613             :         }
     614             :     }
     615         145 :     return *this;
     616             : }
     617             : 
     618         669 : SwScriptInfo::SwScriptInfo() :
     619             :     nInvalidityPos( 0 ),
     620         669 :     nDefaultDir( 0 )
     621             : {
     622         669 : };
     623             : 
     624         669 : SwScriptInfo::~SwScriptInfo()
     625             : {
     626         669 : }
     627             : 
     628             : /*************************************************************************
     629             :  * SwScriptInfo::WhichFont()
     630             :  *
     631             :  * Converts i18n Script Type (LATIN, ASIAN, COMPLEX, WEAK) to
     632             :  * Sw Script Types (SW_LATIN, SW_CJK, SW_CTL), used to identify the font
     633             : *************************************************************************/
     634             : 
     635        6853 : sal_uInt8 SwScriptInfo::WhichFont( xub_StrLen nIdx, const String* pTxt, const SwScriptInfo* pSI )
     636             : {
     637             :     SAL_WARN_IF( !pTxt && !pSI, "sw.core", "How should I determine the script type?" );
     638             :     sal_uInt16 nScript;
     639             : 
     640             :     // First we try to use our SwScriptInfo
     641        6853 :     if ( pSI )
     642        6853 :         nScript = pSI->ScriptType( nIdx );
     643             :     else
     644             :         // Ok, we have to ask the break iterator
     645           0 :         nScript = pBreakIt->GetRealScriptOfText( *pTxt, nIdx );
     646             : 
     647        6853 :     switch ( nScript ) {
     648        6818 :         case i18n::ScriptType::LATIN : return SW_LATIN;
     649          20 :         case i18n::ScriptType::ASIAN : return SW_CJK;
     650          15 :         case i18n::ScriptType::COMPLEX : return SW_CTL;
     651             :     }
     652             : 
     653             :     OSL_FAIL( "Somebody tells lies about the script type!" );
     654           0 :     return SW_LATIN;
     655             : }
     656             : 
     657             : /*************************************************************************
     658             :  * SwScriptInfo::InitScriptInfo()
     659             :  *
     660             :  * searches for script changes in rTxt and stores them
     661             :  *************************************************************************/
     662             : 
     663           0 : void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode )
     664             : {
     665           0 :     InitScriptInfo( rNode, nDefaultDir == UBIDI_RTL );
     666           0 : }
     667             : 
     668         669 : void SwScriptInfo::InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL )
     669             : {
     670         669 :     if( !pBreakIt->GetBreakIter().is() )
     671         669 :         return;
     672             : 
     673         669 :     const String& rTxt = rNode.GetTxt();
     674             : 
     675             :     //
     676             :     // HIDDEN TEXT INFORMATION
     677             :     //
     678         669 :     Range aRange( 0, rTxt.Len() ? rTxt.Len() - 1 : 0 );
     679         669 :     MultiSelection aHiddenMulti( aRange );
     680         669 :     CalcHiddenRanges( rNode, aHiddenMulti );
     681             : 
     682         669 :     aHiddenChg.clear();
     683         669 :     sal_uInt16 i = 0;
     684         669 :     for( i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
     685             :     {
     686           0 :         const Range& rRange = aHiddenMulti.GetRange( i );
     687           0 :         const xub_StrLen nStart = (xub_StrLen)rRange.Min();
     688           0 :         const xub_StrLen nEnd = (xub_StrLen)rRange.Max() + 1;
     689             : 
     690           0 :         aHiddenChg.push_back( nStart );
     691           0 :         aHiddenChg.push_back( nEnd );
     692             :     }
     693             : 
     694             :     //
     695             :     // SCRIPT AND SCRIPT RELATED INFORMATION
     696             :     //
     697             : 
     698         669 :     xub_StrLen nChg = nInvalidityPos;
     699             : 
     700             :     // STRING_LEN means the data structure is up to date
     701         669 :     nInvalidityPos = STRING_LEN;
     702             : 
     703             :     // this is the default direction
     704         669 :     nDefaultDir = static_cast<sal_uInt8>(bRTL ? UBIDI_RTL : UBIDI_LTR);
     705             : 
     706             :     // counter for script info arrays
     707         669 :     sal_uInt16 nCnt = 0;
     708             :     // counter for compression information arrays
     709         669 :     sal_uInt16 nCntComp = 0;
     710             :     // counter for kashida array
     711         669 :     sal_uInt16 nCntKash = 0;
     712             : 
     713         669 :     sal_uInt8 nScript = i18n::ScriptType::LATIN;
     714             : 
     715             :     // compression type
     716         669 :     const SwCharCompressType aCompEnum = rNode.getIDocumentSettingAccess()->getCharacterCompressionType();
     717             : 
     718             :     // justification type
     719             :     const bool bAdjustBlock = SVX_ADJUST_BLOCK ==
     720         669 :                                   rNode.GetSwAttrSet().GetAdjust().GetAdjust();
     721             : 
     722             :     //
     723             :     // FIND INVALID RANGES IN SCRIPT INFO ARRAYS:
     724             :     //
     725             : 
     726         669 :     if( nChg )
     727             :     {
     728             :         // if change position = 0 we do not use any data from the arrays
     729             :         // because by deleting all characters of the first group at the beginning
     730             :         // of a paragraph nScript is set to a wrong value
     731             :         SAL_WARN_IF( !CountScriptChg(), "sw.core", "Where're my changes of script?" );
     732           0 :         while( nCnt < CountScriptChg() )
     733             :         {
     734           0 :             if ( nChg > GetScriptChg( nCnt ) )
     735           0 :                 nCnt++;
     736             :             else
     737             :             {
     738           0 :                 nScript = GetScriptType( nCnt );
     739           0 :                 break;
     740             :             }
     741             :         }
     742           0 :         if( CHARCOMPRESS_NONE != aCompEnum )
     743             :         {
     744           0 :             while( nCntComp < CountCompChg() )
     745             :             {
     746           0 :                 if ( nChg > GetCompStart( nCntComp ) )
     747           0 :                     nCntComp++;
     748             :                 else
     749           0 :                     break;
     750             :             }
     751             :         }
     752           0 :         if ( bAdjustBlock )
     753             :         {
     754           0 :             while( nCntKash < CountKashida() )
     755             :             {
     756           0 :                 if ( nChg > GetKashida( nCntKash ) )
     757           0 :                     nCntKash++;
     758             :                 else
     759           0 :                     break;
     760             :             }
     761             :         }
     762             :     }
     763             : 
     764             :     //
     765             :     // ADJUST nChg VALUE:
     766             :     //
     767             : 
     768             :     // by stepping back one position we know that we are inside a group
     769             :     // declared as an nScript group
     770         669 :     if ( nChg )
     771           0 :         --nChg;
     772             : 
     773         669 :     const xub_StrLen nGrpStart = nCnt ? GetScriptChg( nCnt - 1 ) : 0;
     774             : 
     775             :     // we go back in our group until we reach the first character of
     776             :     // type nScript
     777        2007 :     while ( nChg > nGrpStart &&
     778         669 :             nScript != pBreakIt->GetBreakIter()->getScriptType( rTxt, nChg ) )
     779           0 :         --nChg;
     780             : 
     781             :     // If we are at the start of a group, we do not trust nScript,
     782             :     // we better get nScript from the breakiterator:
     783         669 :     if ( nChg == nGrpStart )
     784         669 :         nScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( rTxt, nChg );
     785             : 
     786             :     //
     787             :     // INVALID DATA FROM THE SCRIPT INFO ARRAYS HAS TO BE DELETED:
     788             :     //
     789             : 
     790             :     // remove invalid entries from script information arrays
     791         669 :     aScriptChanges.erase( aScriptChanges.begin() + nCnt, aScriptChanges.end() );
     792             : 
     793             :     // get the start of the last compression group
     794         669 :     sal_uInt16 nLastCompression = nChg;
     795         669 :     if( nCntComp )
     796             :     {
     797           0 :         --nCntComp;
     798           0 :         nLastCompression = GetCompStart( nCntComp );
     799           0 :         if( nChg >= nLastCompression + GetCompLen( nCntComp ) )
     800             :         {
     801           0 :             nLastCompression = nChg;
     802           0 :             ++nCntComp;
     803             :         }
     804             :     }
     805             : 
     806             :     // remove invalid entries from compression information arrays
     807         669 :     aCompressionChanges.erase(aCompressionChanges.begin() + nCntComp, aCompressionChanges.end() );
     808             : 
     809             :     // get the start of the last kashida group
     810         669 :     sal_uInt16 nLastKashida = nChg;
     811         669 :     if( nCntKash && i18n::ScriptType::COMPLEX == nScript )
     812             :     {
     813           0 :         --nCntKash;
     814           0 :         nLastKashida = GetKashida( nCntKash );
     815             :     }
     816             : 
     817             :     // remove invalid entries from kashida array
     818         669 :     aKashida.erase( aKashida.begin() + nCntKash, aKashida.end() );
     819             : 
     820             :     //
     821             :     // TAKE CARE OF WEAK CHARACTERS: WE MUST FIND AN APPROPRIATE
     822             :     // SCRIPT FOR WEAK CHARACTERS AT THE BEGINNING OF A PARAGRAPH
     823             :     //
     824             : 
     825         669 :     if( WEAK == pBreakIt->GetBreakIter()->getScriptType( rTxt, nChg ) )
     826             :     {
     827             :         // If the beginning of the current group is weak, this means that
     828             :         // all of the characters in this grounp are weak. We have to assign
     829             :         // the scripts to these characters depending on the fonts which are
     830             :         // set for these characters to display them.
     831             :         xub_StrLen nEnd =
     832         207 :                 (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( rTxt, nChg, WEAK );
     833             : 
     834         207 :         if( nEnd > rTxt.Len() )
     835          73 :             nEnd = rTxt.Len();
     836             : 
     837         207 :         nScript = (sal_uInt8)GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() );
     838             : 
     839             :         SAL_WARN_IF( i18n::ScriptType::LATIN != nScript &&
     840             :                 i18n::ScriptType::ASIAN != nScript &&
     841             :                 i18n::ScriptType::COMPLEX != nScript, "sw.core", "Wrong default language" );
     842             : 
     843         207 :         nChg = nEnd;
     844             : 
     845             :         // Get next script type or set to weak in order to exit
     846         207 :         sal_uInt8 nNextScript = ( nEnd < rTxt.Len() ) ?
     847         213 :            (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( rTxt, nEnd ) :
     848         213 :            (sal_uInt8)WEAK;
     849             : 
     850         207 :         if ( nScript != nNextScript )
     851             :         {
     852         205 :             aScriptChanges.push_back( ScriptChangeInfo(nEnd, nScript) );
     853         205 :             nCnt++;
     854         205 :             nScript = nNextScript;
     855             :         }
     856             :     }
     857             : 
     858             :     //
     859             :     // UPDATE THE SCRIPT INFO ARRAYS:
     860             :     //
     861             : 
     862        1802 :     while ( nChg < rTxt.Len() || ( aScriptChanges.empty() && !rTxt.Len() ) )
     863             :     {
     864             :         SAL_WARN_IF( i18n::ScriptType::WEAK == nScript,
     865             :                 "sw.core", "Inserting WEAK into SwScriptInfo structure" );
     866             :         SAL_WARN_IF( STRING_LEN == nChg, "sw.core", "65K? Strange length of script section" );
     867             : 
     868         464 :         xub_StrLen nSearchStt = nChg;
     869         464 :         nChg = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( rTxt, nSearchStt, nScript );
     870             : 
     871         464 :         if ( nChg > rTxt.Len() )
     872           0 :             nChg = rTxt.Len();
     873             : 
     874             :         // #i28203#
     875             :         // for 'complex' portions, we make sure that a portion does not contain more
     876             :         // than one script:
     877         464 :         if( i18n::ScriptType::COMPLEX == nScript )
     878             :         {
     879           2 :             const short nScriptType = ScriptTypeDetector::getCTLScriptType( rTxt, nSearchStt );
     880           2 :             xub_StrLen nNextCTLScriptStart = nSearchStt;
     881           2 :             short nCurrentScriptType = nScriptType;
     882           7 :             while( com::sun::star::i18n::CTLScriptType::CTL_UNKNOWN == nCurrentScriptType || nScriptType == nCurrentScriptType )
     883             :             {
     884           5 :                 nNextCTLScriptStart = (xub_StrLen)ScriptTypeDetector::endOfCTLScriptType( rTxt, nNextCTLScriptStart );
     885           5 :                 if( nNextCTLScriptStart < rTxt.Len() && nNextCTLScriptStart < nChg )
     886           3 :                     nCurrentScriptType = ScriptTypeDetector::getCTLScriptType( rTxt, nNextCTLScriptStart );
     887             :                 else
     888           2 :                     break;
     889             :             }
     890           2 :             nChg = Min( nChg, nNextCTLScriptStart );
     891             :         }
     892             : 
     893             :         // special case for dotted circle since it can be used with complex
     894             :         // before a mark, so we want it associated with the mark's script
     895         928 :         if (nChg < rTxt.Len() && nChg > 0 && (i18n::ScriptType::WEAK ==
     896         464 :             pBreakIt->GetBreakIter()->getScriptType(rTxt,nChg - 1)))
     897             :         {
     898           0 :             int8_t nType = u_charType(rTxt.GetChar(nChg) );
     899           0 :             if (nType == U_NON_SPACING_MARK || nType == U_ENCLOSING_MARK ||
     900             :                 nType == U_COMBINING_SPACING_MARK )
     901             :             {
     902           0 :                 aScriptChanges.push_back( ScriptChangeInfo(nChg-1, nScript) );
     903             :             }
     904             :             else
     905             :             {
     906           0 :                 aScriptChanges.push_back( ScriptChangeInfo(nChg, nScript) );
     907             :             }
     908             :         }
     909             :         else
     910             :         {
     911         464 :             aScriptChanges.push_back( ScriptChangeInfo(nChg, nScript) );
     912             :         }
     913         464 :         ++nCnt;
     914             : 
     915             :         // if current script is asian, we search for compressable characters
     916             :         // in this range
     917         464 :         if ( CHARCOMPRESS_NONE != aCompEnum &&
     918             :              i18n::ScriptType::ASIAN == nScript )
     919             :         {
     920           0 :             sal_uInt8 ePrevState = NONE;
     921             :             sal_uInt8 eState;
     922           0 :             sal_uInt16 nPrevChg = nLastCompression;
     923             : 
     924           0 :             while ( nLastCompression < nChg )
     925             :             {
     926           0 :                 sal_Unicode cChar = rTxt.GetChar( nLastCompression );
     927             : 
     928             :                 // examine current character
     929           0 :                 switch ( cChar )
     930             :                 {
     931             :                 // Left punctuation found
     932             :                 case 0x3008: case 0x300A: case 0x300C: case 0x300E:
     933             :                 case 0x3010: case 0x3014: case 0x3016: case 0x3018:
     934             :                 case 0x301A: case 0x301D:
     935           0 :                     eState = SPECIAL_LEFT;
     936           0 :                     break;
     937             :                 // Right punctuation found
     938             :                 case 0x3001: case 0x3002: case 0x3009: case 0x300B:
     939             :                 case 0x300D: case 0x300F: case 0x3011: case 0x3015:
     940             :                 case 0x3017: case 0x3019: case 0x301B: case 0x301E:
     941             :                 case 0x301F:
     942           0 :                     eState = SPECIAL_RIGHT;
     943           0 :                     break;
     944             :                 default:
     945           0 :                     eState = static_cast<sal_uInt8>( ( 0x3040 <= cChar && 0x3100 > cChar ) ? KANA : NONE );
     946             :                 }
     947             : 
     948             :                 // insert range of compressable characters
     949           0 :                 if( ePrevState != eState )
     950             :                 {
     951           0 :                     if ( ePrevState != NONE )
     952             :                     {
     953             :                         // insert start and type
     954           0 :                         if ( CHARCOMPRESS_PUNCTUATION_KANA == aCompEnum ||
     955             :                              ePrevState != KANA )
     956             :                         {
     957           0 :                             aCompressionChanges.push_back( CompressionChangeInfo(nPrevChg, nLastCompression - nPrevChg, ePrevState) );
     958             :                         }
     959             :                     }
     960             : 
     961           0 :                     ePrevState = eState;
     962           0 :                     nPrevChg = nLastCompression;
     963             :                 }
     964             : 
     965           0 :                 nLastCompression++;
     966             :             }
     967             : 
     968             :             // we still have to examine last entry
     969           0 :             if ( ePrevState != NONE )
     970             :             {
     971             :                 // insert start and type
     972           0 :                 if ( CHARCOMPRESS_PUNCTUATION_KANA == aCompEnum ||
     973             :                      ePrevState != KANA )
     974             :                 {
     975           0 :                     aCompressionChanges.push_back( CompressionChangeInfo(nPrevChg, nLastCompression - nPrevChg, ePrevState) );
     976             :                 }
     977           0 :             }
     978             :         }
     979             : 
     980             :         // we search for connecting opportunities (kashida)
     981         464 :         else if ( bAdjustBlock && i18n::ScriptType::COMPLEX == nScript )
     982             :         {
     983           0 :             SwScanner aScanner( rNode, rNode.GetTxt(), 0, ModelToViewHelper(),
     984             :                                 i18n::WordType::DICTIONARY_WORD,
     985           0 :                                 nLastKashida, nChg );
     986             : 
     987             :             // the search has to be performed on a per word base
     988           0 :             while ( aScanner.NextWord() )
     989             :             {
     990           0 :                 const XubString& rWord = aScanner.GetWord();
     991             : 
     992           0 :                 xub_StrLen nIdx = 0;
     993           0 :                 xub_StrLen nKashidaPos = STRING_LEN;
     994             :                 sal_Unicode cCh;
     995           0 :                 sal_Unicode cPrevCh = 0;
     996             : 
     997           0 :                 sal_uInt16 nPriorityLevel = 7; // 0..6 = level found
     998             :                                            // 7 not found
     999             : 
    1000           0 :                 xub_StrLen nWordLen = rWord.Len();
    1001             : 
    1002             :                 // ignore trailing vowel chars
    1003           0 :                 while( nWordLen && isTransparentChar( rWord.GetChar( nWordLen - 1 )))
    1004           0 :                     --nWordLen;
    1005             : 
    1006           0 :                 while (nIdx < nWordLen)
    1007             :                 {
    1008           0 :                     cCh = rWord.GetChar( nIdx );
    1009             : 
    1010             :                     // 1. Priority:
    1011             :                     // after user inserted kashida
    1012           0 :                     if ( 0x640 == cCh )
    1013             :                     {
    1014           0 :                         nKashidaPos = aScanner.GetBegin() + nIdx;
    1015           0 :                         nPriorityLevel = 0;
    1016             :                     }
    1017             : 
    1018             :                     // 2. Priority:
    1019             :                     // after a Seen or Sad
    1020           0 :                     if (nPriorityLevel >= 1 && nIdx < nWordLen - 1)
    1021             :                     {
    1022           0 :                         if( isSeenOrSadChar( cCh )
    1023           0 :                          && (rWord.GetChar( nIdx+1 ) != 0x200C) ) // #i98410#: prevent ZWNJ expansion
    1024             :                         {
    1025           0 :                             nKashidaPos  = aScanner.GetBegin() + nIdx;
    1026           0 :                             nPriorityLevel = 1;
    1027             :                         }
    1028             :                     }
    1029             : 
    1030             :                     // 3. Priority:
    1031             :                     // before final form of Teh Marbuta, Hah, Dal
    1032           0 :                     if ( nPriorityLevel >= 2 && nIdx > 0 )
    1033             :                     {
    1034           0 :                         if ( isTehMarbutaChar ( cCh ) || // Teh Marbuta (right joining)
    1035           0 :                              isDalChar ( cCh ) ||        // Dal (right joining) final form may appear in the middle of word
    1036           0 :                              ( isHahChar ( cCh ) && nIdx == nWordLen - 1))  // Hah (dual joining) only at end of word
    1037             :                         {
    1038             : 
    1039             :                             SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
    1040             :                             // check if character is connectable to previous character,
    1041           0 :                             if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
    1042             :                             {
    1043           0 :                                 nKashidaPos = aScanner.GetBegin() + nIdx - 1;
    1044           0 :                                 nPriorityLevel = 2;
    1045             :                             }
    1046             :                         }
    1047             :                     }
    1048             : 
    1049             :                     // 4. Priority:
    1050             :                     // before final form of Alef, Lam or Kaf
    1051           0 :                     if ( nPriorityLevel >= 3 && nIdx > 0 )
    1052             :                     {
    1053           0 :                         if ( isAlefChar ( cCh ) ||   // Alef (right joining) final form may appear in the middle of word
    1054           0 :                              (( isLamChar ( cCh ) || // Lam
    1055           0 :                               isKafChar ( cCh )   || // Kaf (both dual joining)
    1056           0 :                               isGafChar ( cCh ) )
    1057             :                               && nIdx == nWordLen - 1))  // only at end of word
    1058             :                         {
    1059             :                             SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
    1060             :                             // check if character is connectable to previous character,
    1061           0 :                             if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
    1062             :                             {
    1063           0 :                                 nKashidaPos = aScanner.GetBegin() + nIdx - 1;
    1064           0 :                                 nPriorityLevel = 3;
    1065             :                             }
    1066             :                         }
    1067             :                     }
    1068             : 
    1069             :                     // 5. Priority:
    1070             :                     // before media Bah
    1071           0 :                     if ( nPriorityLevel >= 4 && nIdx > 0 && nIdx < nWordLen - 1 )
    1072             :                     {
    1073           0 :                         if ( isBaaChar ( cCh )) // Bah
    1074             :                         {
    1075             :                             // check if next character is Reh, Yeh or Alef Maksura
    1076           0 :                             sal_Unicode cNextCh = rWord.GetChar( nIdx + 1 );
    1077           0 :                             if ( isRehChar ( cNextCh ) || isYehChar ( cNextCh ))
    1078             :                            {
    1079             :                                 SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
    1080             :                                 // check if character is connectable to previous character,
    1081           0 :                                 if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
    1082             :                                 {
    1083           0 :                                     nKashidaPos = aScanner.GetBegin() + nIdx - 1;
    1084           0 :                                     nPriorityLevel = 4;
    1085             :                                 }
    1086             :                             }
    1087             :                         }
    1088             :                     }
    1089             : 
    1090             :                     // 6. Priority:
    1091             :                     // before the final form of Waw, Ain, Qaf and Fa
    1092           0 :                     if ( nPriorityLevel >= 5 && nIdx > 0 )
    1093             :                     {
    1094           0 :                         if ( isWawChar ( cCh )   || // Wav (right joining)
    1095             :                                                     // final form may appear in the middle of word
    1096           0 :                              (( isAinChar ( cCh ) ||  // Ain (dual joining)
    1097           0 :                                 isQafChar ( cCh ) ||  // Qaf (dual joining)
    1098           0 :                                 isFehChar ( cCh ) )   // Feh (dual joining)
    1099             :                                 && nIdx == nWordLen - 1))  // only at end of word
    1100             :                         {
    1101             :                             SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
    1102             :                             // check if character is connectable to previous character,
    1103           0 :                             if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
    1104             :                             {
    1105           0 :                                 nKashidaPos = aScanner.GetBegin() + nIdx - 1;
    1106           0 :                                 nPriorityLevel = 5;
    1107             :                             }
    1108             :                         }
    1109             :                     }
    1110             : 
    1111             :                     // other connecting possibilities
    1112           0 :                     if ( nPriorityLevel >= 6 && nIdx > 0 )
    1113             :                     {
    1114             :                         // remaining right joiners
    1115             :                         // Reh, Zain, Thal,
    1116           0 :                         if ( isRehChar ( cCh ) ||   // Reh Zain (right joining)
    1117             :                                                     // final form may appear in the middle of word
    1118             :                              ( 0x60C <= cCh && 0x6FE >= cCh // all others
    1119             :                               && nIdx == nWordLen - 1))   // only at end of word
    1120             :                         {
    1121             :                             SAL_WARN_IF( 0 == cPrevCh, "sw.core", "No previous character" );
    1122             :                             // check if character is connectable to previous character,
    1123           0 :                             if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
    1124             :                             {
    1125           0 :                                 nKashidaPos = aScanner.GetBegin() + nIdx - 1;
    1126           0 :                                 nPriorityLevel = 6;
    1127             :                             }
    1128             :                         }
    1129             :                     }
    1130             : 
    1131             :                     // Do not consider Fathatan, Dammatan, Kasratan, Fatha,
    1132             :                     // Damma, Kasra, Shadda and Sukun when checking if
    1133             :                     // a character can be connected to previous character.
    1134           0 :                     if ( !isTransparentChar ( cCh) )
    1135           0 :                         cPrevCh = cCh;
    1136             : 
    1137           0 :                    ++nIdx;
    1138             :                 } // end of current word
    1139             : 
    1140           0 :                 if ( STRING_LEN != nKashidaPos )
    1141             :                 {
    1142           0 :                     aKashida.insert( aKashida.begin() + nCntKash, nKashidaPos);
    1143           0 :                     nCntKash++;
    1144             :                 }
    1145           0 :             } // end of kashida search
    1146             :         }
    1147             : 
    1148         464 :         if ( nChg < rTxt.Len() )
    1149           0 :             nScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( rTxt, nChg );
    1150             : 
    1151         464 :         nLastCompression = nChg;
    1152         464 :         nLastKashida = nChg;
    1153             :     }
    1154             : 
    1155             : #if OSL_DEBUG_LEVEL > 0
    1156             :     // check kashida data
    1157             :     long nTmpKashidaPos = -1;
    1158             :     bool bWrongKash = false;
    1159             :     for (i = 0; i < aKashida.size(); ++i )
    1160             :     {
    1161             :         long nCurrKashidaPos = GetKashida( i );
    1162             :         if ( nCurrKashidaPos <= nTmpKashidaPos )
    1163             :         {
    1164             :             bWrongKash = true;
    1165             :             break;
    1166             :         }
    1167             :         nTmpKashidaPos = nCurrKashidaPos;
    1168             :     }
    1169             :     SAL_WARN_IF( bWrongKash, "sw.core", "Kashida array contains wrong data" );
    1170             : #endif
    1171             : 
    1172             :     // remove invalid entries from direction information arrays
    1173         669 :     aDirectionChanges.clear();
    1174             : 
    1175             :     // Perform Unicode Bidi Algorithm for text direction information
    1176         669 :     bool bPerformUBA = UBIDI_LTR != nDefaultDir;
    1177         669 :     nCnt = 0;
    1178        2007 :     while( !bPerformUBA && nCnt < CountScriptChg() )
    1179             :     {
    1180         669 :         if ( i18n::ScriptType::COMPLEX == GetScriptType( nCnt++ ) )
    1181           2 :             bPerformUBA = true;
    1182             :     }
    1183             : 
    1184             :     // do not call the unicode bidi algorithm if not required
    1185         669 :     if ( bPerformUBA )
    1186             :     {
    1187           2 :         UpdateBidiInfo( rTxt );
    1188             : 
    1189             :         // #i16354# Change script type for RTL text to CTL:
    1190             :         // 1. All text in RTL runs will use the CTL font
    1191             :         // #i89825# change the script type also to CTL (hennerdrewes)
    1192             :         // 2. Text in embedded LTR runs that does not have any strong LTR characters (numbers!)
    1193           5 :         for ( sal_uInt32 nDirIdx = 0; nDirIdx < aDirectionChanges.size(); ++nDirIdx )
    1194             :         {
    1195           3 :             const sal_uInt8 nCurrDirType = GetDirType( nDirIdx );
    1196             :                 // nStart ist start of RTL run:
    1197           3 :                 const xub_StrLen nStart = nDirIdx > 0 ? GetDirChg( nDirIdx - 1 ) : 0;
    1198             :                 // nEnd is end of RTL run:
    1199           3 :                 const xub_StrLen nEnd = GetDirChg( nDirIdx );
    1200             : 
    1201           3 :             if ( nCurrDirType % 2 == UBIDI_RTL  || // text in RTL run
    1202           0 :                 ( nCurrDirType > UBIDI_LTR && !lcl_HasStrongLTR( rTxt, nStart, nEnd ) ) ) // non-strong text in embedded LTR run
    1203             :             {
    1204             :                 // nScriptIdx points into the ScriptArrays:
    1205           2 :                 size_t nScriptIdx = 0;
    1206             : 
    1207             :                 // Skip entries in ScriptArray which are not inside the RTL run:
    1208             :                 // Make nScriptIdx become the index of the script group with
    1209             :                 // 1. nStartPosOfGroup <= nStart and
    1210             :                 // 2. nEndPosOfGroup > nStart
    1211           4 :                 while ( GetScriptChg( nScriptIdx ) <= nStart )
    1212           0 :                     ++nScriptIdx;
    1213             : 
    1214           2 :                 const xub_StrLen nStartPosOfGroup = nScriptIdx ? GetScriptChg( nScriptIdx - 1 ) : 0;
    1215           2 :                 const sal_uInt8 nScriptTypeOfGroup = GetScriptType( nScriptIdx );
    1216             : 
    1217             :                 SAL_WARN_IF( nStartPosOfGroup > nStart || GetScriptChg( nScriptIdx ) <= nStart,
    1218             :                         "sw.core", "Script override with CTL font trouble" );
    1219             : 
    1220             :                 // Check if we have to insert a new script change at
    1221             :                 // position nStart. If nStartPosOfGroup < nStart,
    1222             :                 // we have to insert a new script change:
    1223           2 :                 if ( nStart > 0 && nStartPosOfGroup < nStart )
    1224             :                 {
    1225           0 :                     aScriptChanges.insert(aScriptChanges.begin() + nScriptIdx,
    1226           0 :                                           ScriptChangeInfo(nStart, nScriptTypeOfGroup) );
    1227           0 :                     ++nScriptIdx;
    1228             :                 }
    1229             : 
    1230             :                 // Remove entries in ScriptArray which end inside the RTL run:
    1231           5 :                 while ( nScriptIdx < aScriptChanges.size() && GetScriptChg( nScriptIdx ) <= nEnd )
    1232             :                 {
    1233           1 :                     aScriptChanges.erase(aScriptChanges.begin() + nScriptIdx);
    1234             :                 }
    1235             : 
    1236             :                 // Insert a new entry in ScriptArray for the end of the RTL run:
    1237           2 :                 aScriptChanges.insert(aScriptChanges.begin() + nScriptIdx,
    1238           4 :                                       ScriptChangeInfo(nEnd, i18n::ScriptType::COMPLEX) );
    1239             : 
    1240             : #if OSL_DEBUG_LEVEL > 0
    1241             :                 // Check that ScriptChangeInfos are in increasing order of
    1242             :                 // position and that we don't have "empty" changes.
    1243             :                 sal_uInt8 nLastTyp = i18n::ScriptType::WEAK;
    1244             :                 xub_StrLen nLastPos = 0;
    1245             :                 for (std::vector<ScriptChangeInfo>::const_iterator i2 = aScriptChanges.begin(); i2 < aScriptChanges.end(); ++i2)
    1246             :                 {
    1247             :                     SAL_WARN_IF( nLastTyp == i2->type ||
    1248             :                             nLastPos >= i2->position,
    1249             :                             "sw.core", "Heavy InitScriptType() confusion" );
    1250             :                     nLastPos = i2->position;
    1251             :                     nLastTyp = i2->type;
    1252             :                 }
    1253             : #endif
    1254             :             }
    1255             :         }
    1256         669 :     }
    1257             : }
    1258             : 
    1259           2 : void SwScriptInfo::UpdateBidiInfo( const String& rTxt )
    1260             : {
    1261             :     // remove invalid entries from direction information arrays
    1262           2 :     aDirectionChanges.clear();
    1263             :     //
    1264             :     // Bidi functions from icu 2.0
    1265             :     //
    1266           2 :     UErrorCode nError = U_ZERO_ERROR;
    1267           2 :     UBiDi* pBidi = ubidi_openSized( rTxt.Len(), 0, &nError );
    1268           2 :     nError = U_ZERO_ERROR;
    1269             : 
    1270           4 :     ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(rTxt.GetBuffer()), rTxt.Len(),    // UChar != sal_Unicode in MinGW
    1271           6 :                    nDefaultDir, NULL, &nError );
    1272           2 :     nError = U_ZERO_ERROR;
    1273           2 :     long nCount = ubidi_countRuns( pBidi, &nError );
    1274           2 :     int32_t nStart = 0;
    1275             :     int32_t nEnd;
    1276             :     UBiDiLevel nCurrDir;
    1277           5 :     for ( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
    1278             :     {
    1279           3 :         ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir );
    1280           3 :         aDirectionChanges.push_back( DirectionChangeInfo(nEnd, nCurrDir) );
    1281           3 :         nStart = nEnd;
    1282             :     }
    1283             : 
    1284           2 :     ubidi_close( pBidi );
    1285           2 : }
    1286             : 
    1287             : 
    1288             : /*************************************************************************
    1289             :  * SwScriptInfo::NextScriptChg(..)
    1290             :  * returns the position of the next character which belongs to another script
    1291             :  * than the character of the actual (input) position.
    1292             :  * If there's no script change until the end of the paragraph, it will return
    1293             :  * STRING_LEN.
    1294             :  * Scripts are Asian (Chinese, Japanese, Korean),
    1295             :  *             Latin ( English etc.)
    1296             :  *         and Complex ( Hebrew, Arabian )
    1297             :  *************************************************************************/
    1298             : 
    1299        1161 : xub_StrLen SwScriptInfo::NextScriptChg( const xub_StrLen nPos )  const
    1300             : {
    1301        1161 :     sal_uInt16 nEnd = CountScriptChg();
    1302        1163 :     for( sal_uInt16 nX = 0; nX < nEnd; ++nX )
    1303             :     {
    1304        1163 :         if( nPos < GetScriptChg( nX ) )
    1305        1161 :             return GetScriptChg( nX );
    1306             :     }
    1307             : 
    1308           0 :     return STRING_LEN;
    1309             : }
    1310             : 
    1311             : /*************************************************************************
    1312             :  * SwScriptInfo::ScriptType(..)
    1313             :  * returns the script of the character at the input position
    1314             :  *************************************************************************/
    1315             : 
    1316        6875 : sal_uInt8 SwScriptInfo::ScriptType( const xub_StrLen nPos ) const
    1317             : {
    1318        6875 :     sal_uInt16 nEnd = CountScriptChg();
    1319        7374 :     for( sal_uInt16 nX = 0; nX < nEnd; ++nX )
    1320             :     {
    1321        6878 :         if( nPos < GetScriptChg( nX ) )
    1322        6379 :             return GetScriptType( nX );
    1323             :     }
    1324             : 
    1325             :     // the default is the application language script
    1326         496 :     return (sal_uInt8)GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() );
    1327             : }
    1328             : 
    1329         612 : xub_StrLen SwScriptInfo::NextDirChg( const xub_StrLen nPos,
    1330             :                                      const sal_uInt8* pLevel )  const
    1331             : {
    1332         612 :     sal_uInt8 nCurrDir = pLevel ? *pLevel : 62;
    1333         612 :     sal_uInt16 nEnd = CountDirChg();
    1334         613 :     for( sal_uInt16 nX = 0; nX < nEnd; ++nX )
    1335             :     {
    1336           6 :         if( nPos < GetDirChg( nX ) &&
    1337           2 :             ( nX + 1 == nEnd || GetDirType( nX + 1 ) <= nCurrDir ) )
    1338           3 :             return GetDirChg( nX );
    1339             :     }
    1340             : 
    1341         609 :     return STRING_LEN;
    1342             : }
    1343             : 
    1344        1325 : sal_uInt8 SwScriptInfo::DirType( const xub_StrLen nPos ) const
    1345             : {
    1346        1325 :     sal_uInt16 nEnd = CountDirChg();
    1347        1329 :     for( sal_uInt16 nX = 0; nX < nEnd; ++nX )
    1348             :     {
    1349           8 :         if( nPos < GetDirChg( nX ) )
    1350           4 :             return GetDirType( nX );
    1351             :     }
    1352             : 
    1353        1321 :     return 0;
    1354             : }
    1355             : 
    1356             : /*************************************************************************
    1357             :  * SwScriptInfo::MaskHiddenRanges(..)
    1358             :  * Takes a string and replaced the hidden ranges with cChar.
    1359             :  **************************************************************************/
    1360             : 
    1361         500 : sal_uInt16 SwScriptInfo::MaskHiddenRanges( const SwTxtNode& rNode, XubString& rText,
    1362             :                                        const xub_StrLen nStt, const xub_StrLen nEnd,
    1363             :                                        const sal_Unicode cChar )
    1364             : {
    1365             :     assert(rNode.GetTxt().Len() == rText.Len());
    1366             : 
    1367         500 :     PositionList aList;
    1368             :     xub_StrLen nHiddenStart;
    1369             :     xub_StrLen nHiddenEnd;
    1370         500 :     sal_uInt16 nNumOfHiddenChars = 0;
    1371         500 :     GetBoundsOfHiddenRange( rNode, 0, nHiddenStart, nHiddenEnd, &aList );
    1372         500 :     PositionList::const_reverse_iterator rFirst( aList.end() );
    1373         500 :     PositionList::const_reverse_iterator rLast( aList.begin() );
    1374        1000 :     while ( rFirst != rLast )
    1375             :     {
    1376           0 :         nHiddenEnd = *(rFirst++);
    1377           0 :         nHiddenStart = *(rFirst++);
    1378             : 
    1379           0 :         if ( nHiddenEnd < nStt || nHiddenStart > nEnd )
    1380           0 :             continue;
    1381             : 
    1382           0 :         while ( nHiddenStart < nHiddenEnd && nHiddenStart < nEnd )
    1383             :         {
    1384           0 :             if ( nHiddenStart >= nStt && nHiddenStart < nEnd )
    1385             :             {
    1386           0 :                 rText.SetChar( nHiddenStart, cChar );
    1387           0 :                 ++nNumOfHiddenChars;
    1388             :             }
    1389           0 :             ++nHiddenStart;
    1390             :         }
    1391             :     }
    1392             : 
    1393         500 :     return nNumOfHiddenChars;
    1394             : }
    1395             : 
    1396             : /*************************************************************************
    1397             :  * SwScriptInfo::DeleteHiddenRanges(..)
    1398             :  * Takes a SwTxtNode and deletes the hidden ranges from the node.
    1399             :  **************************************************************************/
    1400             : 
    1401           0 : void SwScriptInfo::DeleteHiddenRanges( SwTxtNode& rNode )
    1402             : {
    1403           0 :     PositionList aList;
    1404             :     xub_StrLen nHiddenStart;
    1405             :     xub_StrLen nHiddenEnd;
    1406           0 :     GetBoundsOfHiddenRange( rNode, 0, nHiddenStart, nHiddenEnd, &aList );
    1407           0 :     PositionList::const_reverse_iterator rFirst( aList.end() );
    1408           0 :     PositionList::const_reverse_iterator rLast( aList.begin() );
    1409           0 :     while ( rFirst != rLast )
    1410             :     {
    1411           0 :         nHiddenEnd = *(rFirst++);
    1412           0 :         nHiddenStart = *(rFirst++);
    1413             : 
    1414           0 :         SwPaM aPam( rNode, nHiddenStart, rNode, nHiddenEnd );
    1415           0 :         rNode.getIDocumentContentOperations()->DeleteRange( aPam );
    1416           0 :     }
    1417           0 : }
    1418             : 
    1419             : /*************************************************************************
    1420             :  * SwScriptInfo::GetBoundsOfHiddenRange(..)
    1421             :  * static version
    1422             :  **************************************************************************/
    1423             : 
    1424        1463 : bool SwScriptInfo::GetBoundsOfHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos,
    1425             :                                            xub_StrLen& rnStartPos, xub_StrLen& rnEndPos,
    1426             :                                            PositionList* pList )
    1427             : {
    1428        1463 :     rnStartPos = STRING_LEN;
    1429        1463 :     rnEndPos = 0;
    1430             : 
    1431        1463 :     bool bNewContainsHiddenChars = false;
    1432             : 
    1433             :     //
    1434             :     // Optimization: First examine the flags at the text node:
    1435             :     //
    1436        1463 :     if ( !rNode.IsCalcHiddenCharFlags() )
    1437             :     {
    1438         566 :         bool bWholePara = rNode.HasHiddenCharAttribute( true );
    1439         566 :         bool bContainsHiddenChars = rNode.HasHiddenCharAttribute( false );
    1440         566 :         if ( !bContainsHiddenChars )
    1441         566 :             return false;
    1442             : 
    1443           0 :         if ( bWholePara )
    1444             :         {
    1445           0 :             if ( pList )
    1446             :             {
    1447           0 :                 pList->push_back( 0 );
    1448           0 :                 pList->push_back( rNode.GetTxt().Len() );
    1449             :             }
    1450             : 
    1451           0 :             rnStartPos = 0;
    1452           0 :             rnEndPos = rNode.GetTxt().Len();
    1453           0 :             return true;
    1454             :         }
    1455             :     }
    1456             : 
    1457         897 :     const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rNode );
    1458         897 :     if ( pSI )
    1459             :     {
    1460             :         //
    1461             :         // Check first, if we have a valid SwScriptInfo object for this text node:
    1462             :         //
    1463           0 :         bNewContainsHiddenChars = pSI->GetBoundsOfHiddenRange( nPos, rnStartPos, rnEndPos, pList );
    1464           0 :         const bool bNewHiddenCharsHidePara = ( rnStartPos == 0 && rnEndPos >= rNode.GetTxt().Len() );
    1465           0 :         rNode.SetHiddenCharAttribute( bNewHiddenCharsHidePara, bNewContainsHiddenChars );
    1466             :     }
    1467             :     else
    1468             :     {
    1469             :         //
    1470             :         // No valid SwScriptInfo Object, we have to do it the hard way:
    1471             :         //
    1472         897 :         Range aRange( 0, rNode.GetTxt().Len() ? rNode.GetTxt().Len() - 1 : 0 );
    1473         897 :         MultiSelection aHiddenMulti( aRange );
    1474         897 :         SwScriptInfo::CalcHiddenRanges( rNode, aHiddenMulti );
    1475         897 :         for( sal_uInt16 i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
    1476             :         {
    1477           0 :             const Range& rRange = aHiddenMulti.GetRange( i );
    1478           0 :             const xub_StrLen nHiddenStart = (xub_StrLen)rRange.Min();
    1479           0 :             const xub_StrLen nHiddenEnd = (xub_StrLen)rRange.Max() + 1;
    1480             : 
    1481           0 :             if ( nHiddenStart > nPos )
    1482           0 :                 break;
    1483           0 :             else if ( nHiddenStart <= nPos && nPos < nHiddenEnd )
    1484             :             {
    1485           0 :                 rnStartPos = nHiddenStart;
    1486           0 :                 rnEndPos   = Min( nHiddenEnd, rNode.GetTxt().Len() );
    1487           0 :                 break;
    1488             :             }
    1489             :         }
    1490             : 
    1491         897 :         if ( pList )
    1492             :         {
    1493           0 :             for( sal_uInt16 i = 0; i < aHiddenMulti.GetRangeCount(); ++i )
    1494             :             {
    1495           0 :                 const Range& rRange = aHiddenMulti.GetRange( i );
    1496           0 :                 pList->push_back( (xub_StrLen)rRange.Min() );
    1497           0 :                 pList->push_back( (xub_StrLen)rRange.Max() + 1 );
    1498             :             }
    1499             :         }
    1500             : 
    1501         897 :         bNewContainsHiddenChars = aHiddenMulti.GetRangeCount() > 0;
    1502             :     }
    1503             : 
    1504         897 :     return bNewContainsHiddenChars;
    1505             : }
    1506             : 
    1507             : /*************************************************************************
    1508             :  * SwScriptInfo::GetBoundsOfHiddenRange(..)
    1509             :  * non-static version
    1510             :  **************************************************************************/
    1511             : 
    1512        1541 : bool SwScriptInfo::GetBoundsOfHiddenRange( xub_StrLen nPos, xub_StrLen& rnStartPos,
    1513             :                                            xub_StrLen& rnEndPos, PositionList* pList ) const
    1514             : {
    1515        1541 :     rnStartPos = STRING_LEN;
    1516        1541 :     rnEndPos = 0;
    1517             : 
    1518        1541 :     sal_uInt16 nEnd = CountHiddenChg();
    1519        1541 :     for( sal_uInt16 nX = 0; nX < nEnd; ++nX )
    1520             :     {
    1521           0 :         const xub_StrLen nHiddenStart = GetHiddenChg( nX++ );
    1522           0 :         const xub_StrLen nHiddenEnd = GetHiddenChg( nX );
    1523             : 
    1524           0 :         if ( nHiddenStart > nPos )
    1525           0 :             break;
    1526           0 :         else if ( nHiddenStart <= nPos && nPos < nHiddenEnd )
    1527             :         {
    1528           0 :             rnStartPos = nHiddenStart;
    1529           0 :             rnEndPos   = nHiddenEnd;
    1530           0 :             break;
    1531             :         }
    1532             :     }
    1533             : 
    1534        1541 :     if ( pList )
    1535             :     {
    1536           0 :         for( sal_uInt16 nX = 0; nX < nEnd; ++nX )
    1537             :         {
    1538           0 :             pList->push_back( GetHiddenChg( nX++ ) );
    1539           0 :             pList->push_back( GetHiddenChg( nX ) );
    1540             :         }
    1541             :     }
    1542             : 
    1543        1541 :     return CountHiddenChg() > 0;
    1544             : }
    1545             : 
    1546          29 : bool SwScriptInfo::IsInHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos )
    1547             : {
    1548             :     xub_StrLen nStartPos;
    1549             :     xub_StrLen nEndPos;
    1550          29 :     SwScriptInfo::GetBoundsOfHiddenRange( rNode, nPos, nStartPos, nEndPos );
    1551          29 :     return nStartPos != STRING_LEN;
    1552             : }
    1553             : 
    1554             : 
    1555             : #ifdef DBG_UTIL
    1556             : /*************************************************************************
    1557             :  * SwScriptInfo::CompType(..)
    1558             :  * returns the type of the compressed character
    1559             :  *************************************************************************/
    1560             : 
    1561             : sal_uInt8 SwScriptInfo::CompType( const xub_StrLen nPos ) const
    1562             : {
    1563             :     sal_uInt16 nEnd = CountCompChg();
    1564             :     for( sal_uInt16 nX = 0; nX < nEnd; ++nX )
    1565             :     {
    1566             :         xub_StrLen nChg = GetCompStart( nX );
    1567             : 
    1568             :         if ( nPos < nChg )
    1569             :             return NONE;
    1570             : 
    1571             :         if( nPos < nChg + GetCompLen( nX ) )
    1572             :             return GetCompType( nX );
    1573             :     }
    1574             :     return NONE;
    1575             : }
    1576             : #endif
    1577             : 
    1578             : /*************************************************************************
    1579             :  * SwScriptInfo::HasKana()
    1580             :  * returns, if there are compressable kanas or specials
    1581             :  * between nStart and nEnd
    1582             :  *************************************************************************/
    1583             : 
    1584           0 : sal_uInt16 SwScriptInfo::HasKana( xub_StrLen nStart, const xub_StrLen nLen ) const
    1585             : {
    1586           0 :     sal_uInt16 nCnt = CountCompChg();
    1587           0 :     xub_StrLen nEnd = nStart + nLen;
    1588             : 
    1589           0 :     for( sal_uInt16 nX = 0; nX < nCnt; ++nX )
    1590             :     {
    1591           0 :         xub_StrLen nKanaStart  = GetCompStart( nX );
    1592           0 :         xub_StrLen nKanaEnd = nKanaStart + GetCompLen( nX );
    1593             : 
    1594           0 :         if ( nKanaStart >= nEnd )
    1595           0 :             return USHRT_MAX;
    1596             : 
    1597           0 :         if ( nStart < nKanaEnd )
    1598           0 :             return nX;
    1599             :     }
    1600             : 
    1601           0 :     return USHRT_MAX;
    1602             : }
    1603             : 
    1604           0 : long SwScriptInfo::Compress( sal_Int32* pKernArray, xub_StrLen nIdx, xub_StrLen nLen,
    1605             :                              const sal_uInt16 nCompress, const sal_uInt16 nFontHeight,
    1606             :                              Point* pPoint ) const
    1607             : {
    1608             :     SAL_WARN_IF( !nCompress, "sw.core", "Compression without compression?!" );
    1609             :     SAL_WARN_IF( !nLen, "sw.core", "Compression without text?!" );
    1610           0 :     sal_uInt16 nCompCount = CountCompChg();
    1611             : 
    1612             :     // In asian typography, there are full width and half width characters.
    1613             :     // Full width punctuation characters can be compressed by 50 %
    1614             :     // to determine this, we compare the font width with 75 % of its height
    1615           0 :     sal_uInt16 nMinWidth = ( 3 * nFontHeight ) / 4;
    1616             : 
    1617           0 :     sal_uInt16 nCompIdx = HasKana( nIdx, nLen );
    1618             : 
    1619           0 :     if ( USHRT_MAX == nCompIdx )
    1620           0 :         return 0;
    1621             : 
    1622           0 :     xub_StrLen nChg = GetCompStart( nCompIdx );
    1623           0 :     xub_StrLen nCompLen = GetCompLen( nCompIdx );
    1624           0 :     sal_uInt16 nI = 0;
    1625           0 :     nLen = nLen + nIdx;
    1626             : 
    1627           0 :     if( nChg > nIdx )
    1628             :     {
    1629           0 :         nI = nChg - nIdx;
    1630           0 :         nIdx = nChg;
    1631             :     }
    1632           0 :     else if( nIdx < nChg + nCompLen )
    1633           0 :         nCompLen -= nIdx - nChg;
    1634             : 
    1635           0 :     if( nIdx > nLen || nCompIdx >= nCompCount )
    1636           0 :         return 0;
    1637             : 
    1638           0 :     long nSub = 0;
    1639           0 :     long nLast = nI ? pKernArray[ nI - 1 ] : 0;
    1640           0 :     do
    1641             :     {
    1642           0 :         sal_uInt16 nType = GetCompType( nCompIdx );
    1643             : #ifdef DBG_UTIL
    1644             :         SAL_WARN_IF( nType != CompType( nIdx ), "sw.core", "Gimme the right type!" );
    1645             : #endif
    1646           0 :         nCompLen = nCompLen + nIdx;
    1647           0 :         if( nCompLen > nLen )
    1648           0 :             nCompLen = nLen;
    1649             : 
    1650             :         // are we allowed to compress the character?
    1651           0 :         if ( pKernArray[ nI ] - nLast < nMinWidth )
    1652             :         {
    1653           0 :             nIdx++; nI++;
    1654             :         }
    1655             :         else
    1656             :         {
    1657           0 :             while( nIdx < nCompLen )
    1658             :             {
    1659             :                 SAL_WARN_IF( SwScriptInfo::NONE == nType, "sw.core", "None compression?!" );
    1660             : 
    1661             :                 // nLast is width of current character
    1662           0 :                 nLast -= pKernArray[ nI ];
    1663             : 
    1664           0 :                 nLast *= nCompress;
    1665           0 :                 long nMove = 0;
    1666           0 :                 if( SwScriptInfo::KANA != nType )
    1667             :                 {
    1668           0 :                     nLast /= 20000;
    1669           0 :                     if( pPoint && SwScriptInfo::SPECIAL_LEFT == nType )
    1670             :                     {
    1671           0 :                         if( nI )
    1672           0 :                             nMove = nLast;
    1673             :                         else
    1674             :                         {
    1675           0 :                             pPoint->X() += nLast;
    1676           0 :                             nLast = 0;
    1677             :                         }
    1678             :                     }
    1679             :                 }
    1680             :                 else
    1681           0 :                     nLast /= 100000;
    1682           0 :                 nSub -= nLast;
    1683           0 :                 nLast = pKernArray[ nI ];
    1684           0 :                 if( nMove )
    1685           0 :                     pKernArray[ nI - 1 ] += nMove;
    1686           0 :                 pKernArray[ nI++ ] -= nSub;
    1687           0 :                 ++nIdx;
    1688             :             }
    1689             :         }
    1690             : 
    1691           0 :         if( nIdx < nLen )
    1692             :         {
    1693             :             xub_StrLen nTmpChg;
    1694           0 :             if( ++nCompIdx < nCompCount )
    1695             :             {
    1696           0 :                 nTmpChg = GetCompStart( nCompIdx );
    1697           0 :                 if( nTmpChg > nLen )
    1698           0 :                     nTmpChg = nLen;
    1699           0 :                 nCompLen = GetCompLen( nCompIdx );
    1700             :             }
    1701             :             else
    1702           0 :                 nTmpChg = nLen;
    1703           0 :             while( nIdx < nTmpChg )
    1704             :             {
    1705           0 :                 nLast = pKernArray[ nI ];
    1706           0 :                 pKernArray[ nI++ ] -= nSub;
    1707           0 :                 ++nIdx;
    1708             :             }
    1709             :         }
    1710             :         else
    1711           0 :             break;
    1712             :     } while( nIdx < nLen );
    1713           0 :     return nSub;
    1714             : }
    1715             : 
    1716             : /*************************************************************************
    1717             :  * SwScriptInfo::KashidaJustify()
    1718             :  *************************************************************************/
    1719             : 
    1720             : // Note on calling KashidaJustify():
    1721             : // Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean
    1722             : // total number of kashida positions, or the number of kashida positions after some positions
    1723             : // have been dropped, depending on the state of the aKashidaInvalid array.
    1724             : 
    1725           0 : sal_uInt16 SwScriptInfo::KashidaJustify( sal_Int32* pKernArray,
    1726             :                                     sal_Int32* pScrArray,
    1727             :                                     xub_StrLen nStt,
    1728             :                                     xub_StrLen nLen,
    1729             :                                     long nSpaceAdd ) const
    1730             : {
    1731             :     SAL_WARN_IF( !nLen, "sw.core", "Kashida justification without text?!" );
    1732             : 
    1733           0 :     if( !IsKashidaLine(nStt))
    1734           0 :         return STRING_LEN;
    1735             : 
    1736             :     // evaluate kashida information in collected in SwScriptInfo
    1737             : 
    1738           0 :     sal_uInt16 nCntKash = 0;
    1739           0 :     while( nCntKash < CountKashida() )
    1740             :     {
    1741           0 :         if ( nStt <= GetKashida( nCntKash ) )
    1742           0 :             break;
    1743             :         else
    1744           0 :             nCntKash++;
    1745             :     }
    1746             : 
    1747           0 :     const xub_StrLen nEnd = nStt + nLen;
    1748             : 
    1749           0 :     sal_uInt16 nCntKashEnd = nCntKash;
    1750           0 :     while ( nCntKashEnd < CountKashida() )
    1751             :     {
    1752           0 :        if ( nEnd <= GetKashida( nCntKashEnd ) )
    1753           0 :             break;
    1754             :         else
    1755           0 :             nCntKashEnd++;
    1756             :     }
    1757             : 
    1758           0 :     sal_uInt16 nActualKashCount = nCntKashEnd - nCntKash;
    1759           0 :     for ( sal_uInt16 i = nCntKash; i < nCntKashEnd; ++i )
    1760             :     {
    1761           0 :         if ( nActualKashCount && !IsKashidaValid ( i ) )
    1762           0 :             --nActualKashCount;
    1763             :     }
    1764             : 
    1765           0 :     if ( !pKernArray )
    1766           0 :         return nActualKashCount;
    1767             : 
    1768             :     // do nothing if there is no more kashida
    1769           0 :     if ( nCntKash < CountKashida() )
    1770             :     {
    1771             :         // skip any invalid kashidas
    1772           0 :         while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd )
    1773           0 :             ++nCntKash;
    1774             : 
    1775           0 :         xub_StrLen nKashidaPos = GetKashida( nCntKash );
    1776           0 :         xub_StrLen nIdx = nKashidaPos;
    1777           0 :         long nKashAdd = nSpaceAdd;
    1778             : 
    1779           0 :         while ( nIdx < nEnd )
    1780             :         {
    1781           0 :             sal_uInt16 nArrayPos = nIdx - nStt;
    1782             : 
    1783             :             // next kashida position
    1784           0 :             ++nCntKash;
    1785           0 :             while ( ! IsKashidaValid ( nCntKash ) && nCntKash < nCntKashEnd )
    1786           0 :                 ++nCntKash;
    1787             : 
    1788           0 :             nIdx = nCntKash < CountKashida() && IsKashidaValid ( nCntKash ) ? GetKashida( nCntKash ) : nEnd;
    1789           0 :             if ( nIdx > nEnd )
    1790           0 :                 nIdx = nEnd;
    1791             : 
    1792           0 :             const sal_uInt16 nArrayEnd = nIdx - nStt;
    1793             : 
    1794           0 :             while ( nArrayPos < nArrayEnd )
    1795             :             {
    1796           0 :                 pKernArray[ nArrayPos ] += nKashAdd;
    1797           0 :                 if ( pScrArray )
    1798           0 :                     pScrArray[ nArrayPos ] += nKashAdd;
    1799           0 :                 ++nArrayPos;
    1800             :             }
    1801           0 :             nKashAdd += nSpaceAdd;
    1802             :         }
    1803             :     }
    1804             : 
    1805           0 :     return 0;
    1806             : }
    1807             : 
    1808             : /*************************************************************************
    1809             :  * SwScriptInfo::IsArabicText()
    1810             :  *
    1811             :  * Checks if the current text is 'Arabic' text. Note that only the first
    1812             :  * character has to be checked because a ctl portion only contains one
    1813             :  * script, see NewTxtPortion
    1814             :  *************************************************************************/
    1815           2 : bool SwScriptInfo::IsArabicText( const OUString& rTxt, sal_Int32 nStt, sal_Int32 nLen )
    1816             : {
    1817             :     using namespace ::com::sun::star::i18n;
    1818             :     static ScriptTypeList typeList[] = {
    1819             :         { UnicodeScript_kArabic, UnicodeScript_kArabic, UnicodeScript_kArabic },        // 11,
    1820             :         { UnicodeScript_kScriptCount, UnicodeScript_kScriptCount, UnicodeScript_kScriptCount }    // 88
    1821             :     };
    1822             : 
    1823             :     // go forward if current position does not hold a regular character:
    1824           2 :     const CharClass& rCC = GetAppCharClass();
    1825           2 :     sal_Int32 nIdx = nStt;
    1826           2 :     const sal_Int32 nEnd = nStt + nLen;
    1827           4 :     while ( nIdx < nEnd && !rCC.isLetterNumeric( rTxt, (xub_StrLen)nIdx ) )
    1828             :     {
    1829           0 :         ++nIdx;
    1830             :     }
    1831             : 
    1832           2 :     if( nIdx == nEnd )
    1833             :     {
    1834             :         // no regular character found in this portion. Go backward:
    1835           0 :         --nIdx;
    1836           0 :         while ( nIdx >= 0 && !rCC.isLetterNumeric( rTxt, (xub_StrLen)nIdx ) )
    1837             :         {
    1838           0 :             --nIdx;
    1839             :         }
    1840             :     }
    1841             : 
    1842           2 :     if( nIdx >= 0 )
    1843             :     {
    1844           2 :         const sal_Unicode cCh = rTxt[nIdx];
    1845           2 :         const sal_Int16 type = unicode::getUnicodeScriptType( cCh, typeList, UnicodeScript_kScriptCount );
    1846           2 :         return type == UnicodeScript_kArabic;
    1847             :     }
    1848           0 :     return false;
    1849             : }
    1850             : 
    1851           0 : sal_Bool SwScriptInfo::IsKashidaValid ( xub_StrLen nKashPos ) const
    1852             : {
    1853           0 :     for ( size_t i = 0; i < aKashidaInvalid.size(); ++i )
    1854             :     {
    1855           0 :         if ( aKashidaInvalid [ i ] == nKashPos )
    1856           0 :             return false;
    1857             :     }
    1858           0 :     return true;
    1859             : }
    1860             : 
    1861           0 : void SwScriptInfo::ClearKashidaInvalid ( xub_StrLen nKashPos )
    1862             : {
    1863           0 :     for ( size_t i = 0; i < aKashidaInvalid.size(); ++i )
    1864             :     {
    1865           0 :         if ( aKashidaInvalid [ i ] == nKashPos )
    1866             :         {
    1867           0 :            aKashidaInvalid.erase ( aKashidaInvalid.begin() + i );
    1868           0 :            return;
    1869             :         }
    1870             :     }
    1871             : }
    1872             : 
    1873             : /*************************************************************************
    1874             :  * SwScriptInfo::MarkOrClearKashidaInvalid()
    1875             :  *
    1876             :  * bMark == true:
    1877             :  * marks the first valid kashida in the given text range as invalid
    1878             :  *
    1879             :  * bMark == false:
    1880             :  * clears all kashida invalid flags in the given text range
    1881             : *************************************************************************/
    1882             : 
    1883           0 : bool SwScriptInfo::MarkOrClearKashidaInvalid ( xub_StrLen nStt, xub_StrLen nLen, bool bMark, xub_StrLen nMarkCount )
    1884             : {
    1885           0 :     sal_uInt16 nCntKash = 0;
    1886           0 :     while( nCntKash < CountKashida() )
    1887             :     {
    1888           0 :         if ( nStt <= GetKashida( nCntKash ) )
    1889           0 :             break;
    1890             :         else
    1891           0 :             nCntKash++;
    1892             :     }
    1893             : 
    1894           0 :     const xub_StrLen nEnd = nStt + nLen;
    1895             : 
    1896           0 :     while ( nCntKash < CountKashida() )
    1897             :     {
    1898           0 :         if ( nEnd <= GetKashida( nCntKash ) )
    1899           0 :             break;
    1900             :         else
    1901             :         {
    1902           0 :             if(bMark)
    1903             :             {
    1904           0 :                 if ( IsKashidaValid ( nCntKash ) )
    1905             :                 {
    1906           0 :                     MarkKashidaInvalid ( nCntKash );
    1907           0 :                     --nMarkCount;
    1908           0 :                     if(!nMarkCount)
    1909           0 :                        return true;
    1910             :                 }
    1911             :             }
    1912             :             else
    1913             :             {
    1914           0 :                 ClearKashidaInvalid ( nCntKash );
    1915             :             }
    1916           0 :             nCntKash++;
    1917             :         }
    1918             :     }
    1919           0 :     return false;
    1920             : }
    1921             : 
    1922           0 : void SwScriptInfo::MarkKashidaInvalid ( xub_StrLen nKashPos )
    1923             : {
    1924           0 :     aKashidaInvalid.push_back( nKashPos );
    1925           0 : }
    1926             : 
    1927             : /*************************************************************************
    1928             :  * SwScriptInfo::GetKashidaPositions()
    1929             :  * retrieve the kashida positions in the given text range
    1930             : *************************************************************************/
    1931             : 
    1932           0 : sal_uInt16 SwScriptInfo::GetKashidaPositions ( xub_StrLen nStt, xub_StrLen nLen,
    1933             :                                            xub_StrLen* pKashidaPosition )
    1934             : {
    1935           0 :     sal_uInt16 nCntKash = 0;
    1936           0 :     while( nCntKash < CountKashida() )
    1937             :     {
    1938           0 :         if ( nStt <= GetKashida( nCntKash ) )
    1939           0 :             break;
    1940             :         else
    1941           0 :             nCntKash++;
    1942             :     }
    1943             : 
    1944           0 :     const xub_StrLen nEnd = nStt + nLen;
    1945             : 
    1946           0 :     sal_uInt16 nCntKashEnd = nCntKash;
    1947           0 :     while ( nCntKashEnd < CountKashida() )
    1948             :     {
    1949           0 :        if ( nEnd <= GetKashida( nCntKashEnd ) )
    1950           0 :             break;
    1951             :         else
    1952             :         {
    1953           0 :             pKashidaPosition [ nCntKashEnd - nCntKash ] = GetKashida ( nCntKashEnd );
    1954           0 :             nCntKashEnd++;
    1955             :         }
    1956             :     }
    1957           0 :     return nCntKashEnd - nCntKash;
    1958             : }
    1959             : 
    1960           0 : void SwScriptInfo::SetNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen )
    1961             : {
    1962           0 :     aNoKashidaLine.push_back( nStt );
    1963           0 :     aNoKashidaLineEnd.push_back( nStt+nLen );
    1964           0 : }
    1965             : 
    1966             : /*************************************************************************
    1967             :  * SwScriptInfo::IsKashidaLine()
    1968             :  * determines if the line uses kashida justification
    1969             : *************************************************************************/
    1970             : 
    1971           0 : bool SwScriptInfo::IsKashidaLine ( xub_StrLen nCharIdx ) const
    1972             : {
    1973           0 :    for( size_t i = 0; i < aNoKashidaLine.size(); ++i )
    1974             :     {
    1975           0 :        if( nCharIdx >= aNoKashidaLine[ i ] && nCharIdx < aNoKashidaLineEnd[ i ])
    1976           0 :            return false;
    1977             :     }
    1978           0 :    return true;
    1979             : }
    1980             : 
    1981           0 : void SwScriptInfo::ClearNoKashidaLine ( xub_StrLen nStt, xub_StrLen nLen )
    1982             : {
    1983           0 :    size_t i = 0;
    1984           0 :    while( i < aNoKashidaLine.size())
    1985             :    {
    1986           0 :        if( nStt + nLen >= aNoKashidaLine[ i ] && nStt < aNoKashidaLineEnd [ i ] )
    1987             :        {
    1988           0 :            aNoKashidaLine.erase(aNoKashidaLine.begin() + i);
    1989           0 :            aNoKashidaLineEnd.erase(aNoKashidaLineEnd.begin() + i);
    1990             :        }
    1991             :        else
    1992           0 :            ++i;
    1993             :    }
    1994           0 : }
    1995             : 
    1996             : /*************************************************************************
    1997             :  * SwScriptInfo::MarkKashidasInvalid()
    1998             :  *
    1999             :  * mark the given character indices as invalid kashida positions
    2000             : ************************************************************************/
    2001             : 
    2002           0 : bool SwScriptInfo::MarkKashidasInvalid ( xub_StrLen nCnt, xub_StrLen* pKashidaPositions )
    2003             : {
    2004             :    SAL_WARN_IF( !pKashidaPositions || nCnt == 0, "sw.core", "Where are kashidas?" );
    2005             : 
    2006           0 :    sal_uInt16 nCntKash = 0;
    2007           0 :    xub_StrLen nKashidaPosIdx = 0;
    2008             : 
    2009           0 :     while ( nCntKash < CountKashida() && nKashidaPosIdx < nCnt )
    2010             :     {
    2011           0 :        if ( pKashidaPositions [nKashidaPosIdx] > GetKashida( nCntKash ) )
    2012             :        {
    2013           0 :            nCntKash++;
    2014           0 :            continue;
    2015             :        }
    2016             : 
    2017           0 :         if ( pKashidaPositions [nKashidaPosIdx] == GetKashida( nCntKash ) && IsKashidaValid ( nCntKash ) )
    2018             :        {
    2019           0 :             MarkKashidaInvalid ( nCntKash );
    2020             :        }
    2021             :        else
    2022           0 :            return false; // something is wrong
    2023           0 :        nKashidaPosIdx++;
    2024             :    }
    2025           0 :    return true;
    2026             : }
    2027             : 
    2028           0 : sal_Int32 SwScriptInfo::ThaiJustify( const OUString& rTxt, sal_Int32* pKernArray,
    2029             :                                   sal_Int32* pScrArray, sal_Int32 nStt,
    2030             :                                   sal_Int32 nLen, sal_Int32 nNumberOfBlanks,
    2031             :                                   long nSpaceAdd )
    2032             : {
    2033             :     SAL_WARN_IF( nStt + nLen > rTxt.getLength(), "sw.core", "String in ThaiJustify too small" );
    2034             : 
    2035             :     SwTwips nNumOfTwipsToDistribute = nSpaceAdd * nNumberOfBlanks /
    2036           0 :                                       SPACING_PRECISION_FACTOR;
    2037             : 
    2038           0 :     long nSpaceSum = 0;
    2039           0 :     sal_Int32 nCnt = 0;
    2040             : 
    2041           0 :     for (sal_Int32 nI = 0; nI < nLen; ++nI)
    2042             :     {
    2043           0 :         const sal_Unicode cCh = rTxt[nStt + nI];
    2044             : 
    2045             :         // check if character is not above or below base
    2046           0 :         if ( ( 0xE34 > cCh || cCh > 0xE3A ) &&
    2047             :              ( 0xE47 > cCh || cCh > 0xE4E ) && cCh != 0xE31 )
    2048             :         {
    2049           0 :             if ( nNumberOfBlanks > 0 )
    2050             :             {
    2051           0 :                 nSpaceAdd = nNumOfTwipsToDistribute / nNumberOfBlanks;
    2052           0 :                 --nNumberOfBlanks;
    2053           0 :                 nNumOfTwipsToDistribute -= nSpaceAdd;
    2054             :             }
    2055           0 :             nSpaceSum += nSpaceAdd;
    2056           0 :             ++nCnt;
    2057             :         }
    2058             : 
    2059           0 :         if ( pKernArray ) pKernArray[ nI ] += nSpaceSum;
    2060           0 :         if ( pScrArray ) pScrArray[ nI ] += nSpaceSum;
    2061             :     }
    2062             : 
    2063           0 :     return nCnt;
    2064             : }
    2065             : 
    2066         897 : SwScriptInfo* SwScriptInfo::GetScriptInfo( const SwTxtNode& rTNd,
    2067             :                                            sal_Bool bAllowInvalid )
    2068             : {
    2069         897 :     SwIterator<SwTxtFrm,SwTxtNode> aIter( rTNd );
    2070         897 :     SwScriptInfo* pScriptInfo = 0;
    2071             : 
    2072        1768 :     for( SwTxtFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() )
    2073             :     {
    2074         871 :             pScriptInfo = (SwScriptInfo*)pLast->GetScriptInfo();
    2075         871 :             if ( pScriptInfo )
    2076             :             {
    2077           0 :                 if ( !bAllowInvalid && STRING_LEN != pScriptInfo->GetInvalidity() )
    2078           0 :                     pScriptInfo = 0;
    2079           0 :                 else break;
    2080             :             }
    2081             :         }
    2082             : 
    2083         897 :     return pScriptInfo;
    2084             : }
    2085             : 
    2086         662 : SwParaPortion::SwParaPortion()
    2087             : {
    2088         662 :     FormatReset();
    2089         662 :     bFlys = bFtnNum = bMargin = sal_False;
    2090         662 :     SetWhichPor( POR_PARA );
    2091         662 : }
    2092             : 
    2093        1324 : SwParaPortion::~SwParaPortion()
    2094             : {
    2095        1324 : }
    2096             : 
    2097           6 : xub_StrLen SwParaPortion::GetParLen() const
    2098             : {
    2099           6 :     xub_StrLen nLen = 0;
    2100           6 :     const SwLineLayout *pLay = this;
    2101          18 :     while( pLay )
    2102             :     {
    2103           6 :         nLen = nLen + pLay->GetLen();
    2104           6 :         pLay = pLay->GetNext();
    2105             :     }
    2106           6 :     return nLen;
    2107             : }
    2108             : 
    2109        4150 : const SwDropPortion *SwParaPortion::FindDropPortion() const
    2110             : {
    2111        4150 :     const SwLineLayout *pLay = this;
    2112        8566 :     while( pLay && pLay->IsDummy() )
    2113         266 :         pLay = pLay->GetNext();
    2114       12198 :     while( pLay )
    2115             :     {
    2116        3898 :         const SwLinePortion *pPos = pLay->GetPortion();
    2117        8100 :         while ( pPos && !pPos->GetLen() )
    2118         304 :             pPos = pPos->GetPortion();
    2119        3898 :         if( pPos && pPos->IsDropPortion() )
    2120           0 :             return (SwDropPortion *)pPos;
    2121        3898 :         pLay = pLay->GetLen() ? NULL : pLay->GetNext();
    2122             :     }
    2123        4150 :     return NULL;
    2124             : }
    2125             : 
    2126        1136 : void SwLineLayout::Init( SwLinePortion* pNextPortion )
    2127             : {
    2128        1136 :     Height( 0 );
    2129        1136 :     Width( 0 );
    2130        1136 :     SetLen( 0 );
    2131        1136 :     SetAscent( 0 );
    2132        1136 :     SetRealHeight( 0 );
    2133        1136 :     SetPortion( pNextPortion );
    2134        1136 : }
    2135             : 
    2136             : /*--------------------------------------------------
    2137             :  * HangingMargin()
    2138             :  * looks for hanging punctuation portions in the paragraph
    2139             :  * and return the maximum right offset of them.
    2140             :  * If no such portion is found, the Margin/Hanging-flags will be updated.
    2141             :  * --------------------------------------------------*/
    2142             : 
    2143        1448 : SwTwips SwLineLayout::_GetHangingMargin() const
    2144             : {
    2145        1448 :     SwLinePortion* pPor = GetPortion();
    2146        1448 :     bool bFound = false;
    2147        1448 :     SwTwips nDiff = 0;
    2148        3326 :     while( pPor)
    2149             :     {
    2150         430 :         if( pPor->IsHangingPortion() )
    2151             :         {
    2152           0 :             nDiff = ((SwHangingPortion*)pPor)->GetInnerWidth() - pPor->Width();
    2153           0 :             if( nDiff )
    2154           0 :                 bFound = true;
    2155             :         }
    2156             :         // the last post its portion
    2157         430 :         else if ( pPor->IsPostItsPortion() && ! pPor->GetPortion() )
    2158           0 :             nDiff = nAscent;
    2159             : 
    2160         430 :         pPor = pPor->GetPortion();
    2161             :     }
    2162        1448 :     if( !bFound ) // update the hanging-flag
    2163        1448 :         ((SwLineLayout*)this)->SetHanging( sal_False );
    2164        1448 :     return nDiff;
    2165             : }
    2166             : 
    2167         591 : SwTwips SwTxtFrm::HangingMargin() const
    2168             : {
    2169             :     SAL_WARN_IF( !HasPara(), "sw.core", "Don't call me without a paraportion" );
    2170         591 :     if( !GetPara()->IsMargin() )
    2171         591 :         return 0;
    2172           0 :     const SwLineLayout* pLine = GetPara();
    2173           0 :     SwTwips nRet = 0;
    2174           0 :     do
    2175             :     {
    2176           0 :         SwTwips nDiff = pLine->GetHangingMargin();
    2177           0 :         if( nDiff > nRet )
    2178           0 :             nRet = nDiff;
    2179           0 :         pLine = pLine->GetNext();
    2180             :     } while ( pLine );
    2181           0 :     if( !nRet ) // update the margin-flag
    2182           0 :         ((SwParaPortion*)GetPara())->SetMargin( sal_False );
    2183           0 :     return nRet;
    2184             : }
    2185             : 
    2186        1888 : void SwScriptInfo::selectHiddenTextProperty(const SwTxtNode& rNode, MultiSelection &rHiddenMulti)
    2187             : {
    2188             :     assert((!rNode.GetTxt().Len() && rHiddenMulti.GetTotalRange().Len() == 1) ||
    2189             :            (rNode.GetTxt().Len() == rHiddenMulti.GetTotalRange().Len()));
    2190             : 
    2191        1888 :     const SfxPoolItem* pItem = 0;
    2192        1888 :     if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) &&
    2193           0 :         ((SvxCharHiddenItem*)pItem)->GetValue() )
    2194             :     {
    2195           0 :         rHiddenMulti.SelectAll();
    2196             :     }
    2197             : 
    2198        1888 :     const SwpHints* pHints = rNode.GetpSwpHints();
    2199             : 
    2200        1888 :     if( pHints )
    2201             :     {
    2202         843 :         MSHORT nTmp = 0;
    2203             : 
    2204        2908 :         while( nTmp < pHints->GetStartCount() )
    2205             :         {
    2206        1222 :             const SwTxtAttr* pTxtAttr = pHints->GetStart( nTmp++ );
    2207             :             const SvxCharHiddenItem* pHiddenItem =
    2208        1222 :                 static_cast<const SvxCharHiddenItem*>( CharFmt::GetItem( *pTxtAttr, RES_CHRATR_HIDDEN ) );
    2209        1222 :             if( pHiddenItem )
    2210             :             {
    2211           4 :                 xub_StrLen nSt = *pTxtAttr->GetStart();
    2212           4 :                 xub_StrLen nEnd = *pTxtAttr->GetEnd();
    2213           4 :                 if( nEnd > nSt )
    2214             :                 {
    2215           4 :                     Range aTmp( nSt, nEnd - 1 );
    2216           4 :                     rHiddenMulti.Select( aTmp, pHiddenItem->GetValue() );
    2217             :                 }
    2218             :             }
    2219             :         }
    2220             :     }
    2221        1888 : }
    2222             : 
    2223        1888 : void SwScriptInfo::selectRedLineDeleted(const SwTxtNode& rNode, MultiSelection &rHiddenMulti, bool bSelect)
    2224             : {
    2225             :     assert((!rNode.GetTxt().Len() && rHiddenMulti.GetTotalRange().Len() == 1) ||
    2226             :            (rNode.GetTxt().Len() == rHiddenMulti.GetTotalRange().Len()));
    2227             : 
    2228        1888 :     const IDocumentRedlineAccess& rIDRA = *rNode.getIDocumentRedlineAccess();
    2229        1888 :     if ( IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineMode() ) )
    2230             :     {
    2231        1844 :         sal_uInt16 nAct = rIDRA.GetRedlinePos( rNode, USHRT_MAX );
    2232             : 
    2233        1853 :         for ( ; nAct < rIDRA.GetRedlineTbl().size(); nAct++ )
    2234             :         {
    2235           9 :             const SwRedline* pRed = rIDRA.GetRedlineTbl()[ nAct ];
    2236             : 
    2237           9 :             if ( pRed->Start()->nNode > rNode.GetIndex() )
    2238             :                 break;
    2239             : 
    2240             :             xub_StrLen nRedlStart;
    2241             :             xub_StrLen nRedlnEnd;
    2242           9 :             pRed->CalcStartEnd( rNode.GetIndex(), nRedlStart, nRedlnEnd );
    2243             :             //clip it if the redline extends past the end of the nodes text
    2244           9 :             nRedlnEnd = std::min(nRedlnEnd, rNode.GetTxt().Len());
    2245           9 :             if ( nRedlnEnd > nRedlStart )
    2246             :             {
    2247           9 :                 Range aTmp( nRedlStart, nRedlnEnd - 1 );
    2248           9 :                 rHiddenMulti.Select( aTmp, bSelect );
    2249             :             }
    2250             :         }
    2251             :     }
    2252        1888 : }
    2253             : 
    2254             : /*************************************************************************
    2255             :  * SwScriptInfo::CalcHiddenRanges()
    2256             :  *
    2257             :  * Returns a MultiSection indicating the hidden ranges.
    2258             :  *************************************************************************/
    2259             : 
    2260        1566 : void SwScriptInfo::CalcHiddenRanges( const SwTxtNode& rNode, MultiSelection& rHiddenMulti )
    2261             : {
    2262        1566 :     selectHiddenTextProperty(rNode, rHiddenMulti);
    2263             : 
    2264             :     // If there are any hidden ranges in the current text node, we have
    2265             :     // to unhide the redlining ranges:
    2266        1566 :     selectRedLineDeleted(rNode, rHiddenMulti, false);
    2267             : 
    2268             :     //
    2269             :     // We calculated a lot of stuff. Finally we can update the flags at the text node.
    2270             :     //
    2271        1566 :     const bool bNewContainsHiddenChars = rHiddenMulti.GetRangeCount() > 0;
    2272        1566 :     bool bNewHiddenCharsHidePara = false;
    2273        1566 :     if ( bNewContainsHiddenChars )
    2274             :     {
    2275           0 :         const Range& rRange = rHiddenMulti.GetRange( 0 );
    2276           0 :         const xub_StrLen nHiddenStart = (xub_StrLen)rRange.Min();
    2277           0 :         const xub_StrLen nHiddenEnd = (xub_StrLen)rRange.Max() + 1;
    2278           0 :         bNewHiddenCharsHidePara = ( nHiddenStart == 0 && nHiddenEnd >= rNode.GetTxt().Len() );
    2279             :     }
    2280        1566 :     rNode.SetHiddenCharAttribute( bNewHiddenCharsHidePara, bNewContainsHiddenChars );
    2281        1566 : }
    2282             : 
    2283             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10