xref: /aoo41x/main/sw/source/core/text/txthyph.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <hintids.hxx>
33 #include <editeng/unolingu.hxx>
34 #include <com/sun/star/i18n/WordType.hpp>
35 #include <EnhancedPDFExportHelper.hxx>
36 #include <viewopt.hxx>	// SwViewOptions
37 #include <viewsh.hxx>
38 #include <errhdl.hxx>
39 #include <txtcfg.hxx>
40 #include <SwPortionHandler.hxx>
41 #include <porhyph.hxx>	//
42 #include <inftxt.hxx>
43 #include <itrform2.hxx> //
44 #include <guess.hxx>	//
45 #include <splargs.hxx>	// SwInterHyphInfo
46 
47 #ifdef DBG_UTIL
48 extern const sal_Char *GetLangName( const MSHORT nLang );
49 #endif
50 
51 using ::rtl::OUString;
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::beans;
55 using namespace ::com::sun::star::linguistic2;
56 using namespace ::com::sun::star::i18n;
57 
58 /*************************************************************************
59  *						SwTxtFormatInfo::HyphWord()
60  *************************************************************************/
61 
62 Reference< XHyphenatedWord >  SwTxtFormatInfo::HyphWord(
63 								const XubString &rTxt, const MSHORT nMinTrail )
64 {
65 	if( rTxt.Len() < 4 || pFnt->IsSymbol(pVsh) )
66 		return 0;
67 //	ASSERT( IsHyphenate(), "SwTxtFormatter::HyphWord: why?" );
68 	Reference< XHyphenator >  xHyph = ::GetHyphenator();
69 	Reference< XHyphenatedWord > xHyphWord;
70 
71 	if( xHyph.is() )
72 		xHyphWord = xHyph->hyphenate( OUString(rTxt),
73 							pBreakIt->GetLocale( pFnt->GetLanguage() ),
74 							rTxt.Len() - nMinTrail, GetHyphValues() );
75 	return xHyphWord;
76 
77 }
78 
79 /*************************************************************************
80  *						SwTxtFrm::Hyphenate
81  *
82  * Wir formatieren eine Zeile fuer die interaktive Trennung
83  *************************************************************************/
84 
85 sal_Bool SwTxtFrm::Hyphenate( SwInterHyphInfo &rHyphInf )
86 {
87     ASSERT( ! IsVertical() || ! IsSwapped(),"swapped frame at SwTxtFrm::Hyphenate" );
88 
89     if( !pBreakIt->GetBreakIter().is() )
90 		return sal_False;;
91 	// Wir machen den Laden erstmal dicht:
92 	ASSERT( !IsLocked(), "SwTxtFrm::Hyphenate: this is locked" );
93     // 4935: Der frame::Frame muss eine gueltige SSize haben!
94 	Calc();
95 	GetFormatted();
96 
97 	sal_Bool bRet = sal_False;
98 	if( !IsEmpty() )
99 	{
100 		// Wir muessen die Trennung immer einschalten.
101 		// Keine Angst, der SwTxtIter sichert im Hyphenate die alte Zeile.
102 		SwTxtFrmLocker aLock( this );
103 
104         if ( IsVertical() )
105             SwapWidthAndHeight();
106 
107         SwTxtFormatInfo aInf( this, sal_True );     // sal_True fuer interactive hyph!
108 		SwTxtFormatter aLine( this, &aInf );
109         aLine.CharToLine( rHyphInf.nStart );
110 		// Wenn wir innerhalb des ersten Wortes einer Zeile stehen, so koennte
111 		// dieses in der vorherigen getrennt werden, deshalb gehen wir ein Zeile
112 		// zurueck.
113 		if( aLine.Prev() )
114 		{
115 			SwLinePortion *pPor = aLine.GetCurr()->GetFirstPortion();
116 			while( pPor->GetPortion() )
117 				pPor = pPor->GetPortion();
118 			if( pPor->GetWhichPor() == POR_SOFTHYPH ||
119 				pPor->GetWhichPor() == POR_SOFTHYPHSTR )
120 				aLine.Next();
121 		}
122 
123 		const xub_StrLen nEnd = rHyphInf.GetEnd();
124 		while( !bRet && aLine.GetStart() < nEnd )
125 		{
126 			DBG_LOOP;
127 			bRet = aLine.Hyphenate( rHyphInf );
128 			if( !aLine.Next() )
129 				break;
130 		}
131 
132         if ( IsVertical() )
133             SwapWidthAndHeight();
134     }
135 	return bRet;
136 }
137 
138 /*************************************************************************
139  *						SwTxtFormatter::Hyphenate
140  *
141  * Wir formatieren eine Zeile fuer die interaktive Trennung
142  *************************************************************************/
143 // Wir koennen davon ausgehen, dass bereits formatiert wurde.
144 // Fuer die CeBIT'93 gehen wir den einfachen, sicheren Weg:
145 // Die Zeile wird einfach neu formatiert, der Hyphenator wird dann
146 // so vorbereitet, wie ihn die UI erwartet.
147 // Hier stehen natuerlich enorme Optimierungsmoeglichkeiten offen.
148 
149 void SetParaPortion( SwTxtInfo *pInf, SwParaPortion *pRoot )
150 {
151 	ASSERT( pRoot, "SetParaPortion: no root anymore" );
152 	pInf->pPara = pRoot;
153 }
154 
155 sal_Bool SwTxtFormatter::Hyphenate( SwInterHyphInfo &rHyphInf )
156 {
157 	SwTxtFormatInfo &rInf = GetInfo();
158 	sal_Bool bRet = sal_False;
159 
160 	// In der letzten Zeile gibt es nie etwas zu trennen.
161 	// Es sei denn, es befindet sich eine FlyPortion darin,
162 	// oder es ist die letzte Zeile des Masters
163 	if( !GetNext() && !rInf.GetTxtFly()->IsOn() && !pFrm->GetFollow() )
164 		return bRet;
165 
166 	xub_StrLen nWrdStart = nStart;
167 
168 	// Wir muessen die alte Zeile erhalten. Ein Beispiel:
169 	// Das Attribut fuer Trennung wurde nicht gesetzt,
170 	// in SwTxtFrm::Hyphenate wird es jedoch immer gesetzt,
171 	// weil wir Trennpositionen im Hyphenator einstellen wollen.
172 	SwLineLayout *pOldCurr = pCurr;
173 
174 	InitCntHyph();
175 
176 	// 5298: IsParaLine() (ex.IsFirstLine) fragt auf GetParaPortion() ab.
177 	// wir muessen gleiche Bedingungen schaffen: in der ersten
178 	// Zeile formatieren wir SwParaPortions...
179 	if( pOldCurr->IsParaPortion() )
180 	{
181 		SwParaPortion *pPara = new SwParaPortion();
182 		SetParaPortion( &rInf, pPara );
183 		pCurr = pPara;
184 		ASSERT( IsParaLine(), "SwTxtFormatter::Hyphenate: not the first" );
185 	}
186 	else
187 		pCurr = new SwLineLayout();
188 
189 	nWrdStart = FormatLine( nWrdStart );
190 
191 	// Man muss immer im Hinterkopf behalten, dass es z.B.
192 	// Felder gibt, die aufgetrennt werden koennen ...
193 	if( pCurr->PrtWidth() && pCurr->GetLen() )
194 	{
195 		// Wir muessen uns darauf einstellen, dass in der Zeile
196 		// FlyFrms haengen, an denen auch umgebrochen werden darf.
197 		// Wir suchen also die erste HyphPortion in dem angegebenen
198 		// Bereich.
199 
200 		SwLinePortion *pPos = pCurr->GetPortion();
201 		const xub_StrLen nPamStart = rHyphInf.nStart;
202 		nWrdStart = nStart;
203 		const xub_StrLen nEnd = rHyphInf.GetEnd();
204 		while( pPos )
205 		{
206 			// Entweder wir liegen drueber oder wir laufen gerade auf eine
207 			// Hyphportion die am Ende der Zeile oder vor einem Flys steht.
208 			if( nWrdStart >= nEnd )
209 			{
210 				nWrdStart = 0;
211 				break;
212 			}
213 
214 			if( nWrdStart >= nPamStart && pPos->InHyphGrp()
215 				&& ( !pPos->IsSoftHyphPortion()
216 					 || ((SwSoftHyphPortion*)pPos)->IsExpand() ) )
217 			{
218                 nWrdStart = nWrdStart + pPos->GetLen();
219 				break;
220 			}
221 
222 			nWrdStart = nWrdStart + pPos->GetLen();
223 			pPos = pPos->GetPortion();
224 		}
225 		// Wenn pPos 0 ist, wurde keine Trennstelle ermittelt.
226 		if( !pPos )
227 			nWrdStart = 0;
228 	}
229 
230 	// Das alte LineLayout wird wieder eingestellt ...
231 	delete pCurr;
232 	pCurr = pOldCurr;
233 
234 	if( pOldCurr->IsParaPortion() )
235 	{
236 		SetParaPortion( &rInf, (SwParaPortion*)pOldCurr );
237 		ASSERT( IsParaLine(), "SwTxtFormatter::Hyphenate: even not the first" );
238 	}
239 
240 	if( nWrdStart )
241 	{
242 		// nWrdStart bezeichnet nun die Position im String, der
243 		// fuer eine Trennung zur Debatte steht.
244 		// Start() hangelt sich zum End()
245 		rHyphInf.nWordStart = nWrdStart;
246 
247 		xub_StrLen nLen = 0;
248 		const xub_StrLen nEnd = nWrdStart;
249 
250 		// Wir suchen vorwaerts
251 		Reference< XHyphenatedWord > xHyphWord;
252 
253 	    Boundary aBound =
254 			pBreakIt->GetBreakIter()->getWordBoundary( rInf.GetTxt(), nWrdStart,
255 			pBreakIt->GetLocale( rInf.GetFont()->GetLanguage() ), WordType::DICTIONARY_WORD, sal_True );
256         nWrdStart = static_cast<xub_StrLen>(aBound.startPos);
257         nLen = static_cast<xub_StrLen>(aBound.endPos - nWrdStart);
258 		bRet = 0 != nLen;
259 		if( bRet )
260 		{
261 			XubString aSelTxt( rInf.GetTxt().Copy(nWrdStart, nLen) );
262 			xub_StrLen nCnt = 0;
263 
264 // these things should be handled by the dialog
265 //            for( xub_StrLen i = 0; i < nLen; ++i )
266 //            {
267 //                sal_Unicode cCh = aSelTxt.GetChar(i);
268 //                if( (CH_TXTATR_BREAKWORD == cCh || CH_TXTATR_INWORD == cCh )
269 //                     && rInf.HasHint( nWrdStart + i ) )
270 //                {
271 //                    aSelTxt.Erase( i , 1 );
272 //                    nCnt++;
273 //                    --nLen;
274 //                    if( i )
275 //                        --i;
276 //                }
277 //            }
278 
279 			{
280 				MSHORT nMinTrail = 0;
281 				if( nWrdStart + nLen > nEnd )
282 					nMinTrail = nWrdStart + nLen - nEnd - 1;
283 
284 				//!! rHyphInf.SetHyphWord( ... ) mu??? hier geschehen
285 				xHyphWord = rInf.HyphWord( aSelTxt, nMinTrail );
286 				bRet = xHyphWord.is();
287 				if ( !rHyphInf.IsCheck() && sal_False == bRet )
288 					rHyphInf.SetNoLang( sal_True );
289 			}
290 
291 			if( bRet )
292 			{
293 				rHyphInf.SetHyphWord( xHyphWord );
294 				rHyphInf.nWordStart = nWrdStart;
295 				rHyphInf.nWordLen	= nLen+nCnt;
296 				rHyphInf.SetNoLang( sal_False );
297 				rHyphInf.SetCheck( sal_True );
298 			}
299 #ifdef DEBUGGY
300 			if( OPTDBG( rInf ) )
301 			{
302 				ASSERT( aSelTxt == aHyphWord,
303 						"!SwTxtFormatter::Hyphenate: different words, different planets" );
304 				aDbstream << "Diff: \"" << aSelTxt.GetStr() << "\" != \""
305 						  << aHyphWord.GetStr() << "\"" << endl;
306 				ASSERT( bRet, "!SwTxtFormatter::Hyphenate: three of a perfect pair" );
307 				aDbstream << "Hyphenate: ";
308 			}
309 #endif
310 		}
311 	}
312 	return bRet;
313 }
314 
315 /*************************************************************************
316  *						SwTxtPortion::CreateHyphen()
317  *************************************************************************/
318 
319 sal_Bool SwTxtPortion::CreateHyphen( SwTxtFormatInfo &rInf, SwTxtGuess &rGuess )
320 {
321 	Reference< XHyphenatedWord >  xHyphWord = rGuess.HyphWord();
322 
323 	ASSERT( !pPortion, "SwTxtPortion::CreateHyphen(): another portion, another planet..." )
324     ASSERT( xHyphWord.is(), "SwTxtPortion::CreateHyphen(): You are lucky! The code is robust here." )
325 
326 	if( rInf.IsHyphForbud() ||
327 		pPortion || // robust
328         !xHyphWord.is() || // more robust
329 		// Mehrzeilige Felder duerfen nicht interaktiv getrennt werden.
330 		( rInf.IsInterHyph() && InFldGrp() ) )
331 		return sal_False;
332 
333 	SwHyphPortion *pHyphPor;
334 	xub_StrLen nPorEnd;
335 	SwTxtSizeInfo aInf( rInf );
336 
337 	// first case: hyphenated word has alternative spelling
338 	if ( xHyphWord->isAlternativeSpelling() )
339     {
340 		SvxAlternativeSpelling aAltSpell;
341 		aAltSpell = SvxGetAltSpelling( xHyphWord );
342 		ASSERT( aAltSpell.bIsAltSpelling, "no alternatve spelling" );
343 
344 		XubString  aAltTxt   = aAltSpell.aReplacement;
345         nPorEnd = aAltSpell.nChangedPos + rGuess.BreakStart() - rGuess.FieldDiff();
346 		xub_StrLen nTmpLen = 0;
347 
348 		// soft hyphen at alternative spelling position?
349 		if( rInf.GetTxt().GetChar( rInf.GetSoftHyphPos() ) == CHAR_SOFTHYPHEN )
350 		{
351 			pHyphPor = new SwSoftHyphStrPortion( aAltTxt );
352 			nTmpLen = 1;
353 		}
354 		else {
355 			pHyphPor = new SwHyphStrPortion( aAltTxt );
356 		}
357 
358 		// length of pHyphPor is adjusted
359 		pHyphPor->SetLen( aAltTxt.Len() + 1 );
360 		(SwPosSize&)(*pHyphPor) = pHyphPor->GetTxtSize( rInf );
361 		pHyphPor->SetLen( aAltSpell.nChangedLength + nTmpLen );
362 	}
363     else
364     {
365 		// second case: no alternative spelling
366 		SwHyphPortion aHyphPor;
367 		aHyphPor.SetLen( 1 );
368 
369 		static const void* pLastMagicNo = 0;
370 		static KSHORT aMiniCacheH = 0, aMiniCacheW = 0;
371 		const void* pTmpMagic;
372 		MSHORT nFntIdx;
373 		rInf.GetFont()->GetMagic( pTmpMagic, nFntIdx, rInf.GetFont()->GetActual() );
374 		if( !pLastMagicNo || pLastMagicNo != pTmpMagic ) {
375 			pLastMagicNo = pTmpMagic;
376 			(SwPosSize&)aHyphPor = aHyphPor.GetTxtSize( rInf );
377 			aMiniCacheH = aHyphPor.Height(), aMiniCacheW = aHyphPor.Width();
378 		} else {
379 			aHyphPor.Height( aMiniCacheH ), aHyphPor.Width( aMiniCacheW );
380 		}
381 		aHyphPor.SetLen( 0 );
382 		pHyphPor = new SwHyphPortion( aHyphPor );
383 
384 		pHyphPor->SetWhichPor( POR_HYPH );
385 
386 		// values required for this
387         nPorEnd = xHyphWord->getHyphenPos() + 1 + rGuess.BreakStart()
388                 - rGuess.FieldDiff();
389 	}
390 
391 	// portion end must be in front of us
392 	// we do not put hyphens at start of line
393 	if ( nPorEnd > rInf.GetIdx() ||
394 		 ( nPorEnd == rInf.GetIdx() && rInf.GetLineStart() != rInf.GetIdx() ) )
395 	{
396 		aInf.SetLen( nPorEnd - rInf.GetIdx() );
397 		pHyphPor->SetAscent( GetAscent() );
398 		SetLen( aInf.GetLen() );
399 		CalcTxtSize( aInf );
400 
401 		Insert( pHyphPor );
402 
403 		short nKern = rInf.GetFont()->CheckKerning();
404 		if( nKern )
405 			new SwKernPortion( *this, nKern );
406 
407 		return sal_True;
408 	}
409 
410 	// last exit for the lost
411 	delete pHyphPor;
412 	BreakCut( rInf, rGuess );
413 	return sal_False;
414 }
415 
416 
417 /*************************************************************************
418  *              virtual SwHyphPortion::GetExpTxt()
419  *************************************************************************/
420 
421 sal_Bool SwHyphPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
422 {
423     // --> FME 2004-06-24 #i16816# tagged pdf support
424     const sal_Unicode cChar = rInf.GetVsh() &&
425                               rInf.GetVsh()->GetViewOptions()->IsPDFExport() &&
426                               SwTaggedPDFHelper::IsExportTaggedPDF( *rInf.GetOut() ) ?
427                               0xad :
428                               '-';
429     // <--
430 
431     rTxt = cChar;
432 	return sal_True;
433 }
434 
435 /*************************************************************************
436  *              virtual SwHyphPortion::HandlePortion()
437  *************************************************************************/
438 
439 void SwHyphPortion::HandlePortion( SwPortionHandler& rPH ) const
440 {
441     String aString( '-' );
442     rPH.Special( GetLen(), aString, GetWhichPor() );
443 }
444 
445 /*************************************************************************
446  *                 virtual SwHyphPortion::Format()
447  *************************************************************************/
448 
449 sal_Bool SwHyphPortion::Format( SwTxtFormatInfo &rInf )
450 {
451 	const SwLinePortion *pLast = rInf.GetLast();
452 	Height( pLast->Height() );
453 	SetAscent( pLast->GetAscent() );
454 	XubString aTxt;
455 
456 	if( !GetExpTxt( rInf, aTxt ) )
457 		return sal_False;
458 
459 	PrtWidth( rInf.GetTxtSize( aTxt ).Width() );
460 	const sal_Bool bFull = rInf.Width() <= rInf.X() + PrtWidth();
461 	if( bFull && !rInf.IsUnderFlow() ) {
462 		Truncate();
463 		rInf.SetUnderFlow( this );
464 	}
465 
466 	return bFull;
467 }
468 
469 /*************************************************************************
470  *              virtual SwHyphStrPortion::GetExpTxt()
471  *************************************************************************/
472 
473 sal_Bool SwHyphStrPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const
474 {
475 	rTxt = aExpand;
476 	return sal_True;
477 }
478 
479 /*************************************************************************
480  *              virtual SwHyphStrPortion::HandlePortion()
481  *************************************************************************/
482 
483 void SwHyphStrPortion::HandlePortion( SwPortionHandler& rPH ) const
484 {
485     rPH.Special( GetLen(), aExpand, GetWhichPor() );
486 }
487 
488 /*************************************************************************
489  *                      class SwSoftHyphPortion
490  *************************************************************************/
491 
492 SwLinePortion *SwSoftHyphPortion::Compress() { return this; }
493 
494 SwSoftHyphPortion::SwSoftHyphPortion() :
495 	bExpand(sal_False), nViewWidth(0), nHyphWidth(0)
496 {
497 	SetLen(1);
498 	SetWhichPor( POR_SOFTHYPH );
499 }
500 
501 KSHORT SwSoftHyphPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
502 {
503 	// Wir stehen zwar im const, aber nViewWidth sollte erst im letzten
504 	// Moment errechnet werden:
505 	if( !Width() && rInf.OnWin() && rInf.GetOpt().IsSoftHyph() && !IsExpand() )
506 	{
507 		if( !nViewWidth )
508 			((SwSoftHyphPortion*)this)->nViewWidth
509 				= rInf.GetTxtSize( '-' ).Width();
510 	}
511 	else
512 		((SwSoftHyphPortion*)this)->nViewWidth = 0;
513 	return nViewWidth;
514 }
515 
516 /*  Faelle:
517  *  1) SoftHyph steht in der Zeile, ViewOpt aus.
518  *     -> unsichtbar, Nachbarn unveraendert
519  *  2) SoftHyph steht in der Zeile, ViewOpt an.
520  *     -> sichtbar, Nachbarn veraendert
521  *  3) SoftHyph steht am Zeilenende, ViewOpt aus/an.
522  *     -> immer sichtbar, Nachbarn unveraendert
523  */
524 
525 void SwSoftHyphPortion::Paint( const SwTxtPaintInfo &rInf ) const
526 {
527 	if( Width() )
528 	{
529 		rInf.DrawViewOpt( *this, POR_SOFTHYPH );
530 		SwExpandPortion::Paint( rInf );
531 	}
532 }
533 
534 /*************************************************************************
535  *                 virtual SwSoftHyphPortion::Format()
536  *************************************************************************/
537 
538 /* Die endgueltige Breite erhalten wir im FormatEOL().
539  * In der Underflow-Phase stellen wir fest, ob ueberhaupt ein
540  * alternatives Spelling vorliegt. Wenn ja ...
541  *
542  * Fall 1: "Au-to"
543  * 1) {Au}{-}{to}, {to} passt nicht mehr => Underflow
544  * 2) {-} ruft Hyphenate => keine Alternative
545  * 3) FormatEOL() und bFull = sal_True
546  *
547  * Fall 2: "Zuc-ker"
548  * 1) {Zuc}{-}{ker}, {ker} passt nicht mehr => Underflow
549  * 2) {-} ruft Hyphenate => Alternative!
550  * 3) Underflow() und bFull = sal_True
551  * 4) {Zuc} ruft Hyphenate => {Zuk}{-}{ker}
552  */
553 
554 sal_Bool SwSoftHyphPortion::Format( SwTxtFormatInfo &rInf )
555 {
556 	sal_Bool bFull = sal_True;
557 
558 	// special case for old german spelling
559 	if( rInf.IsUnderFlow()	)
560 	{
561 		if( rInf.GetSoftHyphPos() )
562 			return sal_True;
563 
564 		const sal_Bool bHyph = rInf.ChgHyph( sal_True );
565 		if( rInf.IsHyphenate() )
566 		{
567 			rInf.SetSoftHyphPos( rInf.GetIdx() );
568 			Width(0);
569 			// if the soft hyphend word has an alternative spelling
570 			// when hyphenated (old german spelling), the soft hyphen
571 			// portion has to trigger an underflow
572 			SwTxtGuess aGuess;
573 			bFull = rInf.IsInterHyph() ||
574 					!aGuess.AlternativeSpelling( rInf, rInf.GetIdx() - 1 );
575 		}
576 		rInf.ChgHyph( bHyph );
577 
578 		if( bFull && !rInf.IsHyphForbud() )
579 		{
580 			rInf.SetSoftHyphPos(0);
581 			FormatEOL( rInf );
582 			if ( rInf.GetFly() )
583 				rInf.GetRoot()->SetMidHyph( sal_True );
584 			else
585 				rInf.GetRoot()->SetEndHyph( sal_True );
586 		}
587 		else
588 		{
589 			rInf.SetSoftHyphPos( rInf.GetIdx() );
590 			Truncate();
591 			rInf.SetUnderFlow( this );
592 		}
593 		return sal_True;
594 	}
595 
596 	rInf.SetSoftHyphPos(0);
597 	SetExpand( sal_True );
598 	bFull = SwHyphPortion::Format( rInf );
599 	SetExpand( sal_False );
600 	if( !bFull )
601 	{
602 		// default-maessig besitzen wir keine Breite, aber eine Hoehe
603 		nHyphWidth = Width();
604 		Width(0);
605 	}
606 	return bFull;
607 }
608 
609 /*************************************************************************
610  *				   virtual SwSoftHyphPortion::FormatEOL()
611  *************************************************************************/
612 // Format end of Line
613 
614 void SwSoftHyphPortion::FormatEOL( SwTxtFormatInfo &rInf )
615 {
616 	if( !IsExpand() )
617 	{
618 		SetExpand( sal_True );
619 		if( rInf.GetLast() == this )
620 			rInf.SetLast( FindPrevPortion( rInf.GetRoot() ) );
621 
622 		// 5964: alte Werte muessen wieder zurueckgesetzt werden.
623         const SwTwips nOldX  = rInf.X();
624 		const xub_StrLen nOldIdx = rInf.GetIdx();
625 		rInf.X( rInf.X() - PrtWidth() );
626 		rInf.SetIdx( rInf.GetIdx() - GetLen() );
627 		const sal_Bool bFull = SwHyphPortion::Format( rInf );
628 		nHyphWidth = Width();
629 
630 		// 6976: Eine truebe Sache: Wir werden erlaubterweise breiter,
631 		// aber gleich wird noch ein Fly verarbeitet, der eine korrekte
632 		// X-Position braucht.
633 		if( bFull || !rInf.GetFly() )
634 			rInf.X( nOldX );
635 		else
636 			rInf.X( nOldX + Width() );
637 		rInf.SetIdx( nOldIdx );
638 	}
639 }
640 
641 /*************************************************************************
642  *				virtual SwSoftHyphPortion::GetExpTxt()
643  *
644  * Wir expandieren:
645  * - wenn die Sonderzeichen sichtbar sein sollen
646  * - wenn wir am Ende der Zeile stehen.
647  * - wenn wir vor einem (echten/emuliertem) Zeilenumbruch stehen
648  *************************************************************************/
649 
650 sal_Bool SwSoftHyphPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
651 {
652 	if( IsExpand() || ( rInf.OnWin() && rInf.GetOpt().IsSoftHyph() ) ||
653 		( GetPortion() && ( GetPortion()->InFixGrp() ||
654 		  GetPortion()->IsDropPortion() || GetPortion()->IsLayPortion() ||
655 		  GetPortion()->IsParaPortion() || GetPortion()->IsBreakPortion() ) ) )
656 	{
657 		return SwHyphPortion::GetExpTxt( rInf, rTxt );
658 	}
659 	return sal_False;
660 }
661 
662 /*************************************************************************
663  *              virtual SwSoftHyphPortion::HandlePortion()
664  *************************************************************************/
665 
666 void SwSoftHyphPortion::HandlePortion( SwPortionHandler& rPH ) const
667 {
668     const String aString( '-' );
669     const sal_uInt16 nWhich = ! Width() ?
670                           POR_SOFTHYPH_COMP :
671                           GetWhichPor();
672     rPH.Special( GetLen(), aString, nWhich );
673 }
674 
675 /*************************************************************************
676  *						SwSoftHyphStrPortion::Paint
677  *************************************************************************/
678 
679 void SwSoftHyphStrPortion::Paint( const SwTxtPaintInfo &rInf ) const
680 {
681 	// Bug oder feature?:
682 	// {Zu}{k-}{ker}, {k-} wird grau statt {-}
683 	rInf.DrawViewOpt( *this, POR_SOFTHYPH );
684 	SwHyphStrPortion::Paint( rInf );
685 }
686 
687 SwSoftHyphStrPortion::SwSoftHyphStrPortion( const XubString &rStr )
688 	: SwHyphStrPortion( rStr )
689 {
690 	SetLen( 1 );
691 	SetWhichPor( POR_SOFTHYPHSTR );
692 }
693 
694 
695 
696