summaryrefslogtreecommitdiffstats
path: root/sw/source/core/text/frmpaint.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/frmpaint.cxx')
-rw-r--r--sw/source/core/text/frmpaint.cxx810
1 files changed, 810 insertions, 0 deletions
diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
new file mode 100644
index 0000000000..57458a0218
--- /dev/null
+++ b/sw/source/core/text/frmpaint.cxx
@@ -0,0 +1,810 @@
+/* -*- 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 <memory>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <editeng/pgrditem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <tgrditem.hxx>
+#include <paratr.hxx>
+
+#include <fmtline.hxx>
+#include <lineinfo.hxx>
+#include <charfmt.hxx>
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <viewsh.hxx>
+#include <viewopt.hxx>
+#include <frmatr.hxx>
+#include <txtfrm.hxx>
+#include "itrpaint.hxx"
+#include "txtpaint.hxx"
+#include "txtcache.hxx"
+#include <flyfrm.hxx>
+#include "redlnitr.hxx"
+#include <redline.hxx>
+#include <swmodule.hxx>
+#include <tabfrm.hxx>
+#include <numrule.hxx>
+#include <wrong.hxx>
+
+#include <EnhancedPDFExportHelper.hxx>
+
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentStylePoolAccess.hxx>
+
+#define REDLINE_DISTANCE 567/4
+#define REDLINE_MINDIST 567/10
+
+using namespace ::com::sun::star;
+
+static bool bInitFont = true;
+
+namespace {
+
+class SwExtraPainter
+{
+ SwSaveClip m_aClip;
+ SwRect m_aRect;
+ const SwTextFrame* m_pTextFrame;
+ SwViewShell *m_pSh;
+ std::unique_ptr<SwFont> m_pFnt;
+ const SwLineNumberInfo &m_rLineInf;
+ SwTwips m_nX;
+ SwTwips m_nRedX;
+ sal_Int32 m_nLineNr;
+ sal_uInt16 m_nDivider;
+ bool m_bGoLeft;
+ bool IsClipChg() const { return m_aClip.IsChg(); }
+
+ SwExtraPainter(const SwExtraPainter&) = delete;
+ SwExtraPainter& operator=(const SwExtraPainter&) = delete;
+
+public:
+ SwExtraPainter( const SwTextFrame *pFrame, SwViewShell *pVwSh,
+ const SwLineNumberInfo &rLnInf, const SwRect &rRct,
+ sal_Int16 eHor, bool bLnNm );
+ SwFont* GetFont() const { return m_pFnt.get(); }
+ void IncLineNr() { ++m_nLineNr; }
+ bool HasNumber() const {
+ assert( m_rLineInf.GetCountBy() != 0 );
+ if( m_rLineInf.GetCountBy() == 0 )
+ return false;
+ return !( m_nLineNr % static_cast<sal_Int32>(m_rLineInf.GetCountBy()) );
+ }
+ bool HasDivider() const {
+ assert( m_rLineInf.GetDividerCountBy() != 0 );
+ if( !m_nDivider || m_rLineInf.GetDividerCountBy() == 0 )
+ return false;
+ return !(m_nLineNr % m_rLineInf.GetDividerCountBy());
+ }
+
+ void PaintExtra( SwTwips nY, tools::Long nAsc, tools::Long nMax, bool bRed, const OUString* pRedlineText = nullptr );
+ void PaintRedline( SwTwips nY, tools::Long nMax );
+};
+
+}
+
+SwExtraPainter::SwExtraPainter( const SwTextFrame *pFrame, SwViewShell *pVwSh,
+ const SwLineNumberInfo &rLnInf, const SwRect &rRct,
+ sal_Int16 eHor, bool bLineNum )
+ : m_aClip( pVwSh->GetWin() || pFrame->IsUndersized() ? pVwSh->GetOut() : nullptr )
+ , m_aRect( rRct )
+ , m_pTextFrame( pFrame )
+ , m_pSh( pVwSh )
+ , m_rLineInf( rLnInf )
+ , m_nX(0)
+ , m_nRedX(0)
+ , m_nLineNr( 1 )
+ , m_nDivider(0)
+ , m_bGoLeft(false)
+{
+ if( pFrame->IsUndersized() )
+ {
+ SwTwips nBottom = pFrame->getFrameArea().Bottom();
+ if( m_aRect.Bottom() > nBottom )
+ m_aRect.Bottom( nBottom );
+ }
+ std::optional<bool> oIsRightPage;
+ {
+ /* Initializes the Members necessary for line numbering:
+
+ nDivider, how often do we want a substring; 0 == never
+ nX, line number's x position
+ pFnt, line number's font
+ nLineNr, the first line number
+ bLineNum is set back to false if the numbering is completely
+ outside of the paint rect
+ */
+ m_nDivider = !m_rLineInf.GetDivider().isEmpty() ? m_rLineInf.GetDividerCountBy() : 0;
+ m_nX = pFrame->getFrameArea().Left();
+ SwCharFormat* pFormat = m_rLineInf.GetCharFormat( const_cast<IDocumentStylePoolAccess&>(pFrame->GetDoc().getIDocumentStylePoolAccess()) );
+ OSL_ENSURE( pFormat, "PaintExtraData without CharFormat" );
+ m_pFnt.reset( new SwFont(&pFormat->GetAttrSet(), &pFrame->GetDoc().getIDocumentSettingAccess()) );
+ m_pFnt->Invalidate();
+ m_pFnt->ChgPhysFnt( m_pSh, *m_pSh->GetOut() );
+ m_pFnt->SetVertical( 0_deg10, pFrame->IsVertical() );
+ }
+
+ if( bLineNum )
+ {
+ m_nLineNr += pFrame->GetAllLines() - pFrame->GetThisLines();
+ LineNumberPosition ePos = m_rLineInf.GetPos();
+ if( ePos != LINENUMBER_POS_LEFT && ePos != LINENUMBER_POS_RIGHT )
+ {
+ if( pFrame->FindPageFrame()->OnRightPage() )
+ {
+ oIsRightPage = true;
+ ePos = ePos == LINENUMBER_POS_INSIDE ?
+ LINENUMBER_POS_LEFT : LINENUMBER_POS_RIGHT;
+ }
+ else
+ {
+ oIsRightPage = false;
+ ePos = ePos == LINENUMBER_POS_OUTSIDE ?
+ LINENUMBER_POS_LEFT : LINENUMBER_POS_RIGHT;
+ }
+ }
+ if( LINENUMBER_POS_LEFT == ePos )
+ {
+ m_bGoLeft = true;
+ m_nX -= m_rLineInf.GetPosFromLeft();
+ }
+ else
+ {
+ m_bGoLeft = false;
+ m_nX += pFrame->getFrameArea().Width() + m_rLineInf.GetPosFromLeft();
+ }
+ }
+ if( eHor == text::HoriOrientation::NONE )
+ return;
+
+ if( text::HoriOrientation::INSIDE == eHor || text::HoriOrientation::OUTSIDE == eHor )
+ {
+ if (!oIsRightPage.has_value())
+ oIsRightPage = pFrame->FindPageFrame()->OnRightPage();
+ if (*oIsRightPage)
+ eHor = eHor == text::HoriOrientation::INSIDE ? text::HoriOrientation::LEFT : text::HoriOrientation::RIGHT;
+ else
+ eHor = eHor == text::HoriOrientation::OUTSIDE ? text::HoriOrientation::LEFT : text::HoriOrientation::RIGHT;
+ }
+ const SwFrame* pTmpFrame = pFrame->FindTabFrame();
+ if( !pTmpFrame )
+ pTmpFrame = pFrame;
+ m_nRedX = text::HoriOrientation::LEFT == eHor ? pTmpFrame->getFrameArea().Left() - REDLINE_DISTANCE :
+ pTmpFrame->getFrameArea().Right() + REDLINE_DISTANCE;
+}
+
+void SwExtraPainter::PaintExtra( SwTwips nY, tools::Long nAsc, tools::Long nMax, bool bRed, const OUString* pRedlineText )
+{
+ const OUString aTmp( pRedlineText
+ // Tracked change is stronger than the line number
+ ? *pRedlineText
+ : ( HasNumber()
+ // Line number is stronger than the divider
+ ? m_rLineInf.GetNumType().GetNumStr( m_nLineNr )
+ : m_rLineInf.GetDivider() ) );
+
+ // Get script type of line numbering:
+ m_pFnt->SetActual( SwScriptInfo::WhichFont(0, aTmp) );
+
+ if ( pRedlineText )
+ {
+ m_pFnt->SetColor(NON_PRINTING_CHARACTER_COLOR);
+ // don't strike out text in Insertions In Margin mode
+ if ( !m_pSh->GetViewOptions()->IsShowChangesInMargin2() )
+ m_pFnt->SetStrikeout( STRIKEOUT_SINGLE );
+ m_pFnt->SetSize( Size( 0, 200), m_pFnt->GetActual() );
+ }
+
+ SwDrawTextInfo aDrawInf( m_pSh, *m_pSh->GetOut(), aTmp, 0, aTmp.getLength() );
+ aDrawInf.SetSpace( 0 );
+ aDrawInf.SetWrong( nullptr );
+ aDrawInf.SetGrammarCheck( nullptr );
+ aDrawInf.SetSmartTags( nullptr );
+ aDrawInf.SetFrame( m_pTextFrame );
+ aDrawInf.SetFont( m_pFnt.get() );
+ aDrawInf.SetSnapToGrid( false );
+ aDrawInf.SetIgnoreFrameRTL( true );
+
+ bool bTooBig = m_pFnt->GetSize( m_pFnt->GetActual() ).Height() > nMax &&
+ m_pFnt->GetHeight( m_pSh, *m_pSh->GetOut() ) > nMax;
+ SwFont* pTmpFnt;
+ if( bTooBig )
+ {
+ pTmpFnt = new SwFont( *GetFont() );
+ if( nMax >= 20 )
+ {
+ nMax *= 17;
+ nMax /= 20;
+ }
+ pTmpFnt->SetSize( Size( 0, nMax ), pTmpFnt->GetActual() );
+ }
+ else
+ pTmpFnt = GetFont();
+ Point aTmpPos( m_nX, nY );
+ aTmpPos.AdjustY(nAsc );
+ if ( pRedlineText )
+ {
+ Size aSize = pTmpFnt->GetTextSize_( aDrawInf );
+ aTmpPos.AdjustX( -(aSize.Width()) - 200 );
+ }
+ bool bPaint = true;
+ if( !IsClipChg() )
+ {
+ Size aSize = pTmpFnt->GetTextSize_( aDrawInf );
+ if( m_bGoLeft )
+ aTmpPos.AdjustX( -(aSize.Width()) );
+ // calculate rectangle containing the line number
+ SwRect aRct( Point( aTmpPos.X(),
+ aTmpPos.Y() - pTmpFnt->GetAscent( m_pSh, *m_pSh->GetOut() )
+ ), aSize );
+ if( !m_aRect.Contains( aRct ) )
+ {
+ if( aRct.Intersection( m_aRect ).IsEmpty() )
+ bPaint = false;
+ else
+ m_aClip.ChgClip( m_aRect, m_pTextFrame );
+ }
+ }
+ else if( m_bGoLeft )
+ aTmpPos.AdjustX( -(pTmpFnt->GetTextSize_( aDrawInf ).Width()) );
+ aDrawInf.SetPos( aTmpPos );
+ if( bPaint )
+ pTmpFnt->DrawText_( aDrawInf );
+
+ if( bTooBig )
+ delete pTmpFnt;
+ if( bRed )
+ {
+ tools::Long nDiff = m_bGoLeft ? m_nRedX - m_nX : m_nX - m_nRedX;
+ if( nDiff > REDLINE_MINDIST )
+ PaintRedline( nY, nMax );
+ }
+}
+
+void SwExtraPainter::PaintRedline( SwTwips nY, tools::Long nMax )
+{
+ Point aStart( m_nRedX, nY );
+ Point aEnd( m_nRedX, nY + nMax );
+
+ if( !IsClipChg() )
+ {
+ SwRect aRct( aStart, aEnd );
+ if( !m_aRect.Contains( aRct ) )
+ {
+ if( aRct.Intersection( m_aRect ).IsEmpty() )
+ return;
+ m_aClip.ChgClip( m_aRect, m_pTextFrame );
+ }
+ }
+ const Color aOldCol( m_pSh->GetOut()->GetLineColor() );
+ m_pSh->GetOut()->SetLineColor( SW_MOD()->GetRedlineMarkColor() );
+
+ if ( m_pTextFrame->IsVertical() )
+ {
+ m_pTextFrame->SwitchHorizontalToVertical( aStart );
+ m_pTextFrame->SwitchHorizontalToVertical( aEnd );
+ }
+
+ m_pSh->GetOut()->DrawLine( aStart, aEnd );
+ m_pSh->GetOut()->SetLineColor( aOldCol );
+}
+
+void SwTextFrame::PaintExtraData( const SwRect &rRect ) const
+{
+ if( getFrameArea().Top() > rRect.Bottom() || getFrameArea().Bottom() < rRect.Top() )
+ return;
+
+ PaintOutlineContentVisibilityButton();
+
+ SwDoc const& rDoc(GetDoc());
+ const IDocumentRedlineAccess& rIDRA = rDoc.getIDocumentRedlineAccess();
+ const SwLineNumberInfo &rLineInf = rDoc.GetLineNumberInfo();
+ const SwFormatLineNumber &rLineNum = GetAttrSet()->GetLineNumber();
+ bool bLineNum = !IsInTab() && rLineInf.IsPaintLineNumbers() &&
+ ( !IsInFly() || rLineInf.IsCountInFlys() ) && rLineNum.IsCount();
+ sal_Int16 eHor = static_cast<sal_Int16>(SW_MOD()->GetRedlineMarkPos());
+ if (eHor != text::HoriOrientation::NONE
+ && (!IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
+ || getRootFrame()->IsHideRedlines()))
+ {
+ eHor = text::HoriOrientation::NONE;
+ }
+ bool bRedLine = eHor != text::HoriOrientation::NONE;
+ if ( !bLineNum && !bRedLine )
+ return;
+
+ if( IsLocked() || IsHiddenNow() || !getFramePrintArea().Height() )
+ return;
+ SwViewShell *pSh = getRootFrame()->GetCurrShell();
+
+ SwSwapIfNotSwapped swap(const_cast<SwTextFrame *>(this));
+ SwRect rOldRect( rRect );
+
+ if ( IsVertical() )
+ SwitchVerticalToHorizontal( const_cast<SwRect&>(rRect) );
+
+ SwLayoutModeModifier aLayoutModeModifier( *pSh->GetOut() );
+ aLayoutModeModifier.Modify( false );
+
+ // #i16816# tagged pdf support
+ SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh->GetOut() );
+
+ SwExtraPainter aExtra( this, pSh, rLineInf, rRect, eHor, bLineNum );
+
+ if( HasPara() )
+ {
+ TextFrameLockGuard aLock(const_cast<SwTextFrame*>(this));
+
+ SwTextLineAccess aAccess( this );
+ aAccess.GetPara();
+
+ SwTextPaintInfo aInf( const_cast<SwTextFrame*>(this), rRect );
+
+ aLayoutModeModifier.Modify( false );
+
+ SwTextPainter aLine( const_cast<SwTextFrame*>(this), &aInf );
+ bool bNoDummy = !aLine.GetNext(); // Only one empty line!
+
+ while( aLine.Y() + aLine.GetLineHeight() <= rRect.Top() )
+ {
+ if( !aLine.GetCurr()->IsDummy() &&
+ ( rLineInf.IsCountBlankLines() ||
+ aLine.GetCurr()->HasContent() ) )
+ aExtra.IncLineNr();
+ if( !aLine.Next() )
+ {
+ const_cast<SwRect&>(rRect) = rOldRect;
+ return;
+ }
+ }
+
+ tools::Long nBottom = rRect.Bottom();
+
+ bool bNoPrtLine = 0 == GetMinPrtLine();
+ if( !bNoPrtLine )
+ {
+ while ( aLine.Y() < GetMinPrtLine() )
+ {
+ if( ( rLineInf.IsCountBlankLines() || aLine.GetCurr()->HasContent() )
+ && !aLine.GetCurr()->IsDummy() )
+ aExtra.IncLineNr();
+ if( !aLine.Next() )
+ break;
+ }
+ bNoPrtLine = aLine.Y() >= GetMinPrtLine();
+ }
+ const bool bIsShowChangesInMargin = pSh->GetViewOptions()->IsShowChangesInMargin();
+ if( bNoPrtLine )
+ {
+ do
+ {
+ if( bNoDummy || !aLine.GetCurr()->IsDummy() )
+ {
+ bool bRed = bRedLine && aLine.GetCurr()->HasRedline();
+ if( rLineInf.IsCountBlankLines() || aLine.GetCurr()->HasContent() )
+ {
+ bool bRedInMargin = bIsShowChangesInMargin && bRed;
+ bool bNum = bLineNum && ( aExtra.HasNumber() || aExtra.HasDivider() );
+ if( bRedInMargin || bNum )
+ {
+ SwTwips nTmpHeight, nTmpAscent;
+ aLine.CalcAscentAndHeight( nTmpAscent, nTmpHeight );
+ if ( bRedInMargin )
+ {
+ const OUString* pRedlineText = aLine.GetCurr()->GetRedlineText();
+ if( !pRedlineText->isEmpty() )
+ {
+ aExtra.PaintExtra( aLine.Y(), nTmpAscent,
+ nTmpHeight, bRed, pRedlineText );
+ bRed = false;
+ bNum = false;
+ }
+ }
+ if ( bNum )
+ {
+ aExtra.PaintExtra( aLine.Y(), nTmpAscent, nTmpHeight, bRed );
+ bRed = false;
+ }
+ }
+ aExtra.IncLineNr();
+ }
+ if( bRed )
+ aExtra.PaintRedline( aLine.Y(), aLine.GetLineHeight() );
+ }
+ } while( aLine.Next() && aLine.Y() <= nBottom );
+ }
+ }
+ else
+ {
+ if (SwRedlineTable::npos == rIDRA.GetRedlinePos(*GetTextNodeFirst(), RedlineType::Any))
+ {
+ bRedLine = false;
+ }
+
+ if( bLineNum && rLineInf.IsCountBlankLines() &&
+ ( aExtra.HasNumber() || aExtra.HasDivider() ) )
+ {
+ aExtra.PaintExtra( getFrameArea().Top()+getFramePrintArea().Top(), aExtra.GetFont()
+ ->GetAscent( pSh, *pSh->GetOut() ), getFramePrintArea().Height(), bRedLine );
+ }
+ else if( bRedLine )
+ aExtra.PaintRedline( getFrameArea().Top()+getFramePrintArea().Top(), getFramePrintArea().Height() );
+ }
+
+ const_cast<SwRect&>(rRect) = rOldRect;
+
+}
+
+SwRect SwTextFrame::GetPaintSwRect()
+{
+ // finger layout
+ OSL_ENSURE( isFrameAreaPositionValid(), "+SwTextFrame::GetPaintSwRect: no Calc()" );
+
+ SwRect aRet( getFramePrintArea() );
+ if ( IsEmpty() || !HasPara() )
+ aRet += getFrameArea().Pos();
+ else
+ {
+ // We return the right paint rect. Use the calculated PaintOfst as the
+ // left margin
+ SwRepaint& rRepaint = GetPara()->GetRepaint();
+ tools::Long l;
+
+ if ( IsVertLR() && !IsVertLRBT()) // mba: the following line was added, but we don't need it for the existing directions; kept for IsVertLR(), but should be checked
+ rRepaint.Chg( GetUpper()->getFrameArea().Pos() + GetUpper()->getFramePrintArea().Pos(), GetUpper()->getFramePrintArea().SSize() );
+
+ if( rRepaint.GetOffset() )
+ rRepaint.Left( rRepaint.GetOffset() );
+
+ l = rRepaint.GetRightOfst();
+ if( l && l > rRepaint.Right() )
+ rRepaint.Right( l );
+ rRepaint.SetOffset( 0 );
+ aRet = rRepaint;
+
+ // In case our left edge is the same as the body frame's left edge,
+ // then extend the rectangle to include the page margin as well,
+ // otherwise some font will be clipped.
+ SwLayoutFrame* pBodyFrame = GetUpper();
+ if (pBodyFrame->IsBodyFrame() && aRet.Left() == (pBodyFrame->getFrameArea().Left() + pBodyFrame->getFramePrintArea().Left()))
+ if (SwLayoutFrame* pPageFrame = pBodyFrame->GetUpper())
+ aRet.Left(pPageFrame->getFrameArea().Left());
+
+ if ( IsRightToLeft() )
+ SwitchLTRtoRTL( aRet );
+
+ if ( IsVertical() )
+ SwitchHorizontalToVertical( aRet );
+ }
+ ResetRepaint();
+
+ return aRet;
+}
+
+bool SwTextFrame::PaintEmpty( const SwRect &rRect, bool bCheck ) const
+{
+ PaintParagraphStylesHighlighting();
+
+ SwViewShell *pSh = getRootFrame()->GetCurrShell();
+ if( pSh && ( pSh->GetViewOptions()->IsParagraph() || bInitFont ) )
+ {
+ bInitFont = false;
+ SwTextFly aTextFly( this );
+ aTextFly.SetTopRule();
+ SwRect aRect;
+ if( bCheck && aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) )
+ return false;
+ else if( pSh->GetWin() )
+ {
+ std::unique_ptr<SwFont> pFnt;
+ RedlineType eRedline = RedlineType::None;
+ const SwTextNode& rTextNode = *GetTextNodeForParaProps();
+ if ( rTextNode.HasSwAttrSet() )
+ {
+ const SwAttrSet *pAttrSet = &( rTextNode.GetSwAttrSet() );
+ pFnt.reset(new SwFont( pAttrSet, rTextNode.getIDocumentSettingAccess() ));
+ }
+ else
+ {
+ SwFontAccess aFontAccess( &rTextNode.GetAnyFormatColl(), pSh );
+ pFnt.reset(new SwFont( aFontAccess.Get()->GetFont() ));
+ }
+
+ const IDocumentRedlineAccess& rIDRA = rTextNode.getIDocumentRedlineAccess();
+ if (IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
+ && !getRootFrame()->IsHideRedlines())
+ {
+ const SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, RedlineType::Any );
+ if( SwRedlineTable::npos != nRedlPos )
+ {
+ SwAttrHandler aAttrHandler;
+ aAttrHandler.Init( rTextNode.GetSwAttrSet(),
+ *rTextNode.getIDocumentSettingAccess() );
+ SwRedlineItr aRedln(rTextNode, *pFnt, aAttrHandler, nRedlPos, SwRedlineItr::Mode::Show);
+ const SwRangeRedline* pRedline = rIDRA.GetRedlineTable()[nRedlPos];
+ // show redlining only on the inserted/deleted empty paragraph, but not on the next one
+ if ( rTextNode.GetIndex() != pRedline->End()->GetNodeIndex() )
+ eRedline = pRedline->GetType();
+ // except if the next empty paragraph starts a new redline (e.g. deletion after insertion)
+ else if ( nRedlPos + 1 < rIDRA.GetRedlineTable().size() )
+ {
+ const SwRangeRedline* pNextRedline = rIDRA.GetRedlineTable()[nRedlPos + 1];
+ if ( rTextNode.GetIndex() == pNextRedline->Start()->GetNodeIndex() )
+ eRedline = pNextRedline->GetType();
+ }
+ }
+ }
+
+ if( pSh->GetViewOptions()->IsParagraph() && getFramePrintArea().Height() )
+ {
+ if( RTL_TEXTENCODING_SYMBOL == pFnt->GetCharSet( SwFontScript::Latin ) &&
+ pFnt->GetName( SwFontScript::Latin ) != numfunc::GetDefBulletFontname() )
+ {
+ pFnt->SetFamily( FAMILY_DONTKNOW, SwFontScript::Latin );
+ pFnt->SetName( numfunc::GetDefBulletFontname(), SwFontScript::Latin );
+ pFnt->SetStyleName(OUString(), SwFontScript::Latin);
+ pFnt->SetCharSet( RTL_TEXTENCODING_SYMBOL, SwFontScript::Latin );
+ }
+ pFnt->SetVertical( 0_deg10, IsVertical() );
+ SwFrameSwapper aSwapper( this, true );
+ SwLayoutModeModifier aLayoutModeModifier( *pSh->GetOut() );
+ aLayoutModeModifier.Modify( IsRightToLeft() );
+
+ pFnt->Invalidate();
+ pFnt->ChgPhysFnt( pSh, *pSh->GetOut() );
+ Point aPos = getFrameArea().Pos() + getFramePrintArea().Pos();
+
+ const SvxFirstLineIndentItem& rFirstLine(
+ GetTextNodeForParaProps()->GetSwAttrSet().GetFirstLineIndent());
+
+ if (0 < rFirstLine.GetTextFirstLineOffset())
+ {
+ aPos.AdjustX(rFirstLine.GetTextFirstLineOffset());
+ }
+
+ std::unique_ptr<SwSaveClip, o3tl::default_delete<SwSaveClip>> xClip;
+ if( IsUndersized() )
+ {
+ xClip.reset(new SwSaveClip( pSh->GetOut() ));
+ xClip->ChgClip( rRect );
+ }
+
+ aPos.AdjustY(pFnt->GetAscent( pSh, *pSh->GetOut() ) );
+
+ if (GetTextNodeForParaProps()->GetSwAttrSet().GetParaGrid().GetValue() &&
+ IsInDocBody() )
+ {
+ SwTextGridItem const*const pGrid(GetGridItem(FindPageFrame()));
+ if ( pGrid )
+ {
+ // center character in grid line
+ aPos.AdjustY(( pGrid->GetBaseHeight() -
+ pFnt->GetHeight( pSh, *pSh->GetOut() ) ) / 2 );
+
+ if ( ! pGrid->GetRubyTextBelow() )
+ aPos.AdjustY(pGrid->GetRubyHeight() );
+ }
+ }
+
+ // Don't show the paragraph mark for collapsed paragraphs, when they are hidden
+ // No paragraph marker in the non-last part of a split fly anchor, either.
+ if ( EmptyHeight( ) > 1 && !HasNonLastSplitFlyDrawObj() )
+ {
+ SwDrawTextInfo aDrawInf( pSh, *pSh->GetOut(), CH_PAR, 0, 1 );
+ aDrawInf.SetPos( aPos );
+ aDrawInf.SetSpace( 0 );
+ aDrawInf.SetKanaComp( 0 );
+ aDrawInf.SetWrong( nullptr );
+ aDrawInf.SetGrammarCheck( nullptr );
+ aDrawInf.SetSmartTags( nullptr );
+ aDrawInf.SetFrame( this );
+ aDrawInf.SetFont( pFnt.get() );
+ aDrawInf.SetSnapToGrid( false );
+
+ // show redline color and settings drawing a background pilcrow,
+ // but keep also other formattings (with neutral pilcrow color)
+ if ( eRedline != RedlineType::None )
+ {
+ pFnt->DrawText_( aDrawInf );
+ if ( eRedline == RedlineType::Delete )
+ pFnt->SetStrikeout( STRIKEOUT_NONE );
+ else
+ pFnt->SetUnderline( LINESTYLE_NONE );
+ }
+
+ pFnt->SetColor(NON_PRINTING_CHARACTER_COLOR);
+ pFnt->DrawText_( aDrawInf );
+ }
+ }
+ return true;
+ }
+ }
+ else
+ return true;
+ return false;
+}
+
+void SwTextFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
+{
+ ResetRepaint();
+
+ // #i16816# tagged pdf support
+ SwViewShell *pSh = getRootFrame()->GetCurrShell();
+
+ if( IsEmpty() && PaintEmpty( rRect, true ) )
+ return;
+
+ if( IsLocked() || IsHiddenNow() || ! getFramePrintArea().HasArea() )
+ return;
+
+ // It can happen that the IdleCollector withdrew my cached information
+ if( !HasPara() )
+ {
+ OSL_ENSURE( isFrameAreaPositionValid(), "+SwTextFrame::PaintSwFrame: no Calc()" );
+
+ // #i29062# pass info that we are currently
+ // painting.
+ const_cast<SwTextFrame*>(this)->GetFormatted( true );
+ if( IsEmpty() )
+ {
+ PaintEmpty( rRect, false );
+ return;
+ }
+ if( !HasPara() )
+ {
+ OSL_ENSURE( false, "+SwTextFrame::PaintSwFrame: missing format information" );
+ return;
+ }
+ }
+
+ // tdf140219-2.odt text frame with only fly portions and a follow is not
+ // actually a paragraph - delay creating all structured elements to follow.
+ bool const isPDFTaggingEnabled(!HasFollow() || GetPara()->HasContentPortions());
+ ::std::optional<SwTaggedPDFHelper> oTaggedPDFHelperNumbering;
+ if (isPDFTaggingEnabled)
+ {
+ Num_Info aNumInfo(*this);
+ oTaggedPDFHelperNumbering.emplace(&aNumInfo, nullptr, nullptr, rRenderContext);
+ }
+
+ // Lbl unfortunately must be able to contain multiple numbering portions
+ // that may be on multiple lines of text (but apparently always in the
+ // master frame), so it gets complicated.
+ ::std::optional<SwTaggedPDFHelper> oTaggedLabel;
+ // Paragraph tag - if there is a list label, opening should be delayed.
+ ::std::optional<SwTaggedPDFHelper> oTaggedParagraph;
+
+ if (isPDFTaggingEnabled
+ && (GetTextNodeForParaProps()->IsOutline()
+ || !GetPara()->HasNumberingPortion(SwParaPortion::FootnoteToo)))
+ { // no Lbl needed => open paragraph tag now
+ Frame_Info aFrameInfo(*this, false);
+ oTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, rRenderContext);
+ }
+
+ // We don't want to be interrupted while painting.
+ // Do that after thr Format()!
+ TextFrameLockGuard aLock(const_cast<SwTextFrame*>(this));
+
+ // We only paint the part of the TextFrame which changed, is within the
+ // range and was requested to paint.
+ // One could think that the area rRect _needs_ to be painted, although
+ // rRepaint is set. Indeed, we cannot avoid this problem from a formal
+ // perspective. Luckily we can assume rRepaint to be empty when we need
+ // paint the while Frame.
+ SwTextLineAccess aAccess( this );
+ SwParaPortion *pPara = aAccess.GetPara();
+
+ SwRepaint &rRepaint = pPara->GetRepaint();
+
+ // Switch off recycling when in the FlyContentFrame.
+ // A DrawRect is called for repainting the line anyways.
+ if( rRepaint.GetOffset() )
+ {
+ const SwFlyFrame *pFly = FindFlyFrame();
+ if( pFly && pFly->IsFlyInContentFrame() )
+ rRepaint.SetOffset( 0 );
+ }
+
+ // Ge the String for painting. The length is of special interest.
+
+ // Rectangle
+ OSL_ENSURE( ! IsSwapped(), "A frame is swapped before Paint" );
+ SwRect aOldRect( rRect );
+
+ {
+ SwSwapIfNotSwapped swap(const_cast<SwTextFrame *>(this));
+
+ if ( IsVertical() )
+ SwitchVerticalToHorizontal( const_cast<SwRect&>(rRect) );
+
+ if ( IsRightToLeft() )
+ SwitchRTLtoLTR( const_cast<SwRect&>(rRect) );
+
+ SwTextPaintInfo aInf( const_cast<SwTextFrame*>(this), rRect );
+ sw::WrongListIterator iterWrong(*this, &SwTextNode::GetWrong);
+ sw::WrongListIterator iterGrammar(*this, &SwTextNode::GetGrammarCheck);
+ sw::WrongListIterator iterSmartTags(*this, &SwTextNode::GetSmartTags);
+ if (iterWrong.LooksUseful())
+ {
+ aInf.SetWrongList( &iterWrong );
+ }
+ if (iterGrammar.LooksUseful())
+ {
+ aInf.SetGrammarCheckList( &iterGrammar );
+ }
+ if (iterSmartTags.LooksUseful())
+ {
+ aInf.SetSmartTags( &iterSmartTags );
+ }
+ aInf.GetTextFly().SetTopRule();
+
+ SwTextPainter aLine( const_cast<SwTextFrame*>(this), &aInf );
+ // Optimization: if no free flying Frame overlaps into our line, the
+ // SwTextFly just switches off
+ aInf.GetTextFly().Relax();
+
+ OutputDevice* pOut = aInf.GetOut();
+ const bool bOnWin = pSh->GetWin() != nullptr;
+
+ SwSaveClip aClip( bOnWin || IsUndersized() ? pOut : nullptr );
+
+ // Output loop: For each Line ... (which is still visible) ...
+ // adapt rRect (Top + 1, Bottom - 1)
+ // Because the Iterator attaches the Lines without a gap to each other
+ aLine.TwipsToLine( rRect.Top() + 1 );
+ tools::Long nBottom = rRect.Bottom();
+
+ bool bNoPrtLine = 0 == GetMinPrtLine();
+ if( !bNoPrtLine )
+ {
+ while ( aLine.Y() < GetMinPrtLine() && aLine.Next() )
+ ;
+ bNoPrtLine = aLine.Y() >= GetMinPrtLine();
+ }
+ if( bNoPrtLine )
+ {
+ do
+ {
+ aLine.DrawTextLine(rRect, aClip, IsUndersized(), oTaggedLabel, oTaggedParagraph, isPDFTaggingEnabled);
+
+ } while( aLine.Next() && aLine.Y() <= nBottom );
+ }
+
+ // Once is enough:
+ if( aLine.IsPaintDrop() )
+ aLine.PaintDropPortion();
+
+ if( rRepaint.HasArea() )
+ rRepaint.Clear();
+ }
+
+ PaintParagraphStylesHighlighting();
+
+ const_cast<SwRect&>(rRect) = aOldRect;
+
+ OSL_ENSURE( ! IsSwapped(), "A frame is swapped after Paint" );
+
+ assert(!oTaggedLabel); // must have been closed if opened
+ assert(!isPDFTaggingEnabled || oTaggedParagraph || rRect.GetIntersection(getFrameArea()) != getFrameArea()); // must have been created during complete paint (PDF export is always complete paint)
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */