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