LCOV - code coverage report
Current view: top level - sw/source/core/text - porlay.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 973 0.0 %
Date: 2014-04-14 Functions: 0 57 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10