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