Update ooo320-m1
[ooovba.git] / sw / source / core / text / itrpaint.cxx
blob550b8fb291e2f9b85877198b192fb8a1b5e52a9b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: itrpaint.cxx,v $
10 * $Revision: 1.47.210.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include "hintids.hxx"
36 #include "flyfrm.hxx" // SwFlyInCntFrm
37 #include "viewopt.hxx" // SwViewOptions
38 #include "errhdl.hxx"
39 #include "txtatr.hxx" // SwINetFmt
40 #include <tools/multisel.hxx>
41 #include <svx/escpitem.hxx>
42 #include <svx/udlnitem.hxx>
43 #include <svx/lrspitem.hxx>
44 #include <txtinet.hxx>
45 #include <fchrfmt.hxx>
46 #include <frmatr.hxx>
47 #include <sfx2/printer.hxx>
48 #include <fmtftn.hxx>
49 #include <fmtfld.hxx>
50 #include <fldbas.hxx> // SwField
51 #include <rootfrm.hxx>
52 #include <pagefrm.hxx>
53 #include <pagedesc.hxx> // SwPageDesc
54 #include <tgrditem.hxx>
56 // --> FME 2004-06-08 #i12836# enhanced pdf export
57 #include <EnhancedPDFExportHelper.hxx>
58 // <--
61 #include "flyfrms.hxx"
62 #include "viewsh.hxx"
63 #include "txtcfg.hxx"
64 #include "itrpaint.hxx"
65 #include "txtfrm.hxx" // pFrm
66 #include "txtfly.hxx"
67 #include "swfont.hxx"
68 #include "txtpaint.hxx"
69 #include "portab.hxx" // SwTabPortion::IsFilled
70 #include "porfly.hxx" // SwFlyCntPortion
71 #include "porfld.hxx" // SwGrfNumPortion
72 #include "frmfmt.hxx" // LRSpace
73 #include "txatbase.hxx" // SwTxtAttr
74 #include "charfmt.hxx" // SwFmtCharFmt
75 #include "redlnitr.hxx" // SwRedlineItr
76 #include "porrst.hxx" // SwArrowPortion
77 #include "pormulti.hxx"
79 /*************************************************************************
80 * IsUnderlineBreak
82 * Returns, if we have an underline breaking situation
83 * Adding some more conditions here means you also have to change them
84 * in SwTxtPainter::CheckSpecialUnderline
85 *************************************************************************/
86 sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
88 return UNDERLINE_NONE == rFnt.GetUnderline() ||
89 rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
90 rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
91 rPor.IsHolePortion() ||
92 ( rPor.IsMultiPortion() && ! ((SwMultiPortion&)rPor).IsBidi() ) ||
93 rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
94 SVX_CASEMAP_KAPITAELCHEN == rFnt.GetCaseMap();
97 /*************************************************************************
98 * SwTxtPainter::CtorInitTxtPainter()
99 *************************************************************************/
100 void SwTxtPainter::CtorInitTxtPainter( SwTxtFrm *pNewFrm, SwTxtPaintInfo *pNewInf )
102 CtorInitTxtCursor( pNewFrm, pNewInf );
103 pInf = pNewInf;
104 SwFont *pMyFnt = GetFnt();
105 GetInfo().SetFont( pMyFnt );
106 #ifndef PRODUCT
107 if( ALIGN_BASELINE != pMyFnt->GetAlign() )
109 ASSERT( ALIGN_BASELINE == pMyFnt->GetAlign(),
110 "+SwTxtPainter::CTOR: font alignment revolution" );
111 pMyFnt->SetAlign( ALIGN_BASELINE );
113 #endif
114 bPaintDrop = sal_False;
118 /*************************************************************************
119 * SwTxtPainter::CalcPaintOfst()
120 *************************************************************************/
121 SwLinePortion *SwTxtPainter::CalcPaintOfst( const SwRect &rPaint )
123 SwLinePortion *pPor = pCurr->GetFirstPortion();
124 GetInfo().SetPaintOfst( 0 );
125 SwTwips nPaintOfst = rPaint.Left();
127 // nPaintOfst wurde exakt auf das Ende eingestellt, deswegen <=
128 // nPaintOfst ist dokumentglobal, deswegen nLeftMar aufaddieren
129 // const KSHORT nLeftMar = KSHORT(GetLeftMargin());
130 // 8310: painten von LineBreaks in leeren Zeilen.
131 if( nPaintOfst && pCurr->Width() )
133 SwLinePortion *pLast = 0;
134 // 7529 und 4757: nicht <= nPaintOfst
135 while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
136 < nPaintOfst )
138 DBG_LOOP;
139 if( pPor->InSpaceGrp() && GetInfo().GetSpaceAdd() )
141 long nTmp = GetInfo().X() +pPor->Width() +
142 pPor->CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
143 if( nTmp + (pPor->Height()/2) >= nPaintOfst )
144 break;
145 GetInfo().X( nTmp );
146 GetInfo().SetIdx( GetInfo().GetIdx() + pPor->GetLen() );
148 else
149 pPor->Move( GetInfo() );
150 pLast = pPor;
151 pPor = pPor->GetPortion();
154 // 7529: bei PostIts auch pLast returnen.
155 if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
157 pPor = pLast;
158 GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
161 return pPor;
164 /*************************************************************************
165 * SwTxtPainter::DrawTextLine()
167 * Es gibt zwei Moeglichkeiten bei transparenten Font auszugeben:
168 * 1) DrawRect auf die ganze Zeile und die DrawText hinterher
169 * (objektiv schnell, subjektiv langsam).
170 * 2) Fuer jede Portion ein DrawRect mit anschliessendem DrawText
171 * ausgefuehrt (objektiv langsam, subjektiv schnell).
172 * Da der User in der Regel subjektiv urteilt, wird die 2. Methode
173 * als Default eingestellt.
174 *************************************************************************/
175 void SwTxtPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
176 const sal_Bool bUnderSz )
178 #if OSL_DEBUG_LEVEL > 1
179 // USHORT nFntHeight = GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), GetInfo().GetOut() );
180 // USHORT nFntAscent = GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), GetInfo().GetOut() );
181 #endif
183 // Adjustierung ggf. nachholen
184 GetAdjusted();
185 GetInfo().SetpSpaceAdd( pCurr->GetpLLSpaceAdd() );
186 GetInfo().ResetSpaceIdx();
187 GetInfo().SetKanaComp( pCurr->GetpKanaComp() );
188 GetInfo().ResetKanaIdx();
189 // Die Groesse des Frames
190 GetInfo().SetIdx( GetStart() );
191 GetInfo().SetPos( GetTopLeft() );
193 const sal_Bool bDrawInWindow = GetInfo().OnWin();
195 // 6882: Leerzeilen duerfen nicht wegoptimiert werden bei Paragraphzeichen.
196 const sal_Bool bEndPor = GetInfo().GetOpt().IsParagraph() && !GetInfo().GetTxt().Len();
198 SwLinePortion *pPor = bEndPor ? pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
200 // Optimierung!
201 const SwTwips nMaxRight = Min( rPaint.Right(), Right() );
202 const SwTwips nTmpLeft = GetInfo().X();
203 if( !bEndPor && nTmpLeft >= nMaxRight )
204 return;
206 // DropCaps!
207 // 7538: natuerlich auch auf dem Drucker
208 if( !bPaintDrop )
210 // 8084: Optimierung, weniger Painten.
211 // AMA: Durch 8084 wurde 7538 wiederbelebt!
212 // bDrawInWindow entfernt, damit DropCaps auch gedruckt werden
213 bPaintDrop = pPor == pCurr->GetFirstPortion()
214 && GetDropLines() >= GetLineNr();
217 KSHORT nTmpHeight, nTmpAscent;
218 CalcAscentAndHeight( nTmpAscent, nTmpHeight );
220 // bClip entscheidet darueber, ob geclippt werden muss.
221 // Das Ganze muss vor der Retusche stehen
223 sal_Bool bClip = ( bDrawInWindow || bUnderSz ) && !rClip.IsChg();
224 if( bClip && pPor )
226 // Wenn TopLeft oder BottomLeft der Line ausserhalb liegen,
227 // muss geclippt werden. Die Ueberpruefung auf Right() erfolgt
228 // in der folgenden Ausgabeschleife...
230 if( GetInfo().GetPos().X() < rPaint.Left() ||
231 GetInfo().GetPos().Y() < rPaint.Top() ||
232 GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
234 bClip = sal_False;
235 rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
237 #if OSL_DEBUG_LEVEL > 1
238 static sal_Bool bClipAlways = sal_False;
239 if( bClip && bClipAlways )
240 { bClip = sal_False;
241 rClip.ChgClip( rPaint );
243 #endif
246 // Alignment:
247 sal_Bool bPlus = sal_False;
248 OutputDevice* pOut = GetInfo().GetOut();
249 Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
250 if ( aPnt1.X() < rPaint.Left() )
251 aPnt1.X() = rPaint.Left();
252 if ( aPnt1.Y() < rPaint.Top() )
253 aPnt1.Y() = rPaint.Top();
254 Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
255 GetInfo().GetPos().Y() + nTmpHeight );
256 if ( aPnt2.X() > rPaint.Right() )
257 aPnt2.X() = rPaint.Right();
258 if ( aPnt2.Y() > rPaint.Bottom() )
260 aPnt2.Y() = rPaint.Bottom();
261 bPlus = sal_True;
264 const SwRect aLineRect( aPnt1, aPnt2 );
266 if( pCurr->IsClipping() )
268 rClip.ChgClip( aLineRect, pFrm );
269 bClip = sal_False;
272 if( !pPor && !bEndPor )
274 #ifdef DBGTXT
275 aDbstream << "PAINTER: done nothing" << endl;
276 #endif
277 return;
280 // Baseline-Ausgabe auch bei nicht-TxtPortions (vgl. TabPor mit Fill)
281 // if no special vertical alignment is used,
282 // we calculate Y value for the whole line
283 GETGRID( GetTxtFrm()->FindPageFrm() )
284 const sal_Bool bAdjustBaseLine =
285 GetLineInfo().HasSpecialAlign( GetTxtFrm()->IsVertical() ) ||
286 ( 0 != pGrid );
287 const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
288 if ( ! bAdjustBaseLine )
289 GetInfo().Y( nLineBaseLine );
291 // 7529: PostIts prepainten
292 if( GetInfo().OnWin() && pPor && !pPor->Width() )
294 SeekAndChg( GetInfo() );
296 if( bAdjustBaseLine )
298 const SwTwips nOldY = GetInfo().Y();
300 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *pCurr, 0,
301 GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
302 GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
303 ) );
305 pPor->PrePaint( GetInfo(), pPor );
306 GetInfo().Y( nOldY );
308 else
309 pPor->PrePaint( GetInfo(), pPor );
312 // 7923: EndPortions geben auch Zeichen aus, deswegen den Fnt wechseln!
313 if( bEndPor )
314 SeekStartAndChg( GetInfo() );
316 sal_Bool bRest = pCurr->IsRest();
317 sal_Bool bFirst = sal_True;
319 SwArrowPortion *pArrow = NULL;
320 // Reference portion for the paragraph end portion
321 SwLinePortion* pEndTempl = pCurr->GetFirstPortion();
323 while( pPor )
325 DBG_LOOP;
326 sal_Bool bSeeked = sal_True;
327 GetInfo().SetLen( pPor->GetLen() );
329 const SwTwips nOldY = GetInfo().Y();
331 if ( bAdjustBaseLine )
333 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *pCurr, pPor ) );
335 // we store the last portion, because a possible paragraph
336 // end character has the same font as this portion
337 // (only in special vertical alignment case, otherwise the first
338 // portion of the line is used)
339 if ( pPor->Width() && pPor->InTxtGrp() )
340 pEndTempl = pPor;
343 // Ein Sonderfall sind GluePortions, die Blanks ausgeben.
345 // 6168: Der Rest einer FldPortion zog sich die Attribute der naechsten
346 // Portion an, dies wird durch SeekAndChgBefore vermieden:
347 if( ( bRest && pPor->InFldGrp() && !pPor->GetLen() ) )
348 SeekAndChgBefore( GetInfo() );
349 else if ( pPor->IsQuoVadisPortion() )
351 xub_StrLen nOffset = GetInfo().GetIdx();
352 SeekStartAndChg( GetInfo(), sal_True );
353 if( GetRedln() && pCurr->HasRedline() )
354 GetRedln()->Seek( *pFnt, nOffset, 0 );
356 else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
357 SeekAndChg( GetInfo() );
358 else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
360 // Paragraphzeichen sollten den gleichen Font wie das Zeichen vor
361 // haben, es sei denn, es gibt Redlining in dem Absatz.
362 if( GetRedln() )
363 SeekAndChg( GetInfo() );
364 else
365 SeekAndChgBefore( GetInfo() );
367 else
368 bSeeked = sal_False;
370 // bRest = sal_False;
372 // Wenn das Ende der Portion hinausragt, wird geclippt.
373 // Es wird ein Sicherheitsabstand von Height-Halbe aufaddiert,
374 // damit die TTF-"f" nicht im Seitenrand haengen...
375 if( bClip &&
376 GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
378 bClip = sal_False;
379 rClip.ChgClip( rPaint, pFrm, pCurr->HasUnderscore() );
382 // Portions, die "unter" dem Text liegen wie PostIts
383 SwLinePortion *pNext = pPor->GetPortion();
384 if( GetInfo().OnWin() && pNext && !pNext->Width() )
386 // Fix 11289: Felder waren hier ausgeklammert wg. Last!=Owner beim
387 // Laden von Brief.sdw. Jetzt sind die Felder wieder zugelassen,
388 // durch bSeeked wird Last!=Owner vermieden.
389 if ( !bSeeked )
390 SeekAndChg( GetInfo() );
391 pNext->PrePaint( GetInfo(), pPor );
394 // We calculate a separate font for underlining.
395 CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
396 SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
397 if ( pUnderLineFnt )
399 const Point aTmpPoint( GetInfo().X(),
400 bAdjustBaseLine ?
401 pUnderLineFnt->GetPos().Y() :
402 nLineBaseLine );
403 pUnderLineFnt->SetPos( aTmpPoint );
407 // in extended input mode we do not want a common underline font.
408 SwUnderlineFont* pOldUnderLineFnt = 0;
409 if ( GetRedln() && GetRedln()->ExtOn() )
411 pOldUnderLineFnt = GetInfo().GetUnderFnt();
412 GetInfo().SetUnderFnt( 0 );
416 // --> FME 2004-06-24 #i16816# tagged pdf support
417 Por_Info aPorInfo( *pPor, *this );
418 SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, &aPorInfo, *pOut );
419 // <--
421 if( pPor->IsMultiPortion() )
422 PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor );
423 else
424 pPor->Paint( GetInfo() );
427 // reset underline font
428 if ( pOldUnderLineFnt )
429 GetInfo().SetUnderFnt( pOldUnderLineFnt );
431 // reset (for special vertical alignment)
432 GetInfo().Y( nOldY );
434 if( GetFnt()->IsURL() && pPor->InTxtGrp() )
435 GetInfo().NotifyURL( *pPor );
437 bFirst &= !pPor->GetLen();
438 if( pNext || !pPor->IsMarginPortion() )
439 pPor->Move( GetInfo() );
440 if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
441 pArrow = (SwArrowPortion*)pPor;
443 pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
444 // --> FME 2004-06-24 #i16816# tagged pdf support
445 ( GetInfo().GetVsh() &&
446 GetInfo().GetVsh()->GetViewOptions()->IsPDFExport() &&
447 pNext && pNext->IsHolePortion() ) ?
448 // <--
449 pNext :
453 // delete underline font
454 delete GetInfo().GetUnderFnt();
455 GetInfo().SetUnderFnt( 0 );
457 // paint remaining stuff
458 if( bDrawInWindow )
460 // If special vertical alignment is enabled, GetInfo().Y() is the
461 // top of the current line. Therefore is has to be adjusted for
462 // the painting of the remaining stuff. We first store the old value.
463 const SwTwips nOldY = GetInfo().Y();
465 if( !GetNextLine() &&
466 GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() &&
467 GetInfo().GetOpt().IsParagraph() && !GetTxtFrm()->GetFollow() &&
468 GetInfo().GetIdx() >= GetInfo().GetTxt().Len() )
470 const SwTmpEndPortion aEnd( *pEndTempl );
471 GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
473 if ( bAdjustBaseLine )
474 GetInfo().Y( GetInfo().GetPos().Y()
475 + AdjustBaseLine( *pCurr, &aEnd ) );
477 aEnd.Paint( GetInfo() );
478 GetInfo().Y( nOldY );
480 if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreView() )
482 const sal_Bool bNextUndersized =
483 ( GetTxtFrm()->GetNext() &&
484 0 == GetTxtFrm()->GetNext()->Prt().Height() &&
485 GetTxtFrm()->GetNext()->IsTxtFrm() &&
486 ((SwTxtFrm*)GetTxtFrm()->GetNext())->IsUndersized() ) ;
488 if( bUnderSz || bNextUndersized )
490 if ( bAdjustBaseLine )
491 GetInfo().Y( GetInfo().GetPos().Y() + pCurr->GetAscent() );
493 if( pArrow )
494 GetInfo().DrawRedArrow( *pArrow );
496 // GetInfo().Y() must be current baseline.
497 SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTxtFrm()->Frm().Bottom();
498 if( ( nDiff > 0 &&
499 ( GetEnd() < GetInfo().GetTxt().Len() ||
500 ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
501 nDiff >= 0 && bNextUndersized )
504 SwArrowPortion aArrow( GetInfo() );
505 GetInfo().DrawRedArrow( aArrow );
508 GetInfo().Y( nOldY );
513 if( pCurr->IsClipping() )
514 rClip.ChgClip( rPaint, pFrm );
517 void SwTxtPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
518 long nAdjustBaseLine )
520 // Check if common underline should not be continued.
521 if ( IsUnderlineBreak( *pPor, *pFnt ) )
523 // delete underline font
524 delete GetInfo().GetUnderFnt();
525 GetInfo().SetUnderFnt( 0 );
526 return;
529 // If current underline matches the common underline font, we continue
530 // to use the common underline font.
531 if ( GetInfo().GetUnderFnt() &&
532 GetInfo().GetUnderFnt()->GetFont().GetUnderline() ==
533 GetFnt()->GetUnderline() )
534 return;
536 // calculate the new common underline font
537 SwFont* pUnderlineFnt = 0;
538 Point aCommonBaseLine;
540 Range aRange( 0, GetInfo().GetTxt().Len() );
541 MultiSelection aUnderMulti( aRange );
543 ASSERT( GetFnt() && UNDERLINE_NONE != GetFnt()->GetUnderline(),
544 "CheckSpecialUnderline without underlined font" )
545 const SwFont* pParaFnt = GetAttrHandler().GetFont();
546 if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
547 aUnderMulti.SelectAll();
549 SwTxtAttr* pTxtAttr;
550 if( HasHints() )
552 sal_Bool bUnder = sal_False;
553 MSHORT nTmp = 0;
555 while( nTmp < pHints->GetStartCount() )
557 pTxtAttr = pHints->GetStart( nTmp++ );
558 sal_Bool bUnderSelect = sal_False;
560 const SvxUnderlineItem* pItem =
561 static_cast<const SvxUnderlineItem*>(CharFmt::GetItem( *pTxtAttr, RES_CHRATR_UNDERLINE ));
563 if ( pItem )
565 bUnder = sal_True;
566 bUnderSelect = pFnt->GetUnderline() == pItem->GetLineStyle();
569 if( bUnder )
571 xub_StrLen nSt = *pTxtAttr->GetStart();
572 xub_StrLen nEnd = *pTxtAttr->GetEnd();
573 if( nEnd > nSt )
575 Range aTmp( nSt, nEnd - 1 );
576 if( bUnder )
577 aUnderMulti.Select( aTmp, bUnderSelect );
579 bUnder = sal_False;
584 MSHORT i;
585 xub_StrLen nIndx = GetInfo().GetIdx();
586 long nUnderStart = 0;
587 long nUnderEnd = 0;
588 MSHORT nCnt = (MSHORT)aUnderMulti.GetRangeCount();
590 // find the underline range the current portion is contained in
591 for( i = 0; i < nCnt; ++i )
593 const Range& rRange = aUnderMulti.GetRange( i );
594 if( nUnderEnd == rRange.Min() )
595 nUnderEnd = rRange.Max();
596 else if( nIndx >= rRange.Min() )
598 nUnderStart = rRange.Min();
599 nUnderEnd = rRange.Max();
601 else
602 break;
605 // restrict start and end to current line
606 if ( GetStart() > nUnderStart )
607 nUnderStart = GetStart();
609 if ( GetEnd() && GetEnd() <= nUnderEnd )
610 nUnderEnd = GetEnd() - 1;
613 // check, if underlining is not isolated
614 if ( nIndx + GetInfo().GetLen() < nUnderEnd + 1 )
617 // here starts the algorithm for calculating the underline font
619 SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
620 SwAttrIter aIter( *(SwTxtNode*)GetInfo().GetTxtFrm()->GetTxtNode(),
621 rScriptInfo );
623 xub_StrLen nTmpIdx = nIndx;
624 ULONG nSumWidth = 0;
625 ULONG nSumHeight = 0;
626 ULONG nBold = 0;
627 USHORT nMaxBaseLineOfst = 0;
628 USHORT nNumberOfPortions = 0;
630 while( nTmpIdx <= nUnderEnd && pPor )
632 if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
633 pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
634 pPor->IsHolePortion() ||
635 ( pPor->IsMultiPortion() && ! ((SwMultiPortion*)pPor)->IsBidi() ) )
636 break;
638 aIter.Seek( nTmpIdx );
640 if ( aIter.GetFnt()->GetEscapement() < 0 || pFnt->IsWordLineMode() ||
641 SVX_CASEMAP_KAPITAELCHEN == pFnt->GetCaseMap() )
642 break;
644 if ( !aIter.GetFnt()->GetEscapement() )
646 nSumWidth += pPor->Width();
647 const ULONG nFontHeight = aIter.GetFnt()->GetHeight();
649 // If we do not have a common baseline we take the baseline
650 // and the font of the lowest portion.
651 if ( nAdjustBaseLine )
653 USHORT nTmpBaseLineOfst = AdjustBaseLine( *pCurr, pPor );
654 if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
656 nMaxBaseLineOfst = nTmpBaseLineOfst;
657 nSumHeight = nFontHeight;
660 // in horizontal layout we build a weighted sum of the heights
661 else
662 nSumHeight += pPor->Width() * nFontHeight;
664 if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
665 nBold += pPor->Width();
668 ++nNumberOfPortions;
670 nTmpIdx = nTmpIdx + pPor->GetLen();
671 pPor = pPor->GetPortion();
674 // resulting height
675 if ( nNumberOfPortions > 1 && nSumWidth )
677 const ULONG nNewFontHeight = nAdjustBaseLine ?
678 nSumHeight :
679 nSumHeight / nSumWidth;
681 pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
683 // font height
684 const BYTE nActual = pUnderlineFnt->GetActual();
685 pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
686 nNewFontHeight ), nActual );
688 // font weight
689 if ( 2 * nBold > nSumWidth )
690 pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
691 else
692 pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
694 // common base line
695 aCommonBaseLine.Y() = nAdjustBaseLine + nMaxBaseLineOfst;
699 // an escaped redlined portion should also have a special underlining
700 if( ! pUnderlineFnt && pFnt->GetEscapement() > 0 && GetRedln() &&
701 GetRedln()->ChkSpecialUnderline() )
702 pUnderlineFnt = new SwFont( *pFnt );
704 delete GetInfo().GetUnderFnt();
706 if ( pUnderlineFnt )
708 pUnderlineFnt->SetProportion( 100 );
709 pUnderlineFnt->SetEscapement( 0 );
710 pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
711 pUnderlineFnt->SetOverline( UNDERLINE_NONE );
712 const Color aFillColor( COL_TRANSPARENT );
713 pUnderlineFnt->SetFillColor( aFillColor );
715 GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt,
716 aCommonBaseLine ) );
718 else
719 // I'm sorry, we do not have a special underlining font for you.
720 GetInfo().SetUnderFnt( 0 );