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