xref: /trunk/main/sw/source/core/text/itrpaint.cxx (revision 70544ec4)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include "hintids.hxx"
29 #include "flyfrm.hxx"	  // SwFlyInCntFrm
30 #include "viewopt.hxx"	// SwViewOptions
31 #include "errhdl.hxx"
32 #include "txtatr.hxx"  // SwINetFmt
33 #include <tools/multisel.hxx>
34 #include <editeng/escpitem.hxx>
35 #include <editeng/udlnitem.hxx>
36 #include <editeng/lrspitem.hxx>
37 #include <txtinet.hxx>
38 #include <fchrfmt.hxx>
39 #include <frmatr.hxx>
40 #include <sfx2/printer.hxx>
41 #include <fmtftn.hxx>
42 #include <fmtfld.hxx>
43 #include <fldbas.hxx>      // SwField
44 #include <rootfrm.hxx>
45 #include <pagefrm.hxx>
46 #include <pagedesc.hxx> // SwPageDesc
47 #include <tgrditem.hxx>
48 
49 // --> FME 2004-06-08 #i12836# enhanced pdf export
50 #include <EnhancedPDFExportHelper.hxx>
51 // <--
52 
53 
54 #include "flyfrms.hxx"
55 #include "viewsh.hxx"
56 #include "txtcfg.hxx"
57 #include "itrpaint.hxx"
58 #include "txtfrm.hxx"   // pFrm
59 #include "txtfly.hxx"
60 #include "swfont.hxx"
61 #include "txtpaint.hxx"
62 #include "portab.hxx"   // SwTabPortion::IsFilled
63 #include "porfly.hxx"	  // SwFlyCntPortion
64 #include "porfld.hxx"	// SwGrfNumPortion
65 #include "frmfmt.hxx"	// LRSpace
66 #include "txatbase.hxx" // SwTxtAttr
67 #include "charfmt.hxx"  // SwFmtCharFmt
68 #include "redlnitr.hxx" // SwRedlineItr
69 #include "porrst.hxx"	// SwArrowPortion
70 #include "pormulti.hxx"
71 
72 /*************************************************************************
73  *                  IsUnderlineBreak
74  *
75  * Returns, if we have an underline breaking situation
76  * Adding some more conditions here means you also have to change them
77  * in SwTxtPainter::CheckSpecialUnderline
78  *************************************************************************/
IsUnderlineBreak(const SwLinePortion & rPor,const SwFont & rFnt)79 sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
80 {
81     return UNDERLINE_NONE == rFnt.GetUnderline() ||
82            rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
83            rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
84            rPor.IsHolePortion() ||
85           ( rPor.IsMultiPortion() && ! ((SwMultiPortion&)rPor).IsBidi() ) ||
86            rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
87            SVX_CASEMAP_KAPITAELCHEN == rFnt.GetCaseMap();
88 }
89 
90 /*************************************************************************
91  *					SwTxtPainter::CtorInitTxtPainter()
92  *************************************************************************/
CtorInitTxtPainter(SwTxtFrm * pNewFrm,SwTxtPaintInfo * pNewInf)93 void SwTxtPainter::CtorInitTxtPainter( SwTxtFrm *pNewFrm, SwTxtPaintInfo *pNewInf )
94 {
95     CtorInitTxtCursor( pNewFrm, pNewInf );
96 	pInf = pNewInf;
97     SwFont *pMyFnt = GetFnt();
98     GetInfo().SetFont( pMyFnt );
99 #ifdef DBG_UTIL
100     if( ALIGN_BASELINE != pMyFnt->GetAlign() )
101 	{
102         ASSERT( ALIGN_BASELINE == pMyFnt->GetAlign(),
103 				"+SwTxtPainter::CTOR: font alignment revolution" );
104         pMyFnt->SetAlign( ALIGN_BASELINE );
105 	}
106 #endif
107 	bPaintDrop = sal_False;
108 }
109 
110 
111 /*************************************************************************
112  *					  SwTxtPainter::CalcPaintOfst()
113  *************************************************************************/
CalcPaintOfst(const SwRect & rPaint)114 SwLinePortion *SwTxtPainter::CalcPaintOfst( const SwRect &rPaint )
115 {
116 	SwLinePortion *pPor = pCurr->GetFirstPortion();
117 	GetInfo().SetPaintOfst( 0 );
118 	SwTwips nPaintOfst = rPaint.Left();
119 
120 	// nPaintOfst wurde exakt auf das Ende eingestellt, deswegen <=
121 	// nPaintOfst ist dokumentglobal, deswegen nLeftMar aufaddieren
122 	// const KSHORT nLeftMar = KSHORT(GetLeftMargin());
123 	// 8310: painten von LineBreaks in leeren Zeilen.
124 	if( nPaintOfst && pCurr->Width() )
125 	{
126 		SwLinePortion *pLast = 0;
127 		// 7529 und 4757: nicht <= nPaintOfst
128 		while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
129 					   < nPaintOfst )
130 		{
131 			DBG_LOOP;
132 			if( pPor->InSpaceGrp() && GetInfo().GetSpaceAdd() )
133 			{
134 				long nTmp = GetInfo().X() +pPor->Width() +
135 					pPor->CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
136 				if( nTmp + (pPor->Height()/2) >= nPaintOfst )
137 					break;
138 				GetInfo().X( nTmp );
139 				GetInfo().SetIdx( GetInfo().GetIdx() + pPor->GetLen() );
140 			}
141 			else
142 				pPor->Move( GetInfo() );
143 			pLast = pPor;
144 			pPor = pPor->GetPortion();
145 		}
146 
147 		// 7529: bei PostIts auch pLast returnen.
148 		if( pLast && !pLast->Width() &&	pLast->IsPostItsPortion() )
149 		{
150 			pPor = pLast;
151 			GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
152 		}
153 	}
154 	return pPor;
155 }
156 
157 /*************************************************************************
158  *                    SwTxtPainter::DrawTextLine()
159  *
160  * Es gibt zwei Moeglichkeiten bei transparenten Font auszugeben:
161  * 1) DrawRect auf die ganze Zeile und die DrawText hinterher
162  *	  (objektiv schnell, subjektiv langsam).
163  * 2) Fuer jede Portion ein DrawRect mit anschliessendem DrawText
164  *	  ausgefuehrt (objektiv langsam, subjektiv schnell).
165  * Da der User in der Regel subjektiv urteilt, wird die 2. Methode
166  * als Default eingestellt.
167  *************************************************************************/
DrawTextLine(const SwRect & rPaint,SwSaveClip & rClip,const sal_Bool bUnderSz)168 void SwTxtPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
169 								 const sal_Bool bUnderSz )
170 {
171 #if OSL_DEBUG_LEVEL > 1
172 //    sal_uInt16 nFntHeight = GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), GetInfo().GetOut() );
173 //    sal_uInt16 nFntAscent = GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), GetInfo().GetOut() );
174 #endif
175 
176     // Adjustierung ggf. nachholen
177 	GetAdjusted();
178     GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() );
179 	GetInfo().ResetSpaceIdx();
180     GetInfo().SetKanaComp( pCurr->GetpKanaComp() );
181     GetInfo().ResetKanaIdx();
182 	// Die Groesse des Frames
183 	GetInfo().SetIdx( GetStart() );
184 	GetInfo().SetPos( GetTopLeft() );
185 
186 	const sal_Bool bDrawInWindow = GetInfo().OnWin();
187 
188 	// 6882: Leerzeilen duerfen nicht wegoptimiert werden bei Paragraphzeichen.
189 	const sal_Bool bEndPor = GetInfo().GetOpt().IsParagraph() && !GetInfo().GetTxt().Len();
190 
191 	SwLinePortion *pPor = bEndPor ? pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
192 
193 	// Optimierung!
194 	const SwTwips nMaxRight = Min( rPaint.Right(), Right() );
195 	const SwTwips nTmpLeft = GetInfo().X();
196 	if( !bEndPor && nTmpLeft >= nMaxRight )
197 		return;
198 
199 	// DropCaps!
200 	// 7538: natuerlich auch auf dem Drucker
201 	if( !bPaintDrop )
202 	{
203 		// 8084: Optimierung, weniger Painten.
204 		// AMA: Durch 8084 wurde 7538 wiederbelebt!
205 		// bDrawInWindow entfernt, damit DropCaps auch gedruckt werden
206 		bPaintDrop = pPor == pCurr->GetFirstPortion()
207 					 && GetDropLines() >= GetLineNr();
208 	}
209 
210 	KSHORT nTmpHeight, nTmpAscent;
211 	CalcAscentAndHeight( nTmpAscent, nTmpHeight );
212 
213 	// bClip entscheidet darueber, ob geclippt werden muss.
214 	// Das Ganze muss vor der Retusche stehen
215 
216 	sal_Bool bClip = ( bDrawInWindow || bUnderSz ) && !rClip.IsChg();
217 	if( bClip && pPor )
218 	{
219 		// Wenn TopLeft oder BottomLeft der Line ausserhalb liegen,
220 		// muss geclippt werden. Die Ueberpruefung auf Right() erfolgt
221 		// in der folgenden Ausgabeschleife...
222 
223 		if( GetInfo().GetPos().X() < rPaint.Left() ||
224 			GetInfo().GetPos().Y() < rPaint.Top() ||
225 			GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
226 		{
227 			bClip = sal_False;
228             rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
229 		}
230 #if OSL_DEBUG_LEVEL > 1
231 		static sal_Bool bClipAlways = sal_False;
232 		if( bClip && bClipAlways )
233 		{	bClip = sal_False;
234 			rClip.ChgClip( rPaint );
235 		}
236 #endif
237 	}
238 
239 	// Alignment:
240 	sal_Bool bPlus = sal_False;
241     OutputDevice* pOut = GetInfo().GetOut();
242 	Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
243 	if ( aPnt1.X() < rPaint.Left() )
244 		aPnt1.X() = rPaint.Left();
245 	if ( aPnt1.Y() < rPaint.Top() )
246 		aPnt1.Y() = rPaint.Top();
247 	Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
248 				 GetInfo().GetPos().Y() + nTmpHeight );
249 	if ( aPnt2.X() > rPaint.Right() )
250 		aPnt2.X() = rPaint.Right();
251 	if ( aPnt2.Y() > rPaint.Bottom() )
252 	{
253 		aPnt2.Y() = rPaint.Bottom();
254 		bPlus = sal_True;
255 	}
256 
257 	const SwRect aLineRect( aPnt1, aPnt2 );
258 
259 	if( pCurr->IsClipping() )
260 	{
261         rClip.ChgClip( aLineRect, pFrm );
262 		bClip = sal_False;
263 	}
264 
265 	if( !pPor && !bEndPor )
266 	{
267 #ifdef DBGTXT
268 		aDbstream << "PAINTER: done nothing" << endl;
269 #endif
270 		return;
271 	}
272 
273 	// Baseline-Ausgabe auch bei nicht-TxtPortions (vgl. TabPor mit Fill)
274     // if no special vertical alignment is used,
275     // we calculate Y value for the whole line
276     GETGRID( GetTxtFrm()->FindPageFrm() )
277     const sal_Bool bAdjustBaseLine =
278         GetLineInfo().HasSpecialAlign( GetTxtFrm()->IsVertical() ) ||
279         ( 0 != pGrid );
280     const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
281     if ( ! bAdjustBaseLine )
282         GetInfo().Y( nLineBaseLine );
283 
284 	// 7529: PostIts prepainten
285 	if( GetInfo().OnWin() && pPor && !pPor->Width() )
286 	{
287 		SeekAndChg( GetInfo() );
288 
289         if( bAdjustBaseLine )
290         {
291             const SwTwips nOldY = GetInfo().Y();
292 
293             GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *pCurr, 0,
294                 GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
295                 GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
296             ) );
297 
298             pPor->PrePaint( GetInfo(), pPor );
299             GetInfo().Y( nOldY );
300         }
301         else
302             pPor->PrePaint( GetInfo(), pPor );
303 	}
304 
305 	// 7923: EndPortions geben auch Zeichen aus, deswegen den Fnt wechseln!
306 	if( bEndPor )
307 		SeekStartAndChg( GetInfo() );
308 
309 	sal_Bool bRest = pCurr->IsRest();
310 	sal_Bool bFirst = sal_True;
311 
312 	SwArrowPortion *pArrow = NULL;
313     // Reference portion for the paragraph end portion
314     SwLinePortion* pEndTempl = pCurr->GetFirstPortion();
315 
316 	while( pPor )
317 	{
318 		DBG_LOOP;
319 		sal_Bool bSeeked = sal_True;
320 		GetInfo().SetLen( pPor->GetLen() );
321 
322         const SwTwips nOldY = GetInfo().Y();
323 
324         if ( bAdjustBaseLine )
325         {
326             GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *pCurr, pPor ) );
327 
328             // we store the last portion, because a possible paragraph
329             // end character has the same font as this portion
330             // (only in special vertical alignment case, otherwise the first
331             // portion of the line is used)
332             if ( pPor->Width() && pPor->InTxtGrp() )
333                 pEndTempl = pPor;
334         }
335 
336 		// Ein Sonderfall sind GluePortions, die Blanks ausgeben.
337 
338 		// 6168: Der Rest einer FldPortion zog sich die Attribute der naechsten
339 		// Portion an, dies wird durch SeekAndChgBefore vermieden:
340 		if( ( bRest && pPor->InFldGrp() && !pPor->GetLen() ) )
341 			SeekAndChgBefore( GetInfo() );
342 		else if ( pPor->IsQuoVadisPortion() )
343 		{
344 			xub_StrLen nOffset = GetInfo().GetIdx();
345 			SeekStartAndChg( GetInfo(), sal_True );
346 			if( GetRedln() && pCurr->HasRedline() )
347 				GetRedln()->Seek( *pFnt, nOffset, 0 );
348 		}
349 		else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
350 			SeekAndChg( GetInfo() );
351 		else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
352 		{
353 			// Paragraphzeichen sollten den gleichen Font wie das Zeichen vor
354 			// haben, es sei denn, es gibt Redlining in dem Absatz.
355 			if( GetRedln() )
356 				SeekAndChg( GetInfo() );
357 			else
358 				SeekAndChgBefore( GetInfo() );
359 		}
360 		else
361 			bSeeked = sal_False;
362 
363 //		bRest = sal_False;
364 
365 		// Wenn das Ende der Portion hinausragt, wird geclippt.
366 		// Es wird ein Sicherheitsabstand von Height-Halbe aufaddiert,
367 		// damit die TTF-"f" nicht im Seitenrand haengen...
368         if( bClip &&
369             GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
370         {
371             bClip = sal_False;
372             rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
373 		}
374 
375 		// Portions, die "unter" dem Text liegen wie PostIts
376 		SwLinePortion *pNext = pPor->GetPortion();
377         if( GetInfo().OnWin() && pNext && !pNext->Width() )
378 		{
379 			// Fix 11289: Felder waren hier ausgeklammert wg. Last!=Owner beim
380 			// Laden von Brief.sdw. Jetzt sind die Felder wieder zugelassen,
381 			// durch bSeeked wird Last!=Owner vermieden.
382 			if ( !bSeeked )
383 				SeekAndChg( GetInfo() );
384             pNext->PrePaint( GetInfo(), pPor );
385 		}
386 
387         // We calculate a separate font for underlining.
388         CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
389         SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
390         if ( pUnderLineFnt )
391         {
392             const Point aTmpPoint( GetInfo().X(),
393                                    bAdjustBaseLine ?
394                                    pUnderLineFnt->GetPos().Y() :
395                                    nLineBaseLine );
396             pUnderLineFnt->SetPos( aTmpPoint );
397         }
398 
399 
400         // in extended input mode we do not want a common underline font.
401         SwUnderlineFont* pOldUnderLineFnt = 0;
402         if ( GetRedln() && GetRedln()->ExtOn() )
403         {
404             pOldUnderLineFnt = GetInfo().GetUnderFnt();
405             GetInfo().SetUnderFnt( 0 );
406         }
407 
408         {
409             // --> FME 2004-06-24 #i16816# tagged pdf support
410             Por_Info aPorInfo( *pPor, *this );
411             SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, &aPorInfo, *pOut );
412             // <--
413 
414             if( pPor->IsMultiPortion() )
415                 PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor );
416             else
417                 pPor->Paint( GetInfo() );
418         }
419 
420         // reset underline font
421         if ( pOldUnderLineFnt )
422             GetInfo().SetUnderFnt( pOldUnderLineFnt );
423 
424         // reset (for special vertical alignment)
425         GetInfo().Y( nOldY );
426 
427         if( GetFnt()->IsURL() && pPor->InTxtGrp() )
428 			GetInfo().NotifyURL( *pPor );
429 
430 		bFirst &= !pPor->GetLen();
431 		if( pNext || !pPor->IsMarginPortion() )
432 			pPor->Move( GetInfo() );
433 		if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
434 			pArrow = (SwArrowPortion*)pPor;
435 
436         pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
437                // --> FME 2004-06-24 #i16816# tagged pdf support
438                ( GetInfo().GetVsh() &&
439                  GetInfo().GetVsh()->GetViewOptions()->IsPDFExport() &&
440                  pNext && pNext->IsHolePortion() ) ?
441                // <--
442                pNext :
443                0;
444 	}
445 
446     // delete underline font
447     delete GetInfo().GetUnderFnt();
448     GetInfo().SetUnderFnt( 0 );
449 
450     // paint remaining stuff
451 	if( bDrawInWindow )
452 	{
453         // If special vertical alignment is enabled, GetInfo().Y() is the
454         // top of the current line. Therefore is has to be adjusted for
455         // the painting of the remaining stuff. We first store the old value.
456         const SwTwips nOldY = GetInfo().Y();
457 
458         if( !GetNextLine() &&
459 			GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() &&
460 			GetInfo().GetOpt().IsParagraph() &&	!GetTxtFrm()->GetFollow() &&
461 			GetInfo().GetIdx() >= GetInfo().GetTxt().Len() )
462 		{
463             const SwTmpEndPortion aEnd( *pEndTempl );
464             GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
465 
466             if ( bAdjustBaseLine )
467                 GetInfo().Y( GetInfo().GetPos().Y()
468                            + AdjustBaseLine( *pCurr, &aEnd ) );
469 
470             aEnd.Paint( GetInfo() );
471             GetInfo().Y( nOldY );
472         }
473         if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() )
474         {
475             const sal_Bool bNextUndersized =
476                 ( GetTxtFrm()->GetNext() &&
477                   0 == GetTxtFrm()->GetNext()->Prt().Height() &&
478                   GetTxtFrm()->GetNext()->IsTxtFrm() &&
479                   ((SwTxtFrm*)GetTxtFrm()->GetNext())->IsUndersized() ) ;
480 
481             if( bUnderSz || bNextUndersized )
482 			{
483                 if ( bAdjustBaseLine )
484                     GetInfo().Y( GetInfo().GetPos().Y() + pCurr->GetAscent() );
485 
486                 if( pArrow )
487                     GetInfo().DrawRedArrow( *pArrow );
488 
489                 // GetInfo().Y() must be current baseline.
490                 SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTxtFrm()->Frm().Bottom();
491                 if( ( nDiff > 0 &&
492                       ( GetEnd() < GetInfo().GetTxt().Len() ||
493                         ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
494                     (nDiff >= 0 && bNextUndersized) )
495 
496                 {
497                     SwArrowPortion aArrow( GetInfo() );
498                     GetInfo().DrawRedArrow( aArrow );
499                 }
500 
501                 GetInfo().Y( nOldY );
502 			}
503 		}
504 	}
505 
506     if( pCurr->IsClipping() )
507         rClip.ChgClip( rPaint, pFrm );
508 }
509 
CheckSpecialUnderline(const SwLinePortion * pPor,long nAdjustBaseLine)510 void SwTxtPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
511                                           long nAdjustBaseLine )
512 {
513     // Check if common underline should not be continued.
514     if ( IsUnderlineBreak( *pPor, *pFnt ) )
515     {
516         // delete underline font
517         delete GetInfo().GetUnderFnt();
518         GetInfo().SetUnderFnt( 0 );
519         return;
520     }
521 
522     // If current underline matches the common underline font, we continue
523     // to use the common underline font.
524 	//Bug 120769:Color of underline display wrongly
525 		Color aAutoCo(COL_AUTO);
526     if ( GetInfo().GetUnderFnt() &&
527 		GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
528         GetInfo().GetFont() && GetInfo().GetFont()->GetUnderColor() != aAutoCo )
529 		return;
530 	//Bug 120769(End)
531     // calculate the new common underline font
532     SwFont* pUnderlineFnt = 0;
533     Point aCommonBaseLine;
534 
535     Range aRange( 0, GetInfo().GetTxt().Len() );
536     MultiSelection aUnderMulti( aRange );
537 
538     ASSERT( GetFnt() && UNDERLINE_NONE != GetFnt()->GetUnderline(),
539             "CheckSpecialUnderline without underlined font" )
540     const SwFont* pParaFnt = GetAttrHandler().GetFont();
541     if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
542         aUnderMulti.SelectAll();
543 
544     SwTxtAttr* pTxtAttr;
545     if( HasHints() )
546 	{
547         sal_Bool bUnder = sal_False;
548 		MSHORT nTmp = 0;
549 
550         while( nTmp < pHints->GetStartCount() )
551 		{
552 			pTxtAttr = pHints->GetStart( nTmp++ );
553             sal_Bool bUnderSelect = sal_False;
554 
555             const SvxUnderlineItem* pItem =
556                     static_cast<const SvxUnderlineItem*>(CharFmt::GetItem( *pTxtAttr, RES_CHRATR_UNDERLINE ));
557 
558             if ( pItem )
559             {
560                 bUnder = sal_True;
561                 bUnderSelect = pFnt->GetUnderline() == pItem->GetLineStyle();
562             }
563 
564             if( bUnder )
565 			{
566 				xub_StrLen nSt = *pTxtAttr->GetStart();
567 				xub_StrLen nEnd = *pTxtAttr->GetEnd();
568 				if( nEnd > nSt )
569 				{
570 					Range aTmp( nSt, nEnd - 1 );
571 					if( bUnder )
572 						aUnderMulti.Select( aTmp, bUnderSelect );
573 				}
574 				bUnder = sal_False;
575 			}
576 		}
577     }
578 
579     MSHORT i;
580     xub_StrLen nIndx = GetInfo().GetIdx();
581     long nUnderStart = 0;
582     long nUnderEnd = 0;
583     MSHORT nCnt = (MSHORT)aUnderMulti.GetRangeCount();
584 
585     // find the underline range the current portion is contained in
586     for( i = 0; i < nCnt; ++i )
587     {
588         const Range& rRange = aUnderMulti.GetRange( i );
589         if( nUnderEnd == rRange.Min() )
590             nUnderEnd = rRange.Max();
591         else if( nIndx >= rRange.Min() )
592         {
593             nUnderStart = rRange.Min();
594             nUnderEnd = rRange.Max();
595         }
596         else
597             break;
598     }
599 
600     // restrict start and end to current line
601     if ( GetStart() > nUnderStart )
602         nUnderStart = GetStart();
603 
604     if ( GetEnd() && GetEnd() <= nUnderEnd )
605         nUnderEnd = GetEnd() - 1;
606 
607 
608     // check, if underlining is not isolated
609     if ( nIndx + GetInfo().GetLen() < nUnderEnd + 1 )
610     {
611         //
612         // here starts the algorithm for calculating the underline font
613         //
614         SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
615         SwAttrIter aIter( *(SwTxtNode*)GetInfo().GetTxtFrm()->GetTxtNode(),
616                           rScriptInfo );
617 
618         xub_StrLen nTmpIdx = nIndx;
619         sal_uLong nSumWidth = 0;
620         sal_uLong nSumHeight = 0;
621         sal_uLong nBold = 0;
622         sal_uInt16 nMaxBaseLineOfst = 0;
623         sal_uInt16 nNumberOfPortions = 0;
624 
625         while( nTmpIdx <= nUnderEnd && pPor )
626         {
627             if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
628                 pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
629                 pPor->IsHolePortion() ||
630                 ( pPor->IsMultiPortion() && ! ((SwMultiPortion*)pPor)->IsBidi() ) )
631                 break;
632 
633             aIter.Seek( nTmpIdx );
634 
635             if ( aIter.GetFnt()->GetEscapement() < 0 || pFnt->IsWordLineMode() ||
636                  SVX_CASEMAP_KAPITAELCHEN == pFnt->GetCaseMap() )
637                 break;
638 
639             if ( !aIter.GetFnt()->GetEscapement() )
640             {
641                 nSumWidth += pPor->Width();
642                 const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();
643 
644                 // If we do not have a common baseline we take the baseline
645                 // and the font of the lowest portion.
646                 if ( nAdjustBaseLine )
647                 {
648                     sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *pCurr, pPor );
649                     if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
650                     {
651                         nMaxBaseLineOfst = nTmpBaseLineOfst;
652                         nSumHeight = nFontHeight;
653                     }
654                 }
655                 // in horizontal layout we build a weighted sum of the heights
656                 else
657                     nSumHeight += pPor->Width() * nFontHeight;
658 
659                 if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
660                     nBold += pPor->Width();
661             }
662 
663             ++nNumberOfPortions;
664 
665             nTmpIdx = nTmpIdx + pPor->GetLen();
666             pPor = pPor->GetPortion();
667         }
668 
669         // resulting height
670         if ( nNumberOfPortions > 1 && nSumWidth )
671         {
672             const sal_uLong nNewFontHeight = nAdjustBaseLine ?
673                                          nSumHeight :
674                                          nSumHeight / nSumWidth;
675 
676             pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
677 
678             // font height
679             const sal_uInt8 nActual = pUnderlineFnt->GetActual();
680             pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
681                                           nNewFontHeight ), nActual );
682 
683             // font weight
684             if ( 2 * nBold > nSumWidth )
685                 pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
686             else
687                 pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
688 
689             // common base line
690             aCommonBaseLine.Y() = nAdjustBaseLine + nMaxBaseLineOfst;
691         }
692     }
693 
694     // an escaped redlined portion should also have a special underlining
695     if( ! pUnderlineFnt && pFnt->GetEscapement() > 0 && GetRedln() &&
696         GetRedln()->ChkSpecialUnderline() )
697         pUnderlineFnt = new SwFont( *pFnt );
698 
699     delete GetInfo().GetUnderFnt();
700 
701     if ( pUnderlineFnt )
702     {
703         pUnderlineFnt->SetProportion( 100 );
704         pUnderlineFnt->SetEscapement( 0 );
705         pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
706         pUnderlineFnt->SetOverline( UNDERLINE_NONE );
707         const Color aFillColor( COL_TRANSPARENT );
708         pUnderlineFnt->SetFillColor( aFillColor );
709 
710         GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt,
711                                                      aCommonBaseLine ) );
712     }
713     else
714         // I'm sorry, we do not have a special underlining font for you.
715         GetInfo().SetUnderFnt( 0 );
716 }
717