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