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