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