summaryrefslogtreecommitdiffstats
path: root/sw/source/core/text/itrpaint.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sw/source/core/text/itrpaint.cxx
parentInitial commit. (diff)
downloadlibreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz
libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/text/itrpaint.cxx')
-rw-r--r--sw/source/core/text/itrpaint.cxx693
1 files changed, 693 insertions, 0 deletions
diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx
new file mode 100644
index 000000000..28eb142d6
--- /dev/null
+++ b/sw/source/core/text/itrpaint.cxx
@@ -0,0 +1,693 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <hintids.hxx>
+#include <viewopt.hxx>
+#include <tools/multisel.hxx>
+#include <editeng/udlnitem.hxx>
+#include <pagefrm.hxx>
+#include <tgrditem.hxx>
+
+#include <EnhancedPDFExportHelper.hxx>
+#include <IDocumentSettingAccess.hxx>
+
+#include <viewsh.hxx>
+#include "itrpaint.hxx"
+#include <txtfrm.hxx>
+#include <swfont.hxx>
+#include "txtpaint.hxx"
+#include "portab.hxx"
+#include <txatbase.hxx>
+#include <charfmt.hxx>
+#include "redlnitr.hxx"
+#include "porrst.hxx"
+#include "pormulti.hxx"
+#include <doc.hxx>
+
+// Returns, if we have an underline breaking situation
+// Adding some more conditions here means you also have to change them
+// in SwTextPainter::CheckSpecialUnderline
+bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
+{
+ return LINESTYLE_NONE == rFnt.GetUnderline() ||
+ rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
+ rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
+ rPor.IsHolePortion() ||
+ ( rPor.IsMultiPortion() && ! static_cast<const SwMultiPortion&>(rPor).IsBidi() ) ||
+ rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
+ SvxCaseMap::SmallCaps == rFnt.GetCaseMap();
+}
+
+static Color GetUnderColor( const SwFont *pFont )
+{
+ return pFont->GetUnderColor() == COL_AUTO ?
+ pFont->GetColor() : pFont->GetUnderColor();
+}
+
+void SwTextPainter::CtorInitTextPainter( SwTextFrame *pNewFrame, SwTextPaintInfo *pNewInf )
+{
+ CtorInitTextCursor( pNewFrame, pNewInf );
+ m_pInf = pNewInf;
+ SwFont *pMyFnt = GetFnt();
+ GetInfo().SetFont( pMyFnt );
+ bPaintDrop = false;
+}
+
+SwLinePortion *SwTextPainter::CalcPaintOfst( const SwRect &rPaint )
+{
+ SwLinePortion *pPor = m_pCurr->GetFirstPortion();
+ GetInfo().SetPaintOfst( 0 );
+ SwTwips nPaintOfst = rPaint.Left();
+
+ // nPaintOfst was exactly set to the end, therefore <=
+ // nPaintOfst is document global, therefore add up nLeftMar
+ // const sal_uInt16 nLeftMar = sal_uInt16(GetLeftMargin());
+ // 8310: paint of LineBreaks in empty lines.
+ if( nPaintOfst && m_pCurr->Width() )
+ {
+ SwLinePortion *pLast = nullptr;
+ // 7529 and 4757: not <= nPaintOfst
+ while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
+ < nPaintOfst )
+ {
+ if( pPor->InSpaceGrp() && GetInfo().GetSpaceAdd() )
+ {
+ long nTmp = GetInfo().X() +pPor->Width() +
+ pPor->CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
+ if( nTmp + (pPor->Height()/2) >= nPaintOfst )
+ break;
+ GetInfo().X( nTmp );
+ GetInfo().SetIdx( GetInfo().GetIdx() + pPor->GetLen() );
+ }
+ else
+ pPor->Move( GetInfo() );
+ pLast = pPor;
+ pPor = pPor->GetNextPortion();
+ }
+
+ // 7529: if PostIts return also pLast.
+ if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
+ {
+ pPor = pLast;
+ GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
+ }
+ }
+ return pPor;
+}
+
+// There are two possibilities to output transparent font:
+// 1) DrawRect on the whole line and DrawText afterwards
+// (objectively fast, subjectively slow)
+// 2) For every portion a DrawRect with subsequent DrawText is done
+// (objectively slow, subjectively fast)
+// Since the user usually judges subjectively the second method is set as default.
+void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
+ const bool bUnderSized )
+{
+#if OSL_DEBUG_LEVEL > 1
+// sal_uInt16 nFntHeight = GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), GetInfo().GetOut() );
+// sal_uInt16 nFntAscent = GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), GetInfo().GetOut() );
+#endif
+
+ // maybe catch-up adjustment
+ GetAdjusted();
+ GetInfo().SetpSpaceAdd( m_pCurr->GetpLLSpaceAdd() );
+ GetInfo().ResetSpaceIdx();
+ GetInfo().SetKanaComp( m_pCurr->GetpKanaComp() );
+ GetInfo().ResetKanaIdx();
+ // The size of the frame
+ GetInfo().SetIdx( GetStart() );
+ GetInfo().SetPos( GetTopLeft() );
+
+ const bool bDrawInWindow = GetInfo().OnWin();
+
+ // 6882: blank lines can't be optimized by removing them if Formatting Marks are shown
+ const bool bEndPor = GetInfo().GetOpt().IsParagraph() && GetInfo().GetText().isEmpty();
+
+ SwLinePortion *pPor = bEndPor ? m_pCurr->GetFirstPortion() : CalcPaintOfst( rPaint );
+
+ // Optimization!
+ SwTwips nMaxRight = std::min( rPaint.Right(), Right() );
+ const SwTwips nTmpLeft = GetInfo().X();
+ //compatibility setting: allow tabstop text to exceed right margin
+ if (GetInfo().GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_OVER_MARGIN))
+ {
+ SwLinePortion* pPorIter = pPor;
+ while( pPorIter )
+ {
+ if( pPorIter->InTabGrp() )
+ {
+ const SwTabPortion* pTabPor = static_cast<SwTabPortion*>(pPorIter);
+ const SwTwips nTabPos = nTmpLeft + pTabPor->GetTabPos();
+ if( nMaxRight < nTabPos )
+ {
+ nMaxRight = rPaint.Right();
+ break;
+ }
+ }
+ pPorIter = pPorIter->GetNextPortion();
+ }
+ }
+ if( !bEndPor && nTmpLeft >= nMaxRight )
+ return;
+
+ // DropCaps!
+ // 7538: of course for the printer, too
+ if( !bPaintDrop )
+ {
+ // 8084: Optimization, less painting
+ // AMA: By 8084 7538 has been revived
+ // bDrawInWindow removed, so that DropCaps also can be printed
+ bPaintDrop = pPor == m_pCurr->GetFirstPortion()
+ && GetDropLines() >= GetLineNr();
+ }
+
+ sal_uInt16 nTmpHeight, nTmpAscent;
+ CalcAscentAndHeight( nTmpAscent, nTmpHeight );
+
+ // bClip decides if there's a need to clip
+ // The whole thing must be done before retouching
+
+ bool bClip = ( bDrawInWindow || bUnderSized ) && !rClip.IsChg();
+ if( bClip && pPor )
+ {
+ // If TopLeft or BottomLeft of the line are outside, the we must clip.
+ // The check for Right() is done in the output loop ...
+
+ if( GetInfo().GetPos().X() < rPaint.Left() ||
+ GetInfo().GetPos().Y() < rPaint.Top() ||
+ GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
+ {
+ bClip = false;
+ rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ static bool bClipAlways = false;
+ if( bClip && bClipAlways )
+ { bClip = false;
+ rClip.ChgClip( rPaint );
+ }
+#endif
+ }
+
+ // Alignment
+ OutputDevice* pOut = GetInfo().GetOut();
+ Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
+ if ( aPnt1.X() < rPaint.Left() )
+ aPnt1.setX( rPaint.Left() );
+ if ( aPnt1.Y() < rPaint.Top() )
+ aPnt1.setY( rPaint.Top() );
+ Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
+ GetInfo().GetPos().Y() + nTmpHeight );
+ if ( aPnt2.X() > rPaint.Right() )
+ aPnt2.setX( rPaint.Right() );
+ if ( aPnt2.Y() > rPaint.Bottom() )
+ aPnt2.setY( rPaint.Bottom() );
+
+ const SwRect aLineRect( aPnt1, aPnt2 );
+
+ if( m_pCurr->IsClipping() )
+ {
+ const SwTextFrame& rFrame = *GetInfo().GetTextFrame();
+ // tdf#117448 at small fixed line height, enlarge clipping area in table cells
+ // to show previously clipped text content on the area of paragraph margins
+ if ( rFrame.IsInTab() )
+ rClip.ChgClip( aLineRect, m_pFrame, false, rFrame.GetTopMargin(), rFrame.GetBottomMargin() );
+ else
+ rClip.ChgClip( aLineRect, m_pFrame );
+ bClip = false;
+ }
+
+ if( !pPor && !bEndPor )
+ return;
+
+ // Baseline output also if non-TextPortion (compare TabPor with Fill)
+ // if no special vertical alignment is used,
+ // we calculate Y value for the whole line
+ SwTextGridItem const*const pGrid(GetGridItem(GetTextFrame()->FindPageFrame()));
+ const bool bAdjustBaseLine =
+ GetLineInfo().HasSpecialAlign( GetTextFrame()->IsVertical() ) ||
+ ( nullptr != pGrid );
+ const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
+ if ( ! bAdjustBaseLine )
+ GetInfo().Y( nLineBaseLine );
+
+ // 7529: Pre-paint post-its
+ if( GetInfo().OnWin() && pPor && !pPor->Width() )
+ {
+ SeekAndChg( GetInfo() );
+
+ if( bAdjustBaseLine )
+ {
+ const SwTwips nOldY = GetInfo().Y();
+
+ GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, nullptr,
+ GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
+ GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
+ ) );
+
+ pPor->PrePaint( GetInfo(), pPor );
+ GetInfo().Y( nOldY );
+ }
+ else
+ pPor->PrePaint( GetInfo(), pPor );
+ }
+
+ // 7923: EndPortions output chars, too, that's why we change the font
+ if( bEndPor )
+ SeekStartAndChg( GetInfo() );
+
+ const bool bRest = m_pCurr->IsRest();
+ bool bFirst = true;
+
+ SwArrowPortion *pArrow = nullptr;
+ // Reference portion for the paragraph end portion
+ SwLinePortion* pEndTempl = m_pCurr->GetFirstPortion();
+
+ while( pPor )
+ {
+ bool bSeeked = true;
+ GetInfo().SetLen( pPor->GetLen() );
+
+ const SwTwips nOldY = GetInfo().Y();
+
+ if ( bAdjustBaseLine )
+ {
+ GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, pPor ) );
+
+ // we store the last portion, because a possible paragraph
+ // end character has the same font as this portion
+ // (only in special vertical alignment case, otherwise the first
+ // portion of the line is used)
+ if ( pPor->Width() && pPor->InTextGrp() )
+ pEndTempl = pPor;
+ }
+
+ // A special case are GluePortions which output blanks.
+
+ // 6168: Avoid that the rest of a FieldPortion gets the attributes of the
+ // next portion with SeekAndChgBefore():
+ if( bRest && pPor->InFieldGrp() && !pPor->GetLen() )
+ SeekAndChgBefore( GetInfo() );
+ else if ( pPor->IsQuoVadisPortion() )
+ {
+ // A remark on QuoVadis/ErgoSum:
+ // We use the Font set for the Paragraph for these portions.
+ // Thus, we initialize:
+ TextFrameIndex nOffset = GetInfo().GetIdx();
+ SeekStartAndChg( GetInfo(), true );
+ if( GetRedln() && m_pCurr->HasRedline() )
+ {
+ std::pair<SwTextNode const*, sal_Int32> const pos(
+ GetTextFrame()->MapViewToModel(nOffset));
+ GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
+ }
+ }
+ else if( pPor->InTextGrp() || pPor->InFieldGrp() || pPor->InTabGrp() )
+ SeekAndChg( GetInfo() );
+ else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
+ {
+ // Paragraph symbols should have the same font as the paragraph in front of them,
+ // except for the case that there's redlining in the paragraph
+ if( GetRedln() )
+ SeekAndChg( GetInfo() );
+ else
+ SeekAndChgBefore( GetInfo() );
+ }
+ else
+ bSeeked = false;
+
+ // bRest = false;
+
+ // If the end of the portion juts out, it is clipped.
+ // A safety distance of half the height is added, so that
+ // TTF-"f" isn't overlapping into the page margin.
+ if( bClip &&
+ GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
+ {
+ bClip = false;
+ rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() );
+ }
+
+ // Portions, which lay "below" the text like post-its
+ SwLinePortion *pNext = pPor->GetNextPortion();
+ if( GetInfo().OnWin() && pNext && !pNext->Width() )
+ {
+ // Fix 11289: Fields were omitted here because of Last!=Owner during
+ // loading Brief.sdw. Now the fields are allowed again,
+ // by bSeeked Last!=Owner is being avoided.
+ if ( !bSeeked )
+ SeekAndChg( GetInfo() );
+ pNext->PrePaint( GetInfo(), pPor );
+ }
+
+ // We calculate a separate font for underlining.
+ CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
+ SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
+ if ( pUnderLineFnt )
+ {
+ const Point aTmpPoint( GetInfo().X(),
+ bAdjustBaseLine ?
+ pUnderLineFnt->GetPos().Y() :
+ nLineBaseLine );
+ pUnderLineFnt->SetPos( aTmpPoint );
+ }
+
+ // in extended input mode we do not want a common underline font.
+ SwUnderlineFont* pOldUnderLineFnt = nullptr;
+ if ( GetRedln() && GetRedln()->ExtOn() )
+ {
+ pOldUnderLineFnt = GetInfo().GetUnderFnt();
+ GetInfo().SetUnderFnt( nullptr );
+ }
+
+ {
+ // #i16816# tagged pdf support
+ Por_Info aPorInfo( *pPor, *this );
+ SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, &aPorInfo, *pOut );
+
+ if( pPor->IsMultiPortion() )
+ PaintMultiPortion( rPaint, static_cast<SwMultiPortion&>(*pPor) );
+ else
+ pPor->Paint( GetInfo() );
+ }
+
+ // reset underline font
+ if ( pOldUnderLineFnt )
+ GetInfo().SetUnderFnt( pOldUnderLineFnt );
+
+ // reset (for special vertical alignment)
+ GetInfo().Y( nOldY );
+
+ bFirst &= !pPor->GetLen();
+ if( pNext || !pPor->IsMarginPortion() )
+ pPor->Move( GetInfo() );
+ if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
+ pArrow = static_cast<SwArrowPortion*>(pPor);
+
+ pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
+ // #i16816# tagged pdf support
+ ( GetInfo().GetVsh() &&
+ GetInfo().GetVsh()->GetViewOptions()->IsPDFExport() &&
+ pNext && pNext->IsHolePortion() ) ?
+ pNext :
+ nullptr;
+ }
+
+ // delete underline font
+ delete GetInfo().GetUnderFnt();
+ GetInfo().SetUnderFnt( nullptr );
+
+ // paint remaining stuff
+ if( bDrawInWindow )
+ {
+ // If special vertical alignment is enabled, GetInfo().Y() is the
+ // top of the current line. Therefore is has to be adjusted for
+ // the painting of the remaining stuff. We first store the old value.
+ const SwTwips nOldY = GetInfo().Y();
+
+ if( !GetNextLine() &&
+ GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() &&
+ GetInfo().GetOpt().IsParagraph() && !GetTextFrame()->GetFollow() &&
+ GetInfo().GetIdx() >= TextFrameIndex(GetInfo().GetText().getLength()))
+ {
+ const SwTmpEndPortion aEnd( *pEndTempl );
+ GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );
+
+ if ( bAdjustBaseLine )
+ GetInfo().Y( GetInfo().GetPos().Y()
+ + AdjustBaseLine( *m_pCurr, &aEnd ) );
+ GetInfo().X( GetInfo().X() +
+ ( GetCurr()->IsHanging() ? GetCurr()->GetHangingMargin() : 0 ) );
+ aEnd.Paint( GetInfo() );
+ GetInfo().Y( nOldY );
+ }
+ if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() )
+ {
+ const bool bNextUndersized =
+ ( GetTextFrame()->GetNext() &&
+ 0 == GetTextFrame()->GetNext()->getFramePrintArea().Height() &&
+ GetTextFrame()->GetNext()->IsTextFrame() &&
+ static_cast<SwTextFrame*>(GetTextFrame()->GetNext())->IsUndersized() ) ;
+
+ if( bUnderSized || bNextUndersized )
+ {
+ if ( bAdjustBaseLine )
+ GetInfo().Y( GetInfo().GetPos().Y() + m_pCurr->GetAscent() );
+
+ // Left arrow (text overflowing)
+ if( pArrow )
+ GetInfo().DrawRedArrow( *pArrow );
+
+ // GetInfo().Y() must be current baseline
+ SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTextFrame()->getFrameArea().Bottom();
+ if( ( nDiff > 0 &&
+ (GetEnd() < TextFrameIndex(GetInfo().GetText().getLength()) ||
+ ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
+ (nDiff >= 0 && bNextUndersized) )
+
+ {
+ // Right arrow (text overflowing)
+ SwArrowPortion aArrow( GetInfo() );
+ GetInfo().DrawRedArrow( aArrow );
+ }
+
+ GetInfo().Y( nOldY );
+ }
+ }
+ }
+
+ if( m_pCurr->IsClipping() )
+ rClip.ChgClip( rPaint, m_pFrame );
+}
+
+void SwTextPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
+ long nAdjustBaseLine )
+{
+ // Check if common underline should not be continued
+ if ( IsUnderlineBreak( *pPor, *m_pFont ) )
+ {
+ // delete underline font
+ delete GetInfo().GetUnderFnt();
+ GetInfo().SetUnderFnt( nullptr );
+ return;
+ }
+ // Reuse calculated underline font as much as possible.
+ if (GetInfo().GetUnderFnt() &&
+ GetInfo().GetIdx() + pPor->GetLen() <= GetInfo().GetUnderFnt()->GetEnd() + TextFrameIndex(1))
+ {
+ SwFont &rFont = GetInfo().GetUnderFnt()->GetFont();
+ const Color aColor = GetUnderColor( GetInfo().GetFont() );
+ if ( GetUnderColor( &rFont ) != aColor )
+ rFont.SetColor( aColor );
+ return;
+ }
+
+ // If current underline matches the common underline font, we continue
+ // to use the common underline font.
+ // Bug 120769:Color of underline display wrongly
+ if ( GetInfo().GetUnderFnt() &&
+ GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
+ GetInfo().GetFont() && GetInfo().GetFont()->GetUnderColor() != COL_AUTO )
+ return;
+ //Bug 120769(End)
+
+ OSL_ENSURE( GetFnt() && LINESTYLE_NONE != GetFnt()->GetUnderline(),
+ "CheckSpecialUnderline without underlined font" );
+ MultiSelection aUnderMulti( Range( 0, GetInfo().GetText().getLength() ) );
+ const SwFont* pParaFnt = GetAttrHandler().GetFont();
+ if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
+ aUnderMulti.SelectAll();
+
+ if (sw::MergedPara const*const pMerged = GetTextFrame()->GetMergedPara())
+ {
+ // first, add the paragraph properties to MultiSelection - if there are
+ // Hints too, they will override the positions if they're added later
+ sal_Int32 nTmp(0);
+ for (auto const& e : pMerged->extents)
+ {
+ const SfxPoolItem* pItem;
+ if (SfxItemState::SET == e.pNode->GetSwAttrSet().GetItemState(
+ RES_CHRATR_UNDERLINE, true, &pItem))
+ {
+ const bool bUnderSelect(m_pFont->GetUnderline() ==
+ static_cast<SvxUnderlineItem const*>(pItem)->GetLineStyle());
+ aUnderMulti.Select(Range(nTmp, nTmp + e.nEnd - e.nStart - 1),
+ bUnderSelect);
+ }
+ nTmp += e.nEnd - e.nStart;
+ }
+ }
+
+ SwTextNode const* pNode(nullptr);
+ sw::MergedAttrIter iter(*GetTextFrame());
+ for (SwTextAttr const* pTextAttr = iter.NextAttr(&pNode); pTextAttr;
+ pTextAttr = iter.NextAttr(&pNode))
+ {
+ SvxUnderlineItem const*const pItem =
+ CharFormat::GetItem(*pTextAttr, RES_CHRATR_UNDERLINE);
+
+ if (pItem)
+ {
+ TextFrameIndex const nStart(
+ GetTextFrame()->MapModelToView(pNode, pTextAttr->GetStart()));
+ TextFrameIndex const nEnd(
+ GetTextFrame()->MapModelToView(pNode, *pTextAttr->End()));
+ if (nEnd > nStart)
+ {
+ const bool bUnderSelect = m_pFont->GetUnderline() == pItem->GetLineStyle();
+ aUnderMulti.Select(Range(sal_Int32(nStart), sal_Int32(nEnd) - 1),
+ bUnderSelect);
+ }
+ }
+ }
+
+ const TextFrameIndex nIndx = GetInfo().GetIdx();
+ TextFrameIndex nUnderEnd(0);
+ const size_t nCnt = aUnderMulti.GetRangeCount();
+
+ // find the underline range the current portion is contained in
+ for( size_t i = 0; i < nCnt; ++i )
+ {
+ const Range& rRange = aUnderMulti.GetRange( i );
+ if (nUnderEnd == TextFrameIndex(rRange.Min()))
+ nUnderEnd = TextFrameIndex(rRange.Max());
+ else if (nIndx >= TextFrameIndex(rRange.Min()))
+ {
+ nUnderEnd = TextFrameIndex(rRange.Max());
+ }
+ else
+ break;
+ }
+
+ if ( GetEnd() && GetEnd() <= nUnderEnd )
+ nUnderEnd = GetEnd() - TextFrameIndex(1);
+
+ // calculate the new common underline font
+ SwFont* pUnderlineFnt = nullptr;
+ Point aCommonBaseLine;
+
+ // check, if underlining is not isolated
+ if (nIndx + GetInfo().GetLen() < nUnderEnd + TextFrameIndex(1))
+ {
+ // here starts the algorithm for calculating the underline font
+ SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
+ SwAttrIter aIter(*GetInfo().GetTextFrame()->GetTextNodeFirst(),
+ rScriptInfo, GetTextFrame());
+
+ TextFrameIndex nTmpIdx = nIndx;
+ sal_uLong nSumWidth = 0;
+ sal_uLong nSumHeight = 0;
+ sal_uLong nBold = 0;
+ sal_uInt16 nMaxBaseLineOfst = 0;
+ int nNumberOfPortions = 0;
+
+ while (nTmpIdx <= nUnderEnd && pPor)
+ {
+ if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
+ pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
+ pPor->IsHolePortion() ||
+ ( pPor->IsMultiPortion() && ! static_cast<const SwMultiPortion*>(pPor)->IsBidi() ) )
+ break;
+
+ aIter.Seek( nTmpIdx );
+ if ( aIter.GetFnt()->GetEscapement() < 0 || m_pFont->IsWordLineMode() ||
+ SvxCaseMap::SmallCaps == m_pFont->GetCaseMap() )
+ break;
+
+ if ( !aIter.GetFnt()->GetEscapement() )
+ {
+ nSumWidth += pPor->Width();
+ const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();
+
+ // If we do not have a common baseline we take the baseline
+ // and the font of the lowest portion.
+ if ( nAdjustBaseLine )
+ {
+ const sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *m_pCurr, pPor );
+ if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
+ {
+ nMaxBaseLineOfst = nTmpBaseLineOfst;
+ nSumHeight = nFontHeight;
+ }
+ }
+ // in horizontal layout we build a weighted sum of the heights
+ else
+ nSumHeight += pPor->Width() * nFontHeight;
+
+ if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
+ nBold += pPor->Width();
+ }
+
+ ++nNumberOfPortions;
+
+ nTmpIdx += pPor->GetLen();
+ pPor = pPor->GetNextPortion();
+ }
+
+ // resulting height
+ if ( nNumberOfPortions > 1 && nSumWidth )
+ {
+ const sal_uLong nNewFontHeight = nAdjustBaseLine ?
+ nSumHeight :
+ nSumHeight / nSumWidth;
+
+ pUnderlineFnt = new SwFont( *GetInfo().GetFont() );
+
+ // font height
+ const SwFontScript nActual = pUnderlineFnt->GetActual();
+ pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
+ nNewFontHeight ), nActual );
+
+ // font weight
+ if ( 2 * nBold > nSumWidth )
+ pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
+ else
+ pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );
+
+ // common base line
+ aCommonBaseLine.setY( nAdjustBaseLine + nMaxBaseLineOfst );
+ }
+ }
+
+ // an escaped redlined portion should also have a special underlining
+ if( ! pUnderlineFnt && m_pFont->GetEscapement() > 0 && GetRedln() &&
+ GetRedln()->ChkSpecialUnderline() )
+ pUnderlineFnt = new SwFont( *m_pFont );
+
+ delete GetInfo().GetUnderFnt();
+
+ if ( pUnderlineFnt )
+ {
+ pUnderlineFnt->SetProportion( 100 );
+ pUnderlineFnt->SetEscapement( 0 );
+ pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
+ pUnderlineFnt->SetOverline( LINESTYLE_NONE );
+ const Color aFillColor( COL_TRANSPARENT );
+ pUnderlineFnt->SetFillColor( aFillColor );
+
+ GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt, nUnderEnd,
+ aCommonBaseLine ) );
+ }
+ else
+ // I'm sorry, we do not have a special underlining font for you.
+ GetInfo().SetUnderFnt( nullptr );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */