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