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