1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <hintids.hxx> 21 #include <flyfrm.hxx> 22 #include <viewopt.hxx> 23 #include <txtatr.hxx> 24 #include <tools/multisel.hxx> 25 #include <editeng/escapementitem.hxx> 26 #include <editeng/udlnitem.hxx> 27 #include <editeng/lrspitem.hxx> 28 #include <txtinet.hxx> 29 #include <fchrfmt.hxx> 30 #include <frmatr.hxx> 31 #include <sfx2/printer.hxx> 32 #include <fmtfld.hxx> 33 #include <fldbas.hxx> 34 #include <rootfrm.hxx> 35 #include <pagefrm.hxx> 36 #include <pagedesc.hxx> 37 #include <tgrditem.hxx> 38 39 #include <EnhancedPDFExportHelper.hxx> 40 #include <IDocumentSettingAccess.hxx> 41 42 #include <flyfrms.hxx> 43 #include <viewsh.hxx> 44 #include "itrpaint.hxx" 45 #include <txtfrm.hxx> 46 #include <txtfly.hxx> 47 #include <swfont.hxx> 48 #include "txtpaint.hxx" 49 #include "portab.hxx" 50 #include "porfly.hxx" 51 #include "porfld.hxx" 52 #include <frmfmt.hxx> 53 #include <txatbase.hxx> 54 #include <charfmt.hxx> 55 #include "redlnitr.hxx" 56 #include "porrst.hxx" 57 #include "pormulti.hxx" 58 59 // Returns, if we have an underline breaking situation 60 // Adding some more conditions here means you also have to change them 61 // in SwTextPainter::CheckSpecialUnderline 62 bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt ) 63 { 64 return LINESTYLE_NONE == rFnt.GetUnderline() || 65 rPor.IsFlyPortion() || rPor.IsFlyCntPortion() || 66 rPor.IsBreakPortion() || rPor.IsMarginPortion() || 67 rPor.IsHolePortion() || 68 ( rPor.IsMultiPortion() && ! static_cast<const SwMultiPortion&>(rPor).IsBidi() ) || 69 rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() || 70 SvxCaseMap::SmallCaps == rFnt.GetCaseMap(); 71 } 72 73 const Color GetUnderColor( const SwFont *pFont ) 74 { 75 return pFont->GetUnderColor() == Color( COL_AUTO ) ? 76 pFont->GetColor() : pFont->GetUnderColor(); 77 } 78 79 void SwTextPainter::CtorInitTextPainter( SwTextFrame *pNewFrame, SwTextPaintInfo *pNewInf ) 80 { 81 CtorInitTextCursor( pNewFrame, pNewInf ); 82 m_pInf = pNewInf; 83 SwFont *pMyFnt = GetFnt(); 84 GetInfo().SetFont( pMyFnt ); 85 bPaintDrop = false; 86 } 87 88 SwLinePortion *SwTextPainter::CalcPaintOfst( const SwRect &rPaint ) 89 { 90 SwLinePortion *pPor = m_pCurr->GetFirstPortion(); 91 GetInfo().SetPaintOfst( 0 ); 92 SwTwips nPaintOfst = rPaint.Left(); 93 94 // nPaintOfst was exactly set to the end, therefore <= 95 // nPaintOfst is document global, therefore add up nLeftMar 96 // const sal_uInt16 nLeftMar = sal_uInt16(GetLeftMargin()); 97 // 8310: paint of LineBreaks in empty lines. 98 if( nPaintOfst && m_pCurr->Width() ) 99 { 100 SwLinePortion *pLast = nullptr; 101 // 7529 and 4757: not <= nPaintOfst 102 while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2) 103 < nPaintOfst ) 104 { 105 if( pPor->InSpaceGrp() && GetInfo().GetSpaceAdd() ) 106 { 107 long nTmp = GetInfo().X() +pPor->Width() + 108 pPor->CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() ); 109 if( nTmp + (pPor->Height()/2) >= nPaintOfst ) 110 break; 111 GetInfo().X( nTmp ); 112 GetInfo().SetIdx( GetInfo().GetIdx() + pPor->GetLen() ); 113 } 114 else 115 pPor->Move( GetInfo() ); 116 pLast = pPor; 117 pPor = pPor->GetPortion(); 118 } 119 120 // 7529: if PostIts return also pLast. 121 if( pLast && !pLast->Width() && pLast->IsPostItsPortion() ) 122 { 123 pPor = pLast; 124 GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() ); 125 } 126 } 127 return pPor; 128 } 129 130 // There are two possibilities to output transparent font: 131 // 1) DrawRect on the whole line and DrawText afterwards 132 // (objectively fast, subjectively slow) 133 // 2) For every portion a DrawRect with subsequent DrawText is done 134 // (objectively slow, subjectively fast) 135 // Since the user usually judges subjectively the second method is set as default. 136 void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip, 137 const bool bUnderSz ) 138 { 139 #if OSL_DEBUG_LEVEL > 1 140 // sal_uInt16 nFntHeight = GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), GetInfo().GetOut() ); 141 // sal_uInt16 nFntAscent = GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), GetInfo().GetOut() ); 142 #endif 143 144 // maybe catch-up adjustment 145 GetAdjusted(); 146 GetInfo().SetpSpaceAdd( m_pCurr->GetpLLSpaceAdd() ); 147 GetInfo().ResetSpaceIdx(); 148 GetInfo().SetKanaComp( m_pCurr->GetpKanaComp() ); 149 GetInfo().ResetKanaIdx(); 150 // The size of the frame 151 GetInfo().SetIdx( GetStart() ); 152 GetInfo().SetPos( GetTopLeft() ); 153 154 const bool bDrawInWindow = GetInfo().OnWin(); 155 156 // 6882: blank lines can't be optimized by removing them if Formatting Marks are shown 157 const bool bEndPor = GetInfo().GetOpt().IsParagraph() && GetInfo().GetText().isEmpty(); 158 159 SwLinePortion *pPor = bEndPor ? m_pCurr->GetFirstPortion() : CalcPaintOfst( rPaint ); 160 161 // Optimization! 162 SwTwips nMaxRight = std::min( rPaint.Right(), Right() ); 163 const SwTwips nTmpLeft = GetInfo().X(); 164 //compatibility setting: allow tabstop text to exceed right margin 165 if( GetInfo().GetTextFrame()->GetTextNode()->getIDocumentSettingAccess()->get(DocumentSettingId::TAB_OVER_MARGIN) ) 166 { 167 SwLinePortion* pPorIter = pPor; 168 while( pPorIter ) 169 { 170 if( pPorIter->InTabGrp() ) 171 { 172 const SwTabPortion* pTabPor = static_cast<SwTabPortion*>(pPorIter); 173 const SwTwips nTabPos = nTmpLeft + pTabPor->GetTabPos(); 174 if( nMaxRight < nTabPos ) 175 { 176 nMaxRight = rPaint.Right(); 177 break; 178 } 179 } 180 pPorIter = pPorIter->GetPortion(); 181 } 182 } 183 if( !bEndPor && nTmpLeft >= nMaxRight ) 184 return; 185 186 // DropCaps! 187 // 7538: of course for the printer, too 188 if( !bPaintDrop ) 189 { 190 // 8084: Optimization, less painting 191 // AMA: By 8084 7538 has been revived 192 // bDrawInWindow removed, so that DropCaps also can be printed 193 bPaintDrop = pPor == m_pCurr->GetFirstPortion() 194 && GetDropLines() >= GetLineNr(); 195 } 196 197 sal_uInt16 nTmpHeight, nTmpAscent; 198 CalcAscentAndHeight( nTmpAscent, nTmpHeight ); 199 200 // bClip decides if there's a need to clip 201 // The whole thing must be done before retouching 202 203 bool bClip = ( bDrawInWindow || bUnderSz ) && !rClip.IsChg(); 204 if( bClip && pPor ) 205 { 206 // If TopLeft or BottomLeft of the line are outside, the we must clip. 207 // The check for Right() is done in the output loop ... 208 209 if( GetInfo().GetPos().X() < rPaint.Left() || 210 GetInfo().GetPos().Y() < rPaint.Top() || 211 GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() ) 212 { 213 bClip = false; 214 rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() ); 215 } 216 #if OSL_DEBUG_LEVEL > 1 217 static bool bClipAlways = false; 218 if( bClip && bClipAlways ) 219 { bClip = false; 220 rClip.ChgClip( rPaint ); 221 } 222 #endif 223 } 224 225 // Alignment 226 OutputDevice* pOut = GetInfo().GetOut(); 227 Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() ); 228 if ( aPnt1.X() < rPaint.Left() ) 229 aPnt1.setX( rPaint.Left() ); 230 if ( aPnt1.Y() < rPaint.Top() ) 231 aPnt1.setY( rPaint.Top() ); 232 Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(), 233 GetInfo().GetPos().Y() + nTmpHeight ); 234 if ( aPnt2.X() > rPaint.Right() ) 235 aPnt2.setX( rPaint.Right() ); 236 if ( aPnt2.Y() > rPaint.Bottom() ) 237 aPnt2.setY( rPaint.Bottom() ); 238 239 const SwRect aLineRect( aPnt1, aPnt2 ); 240 241 if( m_pCurr->IsClipping() ) 242 { 243 rClip.ChgClip( aLineRect, m_pFrame ); 244 bClip = false; 245 } 246 247 if( !pPor && !bEndPor ) 248 return; 249 250 // Baseline output also if non-TextPortion (compare TabPor with Fill) 251 // if no special vertical alignment is used, 252 // we calculate Y value for the whole line 253 SwTextGridItem const*const pGrid(GetGridItem(GetTextFrame()->FindPageFrame())); 254 const bool bAdjustBaseLine = 255 GetLineInfo().HasSpecialAlign( GetTextFrame()->IsVertical() ) || 256 ( nullptr != pGrid ); 257 const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent; 258 if ( ! bAdjustBaseLine ) 259 GetInfo().Y( nLineBaseLine ); 260 261 // 7529: Pre-paint post-its 262 if( GetInfo().OnWin() && pPor && !pPor->Width() ) 263 { 264 SeekAndChg( GetInfo() ); 265 266 if( bAdjustBaseLine ) 267 { 268 const SwTwips nOldY = GetInfo().Y(); 269 270 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, nullptr, 271 GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ), 272 GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut ) 273 ) ); 274 275 pPor->PrePaint( GetInfo(), pPor ); 276 GetInfo().Y( nOldY ); 277 } 278 else 279 pPor->PrePaint( GetInfo(), pPor ); 280 } 281 282 // 7923: EndPortions output chars, too, that's why we change the font 283 if( bEndPor ) 284 SeekStartAndChg( GetInfo() ); 285 286 const bool bRest = m_pCurr->IsRest(); 287 bool bFirst = true; 288 289 SwArrowPortion *pArrow = nullptr; 290 // Reference portion for the paragraph end portion 291 SwLinePortion* pEndTempl = m_pCurr->GetFirstPortion(); 292 293 while( pPor ) 294 { 295 bool bSeeked = true; 296 GetInfo().SetLen( pPor->GetLen() ); 297 298 const SwTwips nOldY = GetInfo().Y(); 299 300 if ( bAdjustBaseLine ) 301 { 302 GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, pPor ) ); 303 304 // we store the last portion, because a possible paragraph 305 // end character has the same font as this portion 306 // (only in special vertical alignment case, otherwise the first 307 // portion of the line is used) 308 if ( pPor->Width() && pPor->InTextGrp() ) 309 pEndTempl = pPor; 310 } 311 312 // A special case are GluePortions which output blanks. 313 314 // 6168: Avoid that the rest of a FieldPortion gets the attributes of the 315 // next portion with SeekAndChgBefore(): 316 if( bRest && pPor->InFieldGrp() && !pPor->GetLen() ) 317 SeekAndChgBefore( GetInfo() ); 318 else if ( pPor->IsQuoVadisPortion() ) 319 { 320 sal_Int32 nOffset = GetInfo().GetIdx(); 321 SeekStartAndChg( GetInfo(), true ); 322 if( GetRedln() && m_pCurr->HasRedline() ) 323 GetRedln()->Seek( *m_pFont, nOffset, 0 ); 324 } 325 else if( pPor->InTextGrp() || pPor->InFieldGrp() || pPor->InTabGrp() ) 326 SeekAndChg( GetInfo() ); 327 else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() ) 328 { 329 // Paragraph symbols should have the same font as the paragraph in front of them, 330 // except for the case that there's redlining in the paragraph 331 if( GetRedln() ) 332 SeekAndChg( GetInfo() ); 333 else 334 SeekAndChgBefore( GetInfo() ); 335 } 336 else 337 bSeeked = false; 338 339 // bRest = false; 340 341 // If the end of the portion juts out, it is clipped. 342 // A safety distance of half the height is added, so that 343 // TTF-"f" isn't overlapping into the page margin. 344 if( bClip && 345 GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight ) 346 { 347 bClip = false; 348 rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() ); 349 } 350 351 // Portions, which lay "below" the text like post-its 352 SwLinePortion *pNext = pPor->GetPortion(); 353 if( GetInfo().OnWin() && pNext && !pNext->Width() ) 354 { 355 // Fix 11289: Fields were omitted here because of Last!=Owner during 356 // loading Brief.sdw. Now the fields are allowed again, 357 // by bSeeked Last!=Owner is being avoided. 358 if ( !bSeeked ) 359 SeekAndChg( GetInfo() ); 360 pNext->PrePaint( GetInfo(), pPor ); 361 } 362 363 // We calculate a separate font for underlining. 364 CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 ); 365 SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt(); 366 if ( pUnderLineFnt ) 367 { 368 const Point aTmpPoint( GetInfo().X(), 369 bAdjustBaseLine ? 370 pUnderLineFnt->GetPos().Y() : 371 nLineBaseLine ); 372 pUnderLineFnt->SetPos( aTmpPoint ); 373 } 374 375 // in extended input mode we do not want a common underline font. 376 SwUnderlineFont* pOldUnderLineFnt = nullptr; 377 if ( GetRedln() && GetRedln()->ExtOn() ) 378 { 379 pOldUnderLineFnt = GetInfo().GetUnderFnt(); 380 GetInfo().SetUnderFnt( nullptr ); 381 } 382 383 { 384 // #i16816# tagged pdf support 385 Por_Info aPorInfo( *pPor, *this ); 386 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, &aPorInfo, *pOut ); 387 388 if( pPor->IsMultiPortion() ) 389 PaintMultiPortion( rPaint, static_cast<SwMultiPortion&>(*pPor) ); 390 else 391 pPor->Paint( GetInfo() ); 392 } 393 394 // reset underline font 395 if ( pOldUnderLineFnt ) 396 GetInfo().SetUnderFnt( pOldUnderLineFnt ); 397 398 // reset (for special vertical alignment) 399 GetInfo().Y( nOldY ); 400 401 bFirst &= !pPor->GetLen(); 402 if( pNext || !pPor->IsMarginPortion() ) 403 pPor->Move( GetInfo() ); 404 if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow ) 405 pArrow = static_cast<SwArrowPortion*>(pPor); 406 407 pPor = bDrawInWindow || GetInfo().X() <= nMaxRight || 408 // #i16816# tagged pdf support 409 ( GetInfo().GetVsh() && 410 GetInfo().GetVsh()->GetViewOptions()->IsPDFExport() && 411 pNext && pNext->IsHolePortion() ) ? 412 pNext : 413 nullptr; 414 } 415 416 // delete underline font 417 delete GetInfo().GetUnderFnt(); 418 GetInfo().SetUnderFnt( nullptr ); 419 420 // paint remaining stuff 421 if( bDrawInWindow ) 422 { 423 // If special vertical alignment is enabled, GetInfo().Y() is the 424 // top of the current line. Therefore is has to be adjusted for 425 // the painting of the remaining stuff. We first store the old value. 426 const SwTwips nOldY = GetInfo().Y(); 427 428 if( !GetNextLine() && 429 GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() && 430 GetInfo().GetOpt().IsParagraph() && !GetTextFrame()->GetFollow() && 431 GetInfo().GetIdx() >= GetInfo().GetText().getLength() ) 432 { 433 const SwTmpEndPortion aEnd( *pEndTempl ); 434 GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut ); 435 436 if ( bAdjustBaseLine ) 437 GetInfo().Y( GetInfo().GetPos().Y() 438 + AdjustBaseLine( *m_pCurr, &aEnd ) ); 439 GetInfo().X( GetInfo().X() + 440 ( GetCurr()->IsHanging() ? GetCurr()->GetHangingMargin() : 0 ) ); 441 aEnd.Paint( GetInfo() ); 442 GetInfo().Y( nOldY ); 443 } 444 if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() ) 445 { 446 const bool bNextUndersized = 447 ( GetTextFrame()->GetNext() && 448 0 == GetTextFrame()->GetNext()->getFramePrintArea().Height() && 449 GetTextFrame()->GetNext()->IsTextFrame() && 450 static_cast<SwTextFrame*>(GetTextFrame()->GetNext())->IsUndersized() ) ; 451 452 if( bUnderSz || bNextUndersized ) 453 { 454 if ( bAdjustBaseLine ) 455 GetInfo().Y( GetInfo().GetPos().Y() + m_pCurr->GetAscent() ); 456 457 if( pArrow ) 458 GetInfo().DrawRedArrow( *pArrow ); 459 460 // GetInfo().Y() must be current baseline 461 SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTextFrame()->getFrameArea().Bottom(); 462 if( ( nDiff > 0 && 463 ( GetEnd() < GetInfo().GetText().getLength() || 464 ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) || 465 (nDiff >= 0 && bNextUndersized) ) 466 467 { 468 SwArrowPortion aArrow( GetInfo() ); 469 GetInfo().DrawRedArrow( aArrow ); 470 } 471 472 GetInfo().Y( nOldY ); 473 } 474 } 475 } 476 477 if( m_pCurr->IsClipping() ) 478 rClip.ChgClip( rPaint, m_pFrame ); 479 } 480 481 void SwTextPainter::CheckSpecialUnderline( const SwLinePortion* pPor, 482 long nAdjustBaseLine ) 483 { 484 // Check if common underline should not be continued 485 if ( IsUnderlineBreak( *pPor, *m_pFont ) ) 486 { 487 // delete underline font 488 delete GetInfo().GetUnderFnt(); 489 GetInfo().SetUnderFnt( nullptr ); 490 return; 491 } 492 // Reuse calculated underline font as much as possible. 493 if ( GetInfo().GetUnderFnt() && GetInfo().GetIdx() + pPor->GetLen() <= GetInfo().GetUnderFnt()->GetEnd() + 1 ) 494 { 495 SwFont &rFont = GetInfo().GetUnderFnt()->GetFont(); 496 const Color aColor = GetUnderColor( GetInfo().GetFont() ); 497 if ( GetUnderColor( &rFont ) != aColor ) 498 rFont.SetColor( aColor ); 499 return; 500 } 501 502 // If current underline matches the common underline font, we continue 503 // to use the common underline font. 504 // Bug 120769:Color of underline display wrongly 505 if ( GetInfo().GetUnderFnt() && 506 GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() && 507 GetInfo().GetFont() && GetInfo().GetFont()->GetUnderColor() != Color(COL_AUTO) ) 508 return; 509 //Bug 120769(End) 510 511 OSL_ENSURE( GetFnt() && LINESTYLE_NONE != GetFnt()->GetUnderline(), 512 "CheckSpecialUnderline without underlined font" ); 513 MultiSelection aUnderMulti( Range( 0, GetInfo().GetText().getLength() ) ); 514 const SwFont* pParaFnt = GetAttrHandler().GetFont(); 515 if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() ) 516 aUnderMulti.SelectAll(); 517 518 if( HasHints() ) 519 { 520 for ( size_t nTmp = 0; nTmp < m_pHints->Count(); ++nTmp ) 521 { 522 SwTextAttr* const pTextAttr = m_pHints->Get( nTmp ); 523 524 const SvxUnderlineItem* pItem = CharFormat::GetItem( *pTextAttr, RES_CHRATR_UNDERLINE ); 525 526 if ( pItem ) 527 { 528 const sal_Int32 nSt = pTextAttr->GetStart(); 529 const sal_Int32 nEnd = *pTextAttr->GetEnd(); 530 if( nEnd > nSt ) 531 { 532 const bool bUnderSelect = m_pFont->GetUnderline() == pItem->GetLineStyle(); 533 aUnderMulti.Select( Range( nSt, nEnd - 1 ), bUnderSelect ); 534 } 535 } 536 } 537 } 538 539 const sal_Int32 nIndx = GetInfo().GetIdx(); 540 long nUnderEnd = 0; 541 const size_t nCnt = aUnderMulti.GetRangeCount(); 542 543 // find the underline range the current portion is contained in 544 for( size_t i = 0; i < nCnt; ++i ) 545 { 546 const Range& rRange = aUnderMulti.GetRange( i ); 547 if( nUnderEnd == rRange.Min() ) 548 nUnderEnd = rRange.Max(); 549 else if( nIndx >= rRange.Min() ) 550 { 551 nUnderEnd = rRange.Max(); 552 } 553 else 554 break; 555 } 556 557 if ( GetEnd() && GetEnd() <= nUnderEnd ) 558 nUnderEnd = GetEnd() - 1; 559 560 // calculate the new common underline font 561 SwFont* pUnderlineFnt = nullptr; 562 Point aCommonBaseLine; 563 564 // check, if underlining is not isolated 565 if ( nIndx + GetInfo().GetLen() < nUnderEnd + 1 ) 566 { 567 // here starts the algorithm for calculating the underline font 568 SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo(); 569 SwAttrIter aIter( *GetInfo().GetTextFrame()->GetTextNode(), 570 rScriptInfo ); 571 572 sal_Int32 nTmpIdx = nIndx; 573 sal_uLong nSumWidth = 0; 574 sal_uLong nSumHeight = 0; 575 sal_uLong nBold = 0; 576 sal_uInt16 nMaxBaseLineOfst = 0; 577 int nNumberOfPortions = 0; 578 579 while( sal::static_int_cast<long>(nTmpIdx) <= nUnderEnd && pPor ) 580 { 581 if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() || 582 pPor->IsBreakPortion() || pPor->IsMarginPortion() || 583 pPor->IsHolePortion() || 584 ( pPor->IsMultiPortion() && ! static_cast<const SwMultiPortion*>(pPor)->IsBidi() ) ) 585 break; 586 587 aIter.Seek( nTmpIdx ); 588 if ( aIter.GetFnt()->GetEscapement() < 0 || m_pFont->IsWordLineMode() || 589 SvxCaseMap::SmallCaps == m_pFont->GetCaseMap() ) 590 break; 591 592 if ( !aIter.GetFnt()->GetEscapement() ) 593 { 594 nSumWidth += pPor->Width(); 595 const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight(); 596 597 // If we do not have a common baseline we take the baseline 598 // and the font of the lowest portion. 599 if ( nAdjustBaseLine ) 600 { 601 const sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *m_pCurr, pPor ); 602 if ( nMaxBaseLineOfst < nTmpBaseLineOfst ) 603 { 604 nMaxBaseLineOfst = nTmpBaseLineOfst; 605 nSumHeight = nFontHeight; 606 } 607 } 608 // in horizontal layout we build a weighted sum of the heights 609 else 610 nSumHeight += pPor->Width() * nFontHeight; 611 612 if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() ) 613 nBold += pPor->Width(); 614 } 615 616 ++nNumberOfPortions; 617 618 nTmpIdx += pPor->GetLen(); 619 pPor = pPor->GetPortion(); 620 } 621 622 // resulting height 623 if ( nNumberOfPortions > 1 && nSumWidth ) 624 { 625 const sal_uLong nNewFontHeight = nAdjustBaseLine ? 626 nSumHeight : 627 nSumHeight / nSumWidth; 628 629 pUnderlineFnt = new SwFont( *GetInfo().GetFont() ); 630 631 // font height 632 const SwFontScript nActual = pUnderlineFnt->GetActual(); 633 pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(), 634 nNewFontHeight ), nActual ); 635 636 // font weight 637 if ( 2 * nBold > nSumWidth ) 638 pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual ); 639 else 640 pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual ); 641 642 // common base line 643 aCommonBaseLine.setY( nAdjustBaseLine + nMaxBaseLineOfst ); 644 } 645 } 646 647 // an escaped redlined portion should also have a special underlining 648 if( ! pUnderlineFnt && m_pFont->GetEscapement() > 0 && GetRedln() && 649 GetRedln()->ChkSpecialUnderline() ) 650 pUnderlineFnt = new SwFont( *m_pFont ); 651 652 delete GetInfo().GetUnderFnt(); 653 654 if ( pUnderlineFnt ) 655 { 656 pUnderlineFnt->SetProportion( 100 ); 657 pUnderlineFnt->SetEscapement( 0 ); 658 pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE ); 659 pUnderlineFnt->SetOverline( LINESTYLE_NONE ); 660 const Color aFillColor( COL_TRANSPARENT ); 661 pUnderlineFnt->SetFillColor( aFillColor ); 662 663 GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt, nUnderEnd, 664 aCommonBaseLine ) ); 665 } 666 else 667 // I'm sorry, we do not have a special underlining font for you. 668 GetInfo().SetUnderFnt( nullptr ); 669 } 670 671 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 672
