xref: /aoo42x/main/sw/source/core/text/guess.cxx (revision 86e1cf34)
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
10efeef26fSAndrew Rist  *
11efeef26fSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12efeef26fSAndrew Rist  *
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.
19efeef26fSAndrew Rist  *
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 #include <ctype.h>
28cdf0e10cSrcweir #include <editeng/unolingu.hxx>
29cdf0e10cSrcweir #include <tools/shl.hxx>    // needed for SW_MOD() macro
30cdf0e10cSrcweir #include <errhdl.hxx>   // ASSERTs
31cdf0e10cSrcweir #include <dlelstnr.hxx>
32cdf0e10cSrcweir #include <swmodule.hxx>
33cdf0e10cSrcweir #include <IDocumentSettingAccess.hxx>
34cdf0e10cSrcweir #include <txtcfg.hxx>
35cdf0e10cSrcweir #include <guess.hxx>
36cdf0e10cSrcweir #include <inftxt.hxx>
37cdf0e10cSrcweir #include <pagefrm.hxx>
38cdf0e10cSrcweir #include <pagedesc.hxx> // SwPageDesc
39cdf0e10cSrcweir #include <tgrditem.hxx>
40cdf0e10cSrcweir #include <com/sun/star/i18n/BreakType.hpp>
41cdf0e10cSrcweir #include <com/sun/star/i18n/WordType.hpp>
42cdf0e10cSrcweir #include <unotools/charclass.hxx>
43cdf0e10cSrcweir #include <porfld.hxx>
44ee093aaeSPedro Giffuni #include <paratr.hxx>
45cdf0e10cSrcweir 
46cdf0e10cSrcweir using ::rtl::OUString;
47cdf0e10cSrcweir using namespace ::com::sun::star;
48cdf0e10cSrcweir using namespace ::com::sun::star::uno;
49cdf0e10cSrcweir using namespace ::com::sun::star::i18n;
50cdf0e10cSrcweir using namespace ::com::sun::star::beans;
51cdf0e10cSrcweir using namespace ::com::sun::star::linguistic2;
52cdf0e10cSrcweir 
53cdf0e10cSrcweir #define CH_FULL_BLANK 0x3000
54cdf0e10cSrcweir 
55cdf0e10cSrcweir /*************************************************************************
56cdf0e10cSrcweir  *						SwTxtGuess::Guess
57cdf0e10cSrcweir  *
58cdf0e10cSrcweir  * provides information for line break calculation
59cdf0e10cSrcweir  * returns true if no line break has to be performed
60cdf0e10cSrcweir  * otherwise possible break or hyphenation position is determined
61cdf0e10cSrcweir  *************************************************************************/
62cdf0e10cSrcweir 
Guess(const SwTxtPortion & rPor,SwTxtFormatInfo & rInf,const KSHORT nPorHeight)63cdf0e10cSrcweir sal_Bool SwTxtGuess::Guess( const SwTxtPortion& rPor, SwTxtFormatInfo &rInf,
64cdf0e10cSrcweir                             const KSHORT nPorHeight )
65cdf0e10cSrcweir {
66cdf0e10cSrcweir 	nCutPos = rInf.GetIdx();
67cdf0e10cSrcweir 
68ee093aaeSPedro Giffuni     // Empty strings are always 0
69cdf0e10cSrcweir 	if( !rInf.GetLen() || !rInf.GetTxt().Len() )
70cdf0e10cSrcweir 		return sal_False;
71cdf0e10cSrcweir 
72cdf0e10cSrcweir     ASSERT( rInf.GetIdx() < rInf.GetTxt().Len(),
73cdf0e10cSrcweir 			"+SwTxtGuess::Guess: invalid SwTxtFormatInfo" );
74cdf0e10cSrcweir 
75cdf0e10cSrcweir     ASSERT( nPorHeight, "+SwTxtGuess::Guess: no height" );
76cdf0e10cSrcweir 
77cdf0e10cSrcweir     sal_uInt16 nMinSize;
78cdf0e10cSrcweir     sal_uInt16 nMaxSizeDiff;
79cdf0e10cSrcweir 
80cdf0e10cSrcweir     const SwScriptInfo& rSI =
81cdf0e10cSrcweir             ((SwParaPortion*)rInf.GetParaPortion())->GetScriptInfo();
82cdf0e10cSrcweir 
83cdf0e10cSrcweir     sal_uInt16 nMaxComp = ( SW_CJK == rInf.GetFont()->GetActual() ) &&
84cdf0e10cSrcweir                         rSI.CountCompChg() &&
85cdf0e10cSrcweir                         ! rInf.IsMulti() &&
86cdf0e10cSrcweir                         ! rPor.InFldGrp() &&
87cdf0e10cSrcweir                         ! rPor.IsDropPortion() ?
88cdf0e10cSrcweir                         10000 :
89cdf0e10cSrcweir                             0 ;
90cdf0e10cSrcweir 
91cdf0e10cSrcweir     SwTwips nLineWidth = rInf.Width() - rInf.X();
92cdf0e10cSrcweir 	xub_StrLen nMaxLen = rInf.GetTxt().Len() - rInf.GetIdx();
93cdf0e10cSrcweir 
94cdf0e10cSrcweir     if ( rInf.GetLen() < nMaxLen )
95cdf0e10cSrcweir         nMaxLen = rInf.GetLen();
96cdf0e10cSrcweir 
97cdf0e10cSrcweir     if( !nMaxLen )
98cdf0e10cSrcweir 		return sal_False;
99cdf0e10cSrcweir 
100cdf0e10cSrcweir 	KSHORT nItalic = 0;
101cdf0e10cSrcweir     if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() )
102cdf0e10cSrcweir     {
103cdf0e10cSrcweir         sal_Bool bAddItalic = sal_True;
104cdf0e10cSrcweir 
105cdf0e10cSrcweir         // do not add extra italic value if we have an active character grid
106cdf0e10cSrcweir         if ( rInf.SnapToGrid() )
107cdf0e10cSrcweir         {
108cdf0e10cSrcweir             GETGRID( rInf.GetTxtFrm()->FindPageFrm() )
109cdf0e10cSrcweir             bAddItalic = !pGrid || GRID_LINES_CHARS != pGrid->GetGridType();
110cdf0e10cSrcweir         }
111cdf0e10cSrcweir 
112cdf0e10cSrcweir         // do not add extra italic value for an isolated blank:
113cdf0e10cSrcweir         if ( 1 == rInf.GetLen() &&
114cdf0e10cSrcweir              CH_BLANK == rInf.GetTxt().GetChar( rInf.GetIdx() ) )
115cdf0e10cSrcweir             bAddItalic = sal_False;
116cdf0e10cSrcweir 
117cdf0e10cSrcweir         nItalic = bAddItalic ? nPorHeight / 12 : 0;
118cdf0e10cSrcweir 
119cdf0e10cSrcweir         nLineWidth -= nItalic;
120cdf0e10cSrcweir 
121cdf0e10cSrcweir         // --> FME 2005-05-13 #i46524# LineBreak bug with italics
122cdf0e10cSrcweir         if ( nLineWidth < 0 ) nLineWidth = 0;
123cdf0e10cSrcweir         // <--
124cdf0e10cSrcweir 	}
125cdf0e10cSrcweir 
126cdf0e10cSrcweir 	// first check if everything fits to line
127cdf0e10cSrcweir     if ( long ( nLineWidth ) * 2 > long ( nMaxLen ) * nPorHeight )
128cdf0e10cSrcweir 	{
129cdf0e10cSrcweir         // call GetTxtSize with maximum compression (for kanas)
130cdf0e10cSrcweir         rInf.GetTxtSize( &rSI, rInf.GetIdx(), nMaxLen,
131cdf0e10cSrcweir                          nMaxComp, nMinSize, nMaxSizeDiff );
132cdf0e10cSrcweir 
133cdf0e10cSrcweir         nBreakWidth = nMinSize;
134cdf0e10cSrcweir 
135cdf0e10cSrcweir 		if ( nBreakWidth <= nLineWidth )
136cdf0e10cSrcweir 		{
137cdf0e10cSrcweir 			// portion fits to line
138cdf0e10cSrcweir 			nCutPos = rInf.GetIdx() + nMaxLen;
139cdf0e10cSrcweir 			if( nItalic &&
140cdf0e10cSrcweir                 ( nCutPos >= rInf.GetTxt().Len() ||
141cdf0e10cSrcweir                   // --> FME 2005-05-13 #i48035# Needed for CalcFitToContent
142cdf0e10cSrcweir                   // if first line ends with a manual line break
143cdf0e10cSrcweir                   rInf.GetTxt().GetChar( nCutPos ) == CH_BREAK ) )
144cdf0e10cSrcweir                   // <--
145cdf0e10cSrcweir 				nBreakWidth = nBreakWidth + nItalic;
146cdf0e10cSrcweir 
147cdf0e10cSrcweir             // save maximum width for later use
148cdf0e10cSrcweir             if ( nMaxSizeDiff )
149cdf0e10cSrcweir                 rInf.SetMaxWidthDiff( (sal_uLong)&rPor, nMaxSizeDiff );
150cdf0e10cSrcweir 
151cdf0e10cSrcweir             return sal_True;
152cdf0e10cSrcweir 		}
153cdf0e10cSrcweir 	}
154cdf0e10cSrcweir 
155cdf0e10cSrcweir 	sal_Bool bHyph = rInf.IsHyphenate() && !rInf.IsHyphForbud();
156cdf0e10cSrcweir 	xub_StrLen nHyphPos = 0;
157cdf0e10cSrcweir 
158cdf0e10cSrcweir 	// nCutPos is the first character not fitting to the current line
159cdf0e10cSrcweir 	// nHyphPos is the first character not fitting to the current line,
160cdf0e10cSrcweir 	// considering an additional "-" for hyphenation
161cdf0e10cSrcweir 	if( bHyph )
162cdf0e10cSrcweir 	{
163cdf0e10cSrcweir         nCutPos = rInf.GetTxtBreak( nLineWidth, nMaxLen, nMaxComp, nHyphPos );
164cdf0e10cSrcweir 
165cdf0e10cSrcweir         if ( !nHyphPos && rInf.GetIdx() )
166cdf0e10cSrcweir 			nHyphPos = rInf.GetIdx() - 1;
167cdf0e10cSrcweir 	}
168cdf0e10cSrcweir 	else
169cdf0e10cSrcweir     {
170cdf0e10cSrcweir         nCutPos = rInf.GetTxtBreak( nLineWidth, nMaxLen, nMaxComp );
171cdf0e10cSrcweir 
172cdf0e10cSrcweir #ifdef DBG_UTIL
173cdf0e10cSrcweir         if ( STRING_LEN != nCutPos )
174cdf0e10cSrcweir         {
175cdf0e10cSrcweir             rInf.GetTxtSize( &rSI, rInf.GetIdx(), nCutPos - rInf.GetIdx(),
176cdf0e10cSrcweir                              nMaxComp, nMinSize, nMaxSizeDiff );
177cdf0e10cSrcweir             ASSERT( nMinSize <= nLineWidth, "What a Guess!!!" );
178cdf0e10cSrcweir         }
179cdf0e10cSrcweir #endif
180cdf0e10cSrcweir     }
181cdf0e10cSrcweir 
182cdf0e10cSrcweir 	if( nCutPos > rInf.GetIdx() + nMaxLen )
183cdf0e10cSrcweir 	{
184cdf0e10cSrcweir 		// second check if everything fits to line
185cdf0e10cSrcweir 		nCutPos = nBreakPos = rInf.GetIdx() + nMaxLen - 1;
186cdf0e10cSrcweir         rInf.GetTxtSize( &rSI, rInf.GetIdx(), nMaxLen, nMaxComp,
187cdf0e10cSrcweir                          nMinSize, nMaxSizeDiff );
188cdf0e10cSrcweir 
189cdf0e10cSrcweir         nBreakWidth = nMinSize;
190cdf0e10cSrcweir 
191ee093aaeSPedro Giffuni         // The following comparison should always give sal_True, otherwise
192ee093aaeSPedro Giffuni         // a pixel rounding error in GetTxtBreak will appear
193cdf0e10cSrcweir 		if ( nBreakWidth <= nLineWidth )
194cdf0e10cSrcweir 		{
195cdf0e10cSrcweir 			if( nItalic && ( nBreakPos + 1 ) >= rInf.GetTxt().Len() )
196cdf0e10cSrcweir 				nBreakWidth = nBreakWidth + nItalic;
197cdf0e10cSrcweir 
198cdf0e10cSrcweir             // save maximum width for later use
199cdf0e10cSrcweir             if ( nMaxSizeDiff )
200cdf0e10cSrcweir                 rInf.SetMaxWidthDiff( (sal_uLong)&rPor, nMaxSizeDiff );
201cdf0e10cSrcweir 
202cdf0e10cSrcweir             return sal_True;
203cdf0e10cSrcweir 		}
204cdf0e10cSrcweir 	}
205cdf0e10cSrcweir 
206cdf0e10cSrcweir     // we have to trigger an underflow for a footnote portion
207cdf0e10cSrcweir     // which does not fit to the current line
208cdf0e10cSrcweir     if ( rPor.IsFtnPortion() )
209cdf0e10cSrcweir     {
210cdf0e10cSrcweir         nBreakPos = rInf.GetIdx();
211cdf0e10cSrcweir         nCutPos = rInf.GetLen();
212cdf0e10cSrcweir         return sal_False;
213cdf0e10cSrcweir     }
214cdf0e10cSrcweir 
215cdf0e10cSrcweir     xub_StrLen nPorLen = 0;
216cdf0e10cSrcweir     // do not call the break iterator nCutPos is a blank
217cdf0e10cSrcweir     xub_Unicode cCutChar = rInf.GetTxt().GetChar( nCutPos );
218cdf0e10cSrcweir     if( CH_BLANK == cCutChar || CH_FULL_BLANK == cCutChar )
219cdf0e10cSrcweir     {
220cdf0e10cSrcweir 		nBreakPos = nCutPos;
221cdf0e10cSrcweir 		xub_StrLen nX = nBreakPos;
222ee093aaeSPedro Giffuni 
223ee093aaeSPedro Giffuni         const SvxAdjust& rAdjust = rInf.GetTxtFrm()->GetTxtNode()->GetSwAttrSet().GetAdjust().GetAdjust();
224ee093aaeSPedro Giffuni         if ( rAdjust == SVX_ADJUST_LEFT )
225ee093aaeSPedro Giffuni         {
226ee093aaeSPedro Giffuni             // we step back until a non blank character has been found
227ee093aaeSPedro Giffuni             // or there is only one more character left
228ee093aaeSPedro Giffuni             while( nX && nBreakPos > rInf.GetTxt().Len() &&
229ee093aaeSPedro Giffuni                    ( CH_BLANK == ( cCutChar = rInf.GetChar( --nX ) ) ||
230ee093aaeSPedro Giffuni                      CH_FULL_BLANK == cCutChar ) )
231ee093aaeSPedro Giffuni                 --nBreakPos;
232ee093aaeSPedro Giffuni         }
2339a73b0dbSPedro Giffuni         else //#i20878#
234ee093aaeSPedro Giffuni         {
235ee093aaeSPedro Giffuni             while( nX && nBreakPos > rInf.GetLineStart() + 1 &&
236ee093aaeSPedro Giffuni                    ( CH_BLANK == ( cCutChar = rInf.GetChar( --nX ) ) ||
237ee093aaeSPedro Giffuni                      CH_FULL_BLANK == cCutChar ) )
238ee093aaeSPedro Giffuni                 --nBreakPos;
239ee093aaeSPedro Giffuni         }
240ee093aaeSPedro Giffuni 
241ee093aaeSPedro Giffuni         if( nBreakPos > rInf.GetIdx() )
242ee093aaeSPedro Giffuni             nPorLen = nBreakPos - rInf.GetIdx();
243cdf0e10cSrcweir         while( ++nCutPos < rInf.GetTxt().Len() &&
244cdf0e10cSrcweir                ( CH_BLANK == ( cCutChar = rInf.GetChar( nCutPos ) ) ||
245cdf0e10cSrcweir                  CH_FULL_BLANK == cCutChar ) )
246cdf0e10cSrcweir 			; // nothing
247ee093aaeSPedro Giffuni 
248cdf0e10cSrcweir 		nBreakStart = nCutPos;
249cdf0e10cSrcweir 	}
250cdf0e10cSrcweir 	else if( pBreakIt->GetBreakIter().is() )
251cdf0e10cSrcweir 	{
252cdf0e10cSrcweir         // New: We should have a look into the last portion, if it was a
253cdf0e10cSrcweir         // field portion. For this, we expand the text of the field portion
254cdf0e10cSrcweir         // into our string. If the line break position is inside of before
255cdf0e10cSrcweir         // the field portion, we trigger an underflow.
256cdf0e10cSrcweir 
257cdf0e10cSrcweir         xub_StrLen nOldIdx = rInf.GetIdx();
258cdf0e10cSrcweir         xub_Unicode cFldChr = 0;
259cdf0e10cSrcweir 
260cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
261cdf0e10cSrcweir         XubString aDebugString;
262cdf0e10cSrcweir #endif
263cdf0e10cSrcweir 
264cdf0e10cSrcweir         // be careful: a field portion can be both: 0x01 (common field)
265cdf0e10cSrcweir         // or 0x02 (the follow of a footnode)
266cdf0e10cSrcweir         if ( rInf.GetLast() && rInf.GetLast()->InFldGrp() &&
267cdf0e10cSrcweir              ! rInf.GetLast()->IsFtnPortion() &&
268cdf0e10cSrcweir              rInf.GetIdx() > rInf.GetLineStart() &&
269cdf0e10cSrcweir              CH_TXTATR_BREAKWORD ==
270cdf0e10cSrcweir                 ( cFldChr = rInf.GetTxt().GetChar( rInf.GetIdx() - 1 ) ) )
271cdf0e10cSrcweir         {
272cdf0e10cSrcweir             SwFldPortion* pFld = (SwFldPortion*)rInf.GetLast();
273cdf0e10cSrcweir             XubString aTxt;
274cdf0e10cSrcweir             pFld->GetExpTxt( rInf, aTxt );
275cdf0e10cSrcweir 
276cdf0e10cSrcweir             if ( aTxt.Len() )
277cdf0e10cSrcweir             {
278cdf0e10cSrcweir                 nFieldDiff = aTxt.Len() - 1;
279cdf0e10cSrcweir                 nCutPos = nCutPos + nFieldDiff;
280cdf0e10cSrcweir                 nHyphPos = nHyphPos + nFieldDiff;
281cdf0e10cSrcweir 
282cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
283cdf0e10cSrcweir                 aDebugString = rInf.GetTxt();
284cdf0e10cSrcweir #endif
285cdf0e10cSrcweir 
286cdf0e10cSrcweir                 XubString& rOldTxt = (XubString&)rInf.GetTxt();
287cdf0e10cSrcweir                 rOldTxt.Erase( rInf.GetIdx() - 1, 1 );
288cdf0e10cSrcweir                 rOldTxt.Insert( aTxt, rInf.GetIdx() - 1 );
289cdf0e10cSrcweir                 rInf.SetIdx( rInf.GetIdx() + nFieldDiff );
290cdf0e10cSrcweir             }
291cdf0e10cSrcweir             else
292cdf0e10cSrcweir                 cFldChr = 0;
293cdf0e10cSrcweir         }
294cdf0e10cSrcweir 
295cdf0e10cSrcweir         LineBreakHyphenationOptions aHyphOpt;
296cdf0e10cSrcweir 		Reference< XHyphenator >  xHyph;
297cdf0e10cSrcweir 		if( bHyph )
298cdf0e10cSrcweir 		{
299cdf0e10cSrcweir 			xHyph = ::GetHyphenator();
300cdf0e10cSrcweir 			aHyphOpt = LineBreakHyphenationOptions( xHyph,
301cdf0e10cSrcweir 								rInf.GetHyphValues(), nHyphPos );
302cdf0e10cSrcweir 		}
303cdf0e10cSrcweir 
304cdf0e10cSrcweir         // Get Language for break iterator.
305cdf0e10cSrcweir         // We have to switch the current language if we have a script
306cdf0e10cSrcweir         // change at nCutPos. Otherwise LATIN punctuation would never
307cdf0e10cSrcweir         // be allowed to be hanging punctuation.
308cdf0e10cSrcweir         // NEVER call GetLang if the string has been modified!!!
309cdf0e10cSrcweir         LanguageType aLang = rInf.GetFont()->GetLanguage();
310cdf0e10cSrcweir 
311cdf0e10cSrcweir         // If we are inside a field portion, we use a temporar string which
312cdf0e10cSrcweir         // differs from the string at the textnode. Therefore we are not allowed
313cdf0e10cSrcweir         // to call the GetLang function.
314cdf0e10cSrcweir         if ( nCutPos && ! rPor.InFldGrp() )
315cdf0e10cSrcweir         {
316cdf0e10cSrcweir             const CharClass& rCC = GetAppCharClass();
317cdf0e10cSrcweir 
318cdf0e10cSrcweir             // step back until a non-punctuation character is reached
319cdf0e10cSrcweir             xub_StrLen nLangIndex = nCutPos;
320cdf0e10cSrcweir 
321cdf0e10cSrcweir             // If a field has been expanded right in front of us we do not
322cdf0e10cSrcweir             // step further than the beginning of the expanded field
323cdf0e10cSrcweir             // (which is the position of the field placeholder in our
324cdf0e10cSrcweir             // original string).
325cdf0e10cSrcweir             const xub_StrLen nDoNotStepOver = CH_TXTATR_BREAKWORD == cFldChr ?
326cdf0e10cSrcweir                                               rInf.GetIdx() - nFieldDiff - 1:
327cdf0e10cSrcweir                                               0;
328cdf0e10cSrcweir 
329cdf0e10cSrcweir             while ( nLangIndex > nDoNotStepOver &&
330cdf0e10cSrcweir                     ! rCC.isLetterNumeric( rInf.GetTxt(), nLangIndex ) )
331cdf0e10cSrcweir                 --nLangIndex;
332cdf0e10cSrcweir 
333cdf0e10cSrcweir             // last "real" character is not inside our current portion
334cdf0e10cSrcweir             // we have to check the script type of the last "real" character
335cdf0e10cSrcweir             if ( nLangIndex < rInf.GetIdx() )
336cdf0e10cSrcweir             {
337cdf0e10cSrcweir                 sal_uInt16 nScript = pBreakIt->GetRealScriptOfText( rInf.GetTxt(),
338cdf0e10cSrcweir                                                                 nLangIndex );
339cdf0e10cSrcweir                 ASSERT( nScript, "Script is not between 1 and 4" );
340cdf0e10cSrcweir 
341cdf0e10cSrcweir                 // compare current script with script from last "real" character
342cdf0e10cSrcweir                 if ( nScript - 1 != rInf.GetFont()->GetActual() )
343cdf0e10cSrcweir                     aLang = rInf.GetTxtFrm()->GetTxtNode()->GetLang(
344cdf0e10cSrcweir                         CH_TXTATR_BREAKWORD == cFldChr ?
345cdf0e10cSrcweir                         nDoNotStepOver :
346cdf0e10cSrcweir                         nLangIndex, 0, nScript );
347cdf0e10cSrcweir             }
348cdf0e10cSrcweir         }
349cdf0e10cSrcweir 
350cdf0e10cSrcweir 		const ForbiddenCharacters aForbidden(
351cdf0e10cSrcweir                 *rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess()->getForbiddenCharacters( aLang, true ) );
352cdf0e10cSrcweir 
353cdf0e10cSrcweir         const sal_Bool bAllowHanging = rInf.IsHanging() && ! rInf.IsMulti() &&
354cdf0e10cSrcweir                                       ! rPor.InFldGrp();
355cdf0e10cSrcweir 
356cdf0e10cSrcweir 		LineBreakUserOptions aUserOpt(
357cdf0e10cSrcweir 				aForbidden.beginLine, aForbidden.endLine,
358cdf0e10cSrcweir                 rInf.HasForbiddenChars(), bAllowHanging, sal_False );
359cdf0e10cSrcweir 
360cdf0e10cSrcweir         //! register listener to LinguServiceEvents now in order to get
361cdf0e10cSrcweir         //! notified about relevant changes in the future
362cdf0e10cSrcweir         SwModule *pModule = SW_MOD();
363cdf0e10cSrcweir         if (!pModule->GetLngSvcEvtListener().is())
364cdf0e10cSrcweir             pModule->CreateLngSvcEvtListener();
365cdf0e10cSrcweir 
366cdf0e10cSrcweir         // !!! We must have a local copy of the locale, because inside
367cdf0e10cSrcweir         // getLineBreak the LinguEventListener can trigger a new formatting,
368cdf0e10cSrcweir         // which can corrupt the locale pointer inside pBreakIt.
369cdf0e10cSrcweir         const lang::Locale aLocale = pBreakIt->GetLocale( aLang );
370cdf0e10cSrcweir 
371cdf0e10cSrcweir         // determines first possible line break from nRightPos to
372cdf0e10cSrcweir         // start index of current line
373cdf0e10cSrcweir         LineBreakResults aResult = pBreakIt->GetBreakIter()->getLineBreak(
374cdf0e10cSrcweir             rInf.GetTxt(), nCutPos, aLocale,
375cdf0e10cSrcweir             rInf.GetLineStart(), aHyphOpt, aUserOpt );
376cdf0e10cSrcweir 
377cdf0e10cSrcweir         nBreakPos = (xub_StrLen)aResult.breakIndex;
378cdf0e10cSrcweir 
379cdf0e10cSrcweir         // if we are formatting multi portions we want to allow line breaks
380cdf0e10cSrcweir         // at the border between single line and multi line portion
381*86e1cf34SPedro Giffuni         // we have to be careful with footnote portions, they always come in
382cdf0e10cSrcweir         // with an index 0
383cdf0e10cSrcweir         if ( nBreakPos < rInf.GetLineStart() && rInf.IsFirstMulti() &&
384cdf0e10cSrcweir              ! rInf.IsFtnInside() )
385cdf0e10cSrcweir             nBreakPos = rInf.GetLineStart();
386cdf0e10cSrcweir 
387cdf0e10cSrcweir         nBreakStart = nBreakPos;
388cdf0e10cSrcweir 
389cdf0e10cSrcweir         bHyph = BreakType::HYPHENATION == aResult.breakType;
390cdf0e10cSrcweir 
391cdf0e10cSrcweir 		if ( bHyph && nBreakPos != STRING_LEN)
392cdf0e10cSrcweir 		{
393cdf0e10cSrcweir 			// found hyphenation position within line
394cdf0e10cSrcweir 			// nBreakPos is set to the hyphenation position
395cdf0e10cSrcweir 			xHyphWord = aResult.rHyphenatedWord;
396cdf0e10cSrcweir             nBreakPos += xHyphWord->getHyphenationPos() + 1;
397cdf0e10cSrcweir 
398cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
399cdf0e10cSrcweir             // e.g., Schif-fahrt, referes to our string
400cdf0e10cSrcweir             const String aWord = xHyphWord->getWord();
401cdf0e10cSrcweir             // e.g., Schiff-fahrt, referes to the word after hyphenation
402cdf0e10cSrcweir             const String aHyphenatedWord = xHyphWord->getHyphenatedWord();
403cdf0e10cSrcweir             // e.g., Schif-fahrt: 5, referes to our string
404cdf0e10cSrcweir             const sal_uInt16 nHyphenationPos = xHyphWord->getHyphenationPos();
405cdf0e10cSrcweir             (void)nHyphenationPos;
406cdf0e10cSrcweir             // e.g., Schiff-fahrt: 6, referes to the word after hyphenation
407cdf0e10cSrcweir             const sal_uInt16 nHyphenPos = xHyphWord->getHyphenPos();
408cdf0e10cSrcweir             (void)nHyphenPos;
409cdf0e10cSrcweir #endif
410cdf0e10cSrcweir 
411cdf0e10cSrcweir             // if not in interactive mode, we have to break behind a soft hyphen
412cdf0e10cSrcweir             if ( ! rInf.IsInterHyph() && rInf.GetIdx() )
413cdf0e10cSrcweir             {
414cdf0e10cSrcweir                 const long nSoftHyphPos =
415cdf0e10cSrcweir                         xHyphWord->getWord().indexOf( CHAR_SOFTHYPHEN );
416cdf0e10cSrcweir 
417cdf0e10cSrcweir                 if ( nSoftHyphPos >= 0 &&
418cdf0e10cSrcweir                      nBreakStart + nSoftHyphPos <= nBreakPos &&
419cdf0e10cSrcweir                      nBreakPos > rInf.GetLineStart() )
420cdf0e10cSrcweir                     nBreakPos = rInf.GetIdx() - 1;
421cdf0e10cSrcweir             }
422cdf0e10cSrcweir 
423cdf0e10cSrcweir             if( nBreakPos >= rInf.GetIdx() )
424cdf0e10cSrcweir 			{
425cdf0e10cSrcweir 				nPorLen = nBreakPos - rInf.GetIdx();
426cdf0e10cSrcweir 				if( '-' == rInf.GetTxt().GetChar( nBreakPos - 1 ) )
427cdf0e10cSrcweir 					xHyphWord = NULL;
428cdf0e10cSrcweir 			}
429cdf0e10cSrcweir 		}
430cdf0e10cSrcweir         else if ( !bHyph && nBreakPos >= rInf.GetLineStart() )
431cdf0e10cSrcweir 		{
432cdf0e10cSrcweir             ASSERT( nBreakPos != STRING_LEN, "we should have found a break pos" );
433cdf0e10cSrcweir 
434cdf0e10cSrcweir 			// found break position within line
435cdf0e10cSrcweir 			xHyphWord = NULL;
436cdf0e10cSrcweir 
437cdf0e10cSrcweir             // check, if break position is soft hyphen and an underflow
438cdf0e10cSrcweir             // has to be triggered
439cdf0e10cSrcweir             if( nBreakPos > rInf.GetLineStart() && rInf.GetIdx() &&
440cdf0e10cSrcweir                 CHAR_SOFTHYPHEN == rInf.GetTxt().GetChar( nBreakPos - 1 ) )
441cdf0e10cSrcweir 				nBreakPos = rInf.GetIdx() - 1;
442cdf0e10cSrcweir 
443ee093aaeSPedro Giffuni             const SvxAdjust& rAdjust = rInf.GetTxtFrm()->GetTxtNode()->GetSwAttrSet().GetAdjust().GetAdjust();
444ee093aaeSPedro Giffuni             if( rAdjust != SVX_ADJUST_LEFT )
445ee093aaeSPedro Giffuni             {
446ee093aaeSPedro Giffuni                 // Delete any blanks at the end of a line, but be careful:
447ee093aaeSPedro Giffuni                 // If a field has been expanded, we do not want to delete any
448ee093aaeSPedro Giffuni                 // blanks inside the field portion. This would cause an unwanted
449ee093aaeSPedro Giffuni                 // underflow
450ee093aaeSPedro Giffuni                 xub_StrLen nX = nBreakPos;
451ee093aaeSPedro Giffuni                 while( nX > rInf.GetLineStart() &&
452ee093aaeSPedro Giffuni                        ( CH_TXTATR_BREAKWORD != cFldChr || nX > rInf.GetIdx() ) &&
453ee093aaeSPedro Giffuni                        ( CH_BLANK == rInf.GetChar( --nX ) ||
454ee093aaeSPedro Giffuni                          CH_FULL_BLANK == rInf.GetChar( nX ) ) )
455ee093aaeSPedro Giffuni                     nBreakPos = nX;
456ee093aaeSPedro Giffuni             }
457cdf0e10cSrcweir             if( nBreakPos > rInf.GetIdx() )
458cdf0e10cSrcweir 				nPorLen = nBreakPos - rInf.GetIdx();
459cdf0e10cSrcweir 		}
460cdf0e10cSrcweir         else
461cdf0e10cSrcweir         {
462cdf0e10cSrcweir 			// no line break found, setting nBreakPos to STRING_LEN
463cdf0e10cSrcweir 			// causes a break cut
464cdf0e10cSrcweir 			nBreakPos = STRING_LEN;
465cdf0e10cSrcweir 			ASSERT( nCutPos >= rInf.GetIdx(), "Deep cut" );
466cdf0e10cSrcweir 			nPorLen = nCutPos - rInf.GetIdx();
467cdf0e10cSrcweir 		}
468cdf0e10cSrcweir 
469cdf0e10cSrcweir 		if( nBreakPos > nCutPos && nBreakPos != STRING_LEN )
470cdf0e10cSrcweir 		{
471cdf0e10cSrcweir             const xub_StrLen nHangingLen = nBreakPos - nCutPos;
472cdf0e10cSrcweir             SwPosSize aTmpSize = rInf.GetTxtSize( &rSI, nCutPos,
473cdf0e10cSrcweir                                                   nHangingLen, 0 );
474cdf0e10cSrcweir 			ASSERT( !pHanging, "A hanging portion is hanging around" );
475cdf0e10cSrcweir 			pHanging = new SwHangingPortion( aTmpSize );
476cdf0e10cSrcweir             pHanging->SetLen( nHangingLen );
477cdf0e10cSrcweir             nPorLen = nCutPos - rInf.GetIdx();
478cdf0e10cSrcweir         }
479cdf0e10cSrcweir 
480cdf0e10cSrcweir         // If we expanded a field, we must repair the original string.
481cdf0e10cSrcweir         // In case we do not trigger an underflow, we correct the nBreakPos
482cdf0e10cSrcweir         // value, but we cannot correct the nBreakStart value:
483cdf0e10cSrcweir         // If we have found a hyphenation position, nBreakStart can lie before
484cdf0e10cSrcweir         // the field.
485cdf0e10cSrcweir         if ( CH_TXTATR_BREAKWORD == cFldChr )
486cdf0e10cSrcweir         {
487cdf0e10cSrcweir             if ( nBreakPos < rInf.GetIdx() )
488cdf0e10cSrcweir                 nBreakPos = nOldIdx - 1;
489cdf0e10cSrcweir             else if ( STRING_LEN != nBreakPos )
490cdf0e10cSrcweir             {
491cdf0e10cSrcweir                 ASSERT( nBreakPos >= nFieldDiff, "I've got field trouble!" );
492cdf0e10cSrcweir                 nBreakPos = nBreakPos - nFieldDiff;
493cdf0e10cSrcweir             }
494cdf0e10cSrcweir 
495cdf0e10cSrcweir             ASSERT( nCutPos >= rInf.GetIdx() && nCutPos >= nFieldDiff,
496cdf0e10cSrcweir                     "I've got field trouble, part2!" );
497cdf0e10cSrcweir             nCutPos = nCutPos - nFieldDiff;
498cdf0e10cSrcweir 
499cdf0e10cSrcweir             XubString& rOldTxt = (XubString&)rInf.GetTxt();
500cdf0e10cSrcweir             rOldTxt.Erase( nOldIdx - 1, nFieldDiff + 1 );
501cdf0e10cSrcweir             rOldTxt.Insert( cFldChr, nOldIdx - 1 );
502cdf0e10cSrcweir             rInf.SetIdx( nOldIdx );
503cdf0e10cSrcweir 
504cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
505cdf0e10cSrcweir             ASSERT( aDebugString == rInf.GetTxt(),
506cdf0e10cSrcweir                     "Somebody, somebody, somebody put something in my string" );
507cdf0e10cSrcweir #endif
508cdf0e10cSrcweir         }
509cdf0e10cSrcweir     }
510cdf0e10cSrcweir 
511cdf0e10cSrcweir 	if( nPorLen )
512cdf0e10cSrcweir     {
513cdf0e10cSrcweir         rInf.GetTxtSize( &rSI, rInf.GetIdx(), nPorLen,
514cdf0e10cSrcweir                          nMaxComp, nMinSize, nMaxSizeDiff );
515cdf0e10cSrcweir 
516cdf0e10cSrcweir         // save maximum width for later use
517cdf0e10cSrcweir         if ( nMaxSizeDiff )
518cdf0e10cSrcweir             rInf.SetMaxWidthDiff( (sal_uLong)&rPor, nMaxSizeDiff );
519cdf0e10cSrcweir 
520cdf0e10cSrcweir         nBreakWidth = nItalic + nMinSize;
521cdf0e10cSrcweir     }
522cdf0e10cSrcweir 	else
523cdf0e10cSrcweir 		nBreakWidth = 0;
524cdf0e10cSrcweir 
525cdf0e10cSrcweir     if( pHanging )
526cdf0e10cSrcweir         nBreakPos = nCutPos;
527cdf0e10cSrcweir 
528cdf0e10cSrcweir     return sal_False;
529cdf0e10cSrcweir }
530cdf0e10cSrcweir 
531cdf0e10cSrcweir /*************************************************************************
532cdf0e10cSrcweir  *						SwTxtGuess::AlternativeSpelling
533cdf0e10cSrcweir  *************************************************************************/
534cdf0e10cSrcweir 
535cdf0e10cSrcweir // returns true if word at position nPos has a diffenrent spelling
536cdf0e10cSrcweir // if hyphenated at this position (old german spelling)
537cdf0e10cSrcweir 
AlternativeSpelling(const SwTxtFormatInfo & rInf,const xub_StrLen nPos)538cdf0e10cSrcweir sal_Bool SwTxtGuess::AlternativeSpelling( const SwTxtFormatInfo &rInf,
539cdf0e10cSrcweir 	const xub_StrLen nPos )
540cdf0e10cSrcweir {
541cdf0e10cSrcweir 	// get word boundaries
542cdf0e10cSrcweir 	xub_StrLen nWordLen;
543cdf0e10cSrcweir 
544cdf0e10cSrcweir 	Boundary aBound =
545cdf0e10cSrcweir 		pBreakIt->GetBreakIter()->getWordBoundary( rInf.GetTxt(), nPos,
546cdf0e10cSrcweir 		pBreakIt->GetLocale( rInf.GetFont()->GetLanguage() ),
547cdf0e10cSrcweir 		WordType::DICTIONARY_WORD, sal_True );
548cdf0e10cSrcweir 	nBreakStart = (xub_StrLen)aBound.startPos;
549cdf0e10cSrcweir     nWordLen = static_cast<xub_StrLen>(aBound.endPos - nBreakStart);
550cdf0e10cSrcweir 
551cdf0e10cSrcweir     // if everything else fails, we want to cut at nPos
552cdf0e10cSrcweir     nCutPos = nPos;
553cdf0e10cSrcweir 
554cdf0e10cSrcweir 	XubString aTxt( rInf.GetTxt().Copy( nBreakStart, nWordLen ) );
555cdf0e10cSrcweir 
556cdf0e10cSrcweir 	// check, if word has alternative spelling
557cdf0e10cSrcweir 	Reference< XHyphenator >  xHyph( ::GetHyphenator() );
558cdf0e10cSrcweir 	ASSERT( xHyph.is(), "Hyphenator is missing");
559cdf0e10cSrcweir 	//! subtract 1 since the UNO-interface is 0 based
560cdf0e10cSrcweir 	xHyphWord =	xHyph->queryAlternativeSpelling( OUString(aTxt),
561cdf0e10cSrcweir 						pBreakIt->GetLocale( rInf.GetFont()->GetLanguage() ),
562cdf0e10cSrcweir 						nPos - nBreakStart, rInf.GetHyphValues() );
563cdf0e10cSrcweir 	return xHyphWord.is() && xHyphWord->isAlternativeSpelling();
564cdf0e10cSrcweir }
565cdf0e10cSrcweir 
566