1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <com/sun/star/text/HoriOrientation.hpp>
22 #include <editeng/pgrditem.hxx>
23 #include <editeng/lrspitem.hxx>
24 #include <tgrditem.hxx>
27 #include <fmtline.hxx>
28 #include <lineinfo.hxx>
29 #include <charfmt.hxx>
30 #include <rootfrm.hxx>
31 #include <pagefrm.hxx>
33 #include <viewopt.hxx>
36 #include "itrpaint.hxx"
37 #include "txtpaint.hxx"
38 #include "txtcache.hxx"
40 #include "redlnitr.hxx"
41 #include <redline.hxx>
42 #include <swmodule.hxx>
44 #include <numrule.hxx>
47 #include <EnhancedPDFExportHelper.hxx>
49 #include <IDocumentRedlineAccess.hxx>
50 #include <IDocumentStylePoolAccess.hxx>
52 #define REDLINE_DISTANCE 567/4
53 #define REDLINE_MINDIST 567/10
55 using namespace ::com::sun::star
;
57 static bool bInitFont
= true;
65 const SwTextFrame
* m_pTextFrame
;
67 std::unique_ptr
<SwFont
> m_pFnt
;
68 const SwLineNumberInfo
&m_rLineInf
;
72 sal_uInt16 m_nDivider
;
74 bool IsClipChg() const { return m_aClip
.IsChg(); }
76 SwExtraPainter(const SwExtraPainter
&) = delete;
77 SwExtraPainter
& operator=(const SwExtraPainter
&) = delete;
80 SwExtraPainter( const SwTextFrame
*pFrame
, SwViewShell
*pVwSh
,
81 const SwLineNumberInfo
&rLnInf
, const SwRect
&rRct
,
82 sal_Int16 eHor
, bool bLnNm
);
83 SwFont
* GetFont() const { return m_pFnt
.get(); }
84 void IncLineNr() { ++m_nLineNr
; }
85 bool HasNumber() const {
86 assert( m_rLineInf
.GetCountBy() != 0 );
87 if( m_rLineInf
.GetCountBy() == 0 )
89 return !( m_nLineNr
% static_cast<sal_Int32
>(m_rLineInf
.GetCountBy()) );
91 bool HasDivider() const {
92 assert( m_rLineInf
.GetDividerCountBy() != 0 );
93 if( !m_nDivider
|| m_rLineInf
.GetDividerCountBy() == 0 )
95 return !(m_nLineNr
% m_rLineInf
.GetDividerCountBy());
98 void PaintExtra( SwTwips nY
, tools::Long nAsc
, tools::Long nMax
, bool bRed
, const OUString
* pRedlineText
= nullptr );
99 void PaintRedline( SwTwips nY
, tools::Long nMax
);
104 SwExtraPainter::SwExtraPainter( const SwTextFrame
*pFrame
, SwViewShell
*pVwSh
,
105 const SwLineNumberInfo
&rLnInf
, const SwRect
&rRct
,
106 sal_Int16 eHor
, bool bLineNum
)
107 : m_aClip( pVwSh
->GetWin() || pFrame
->IsUndersized() ? pVwSh
->GetOut() : nullptr )
109 , m_pTextFrame( pFrame
)
111 , m_rLineInf( rLnInf
)
118 if( pFrame
->IsUndersized() )
120 SwTwips nBottom
= pFrame
->getFrameArea().Bottom();
121 if( m_aRect
.Bottom() > nBottom
)
122 m_aRect
.Bottom( nBottom
);
124 std::optional
<bool> oIsRightPage
;
126 /* Initializes the Members necessary for line numbering:
128 nDivider, how often do we want a substring; 0 == never
129 nX, line number's x position
130 pFnt, line number's font
131 nLineNr, the first line number
132 bLineNum is set back to false if the numbering is completely
133 outside of the paint rect
135 m_nDivider
= !m_rLineInf
.GetDivider().isEmpty() ? m_rLineInf
.GetDividerCountBy() : 0;
136 m_nX
= pFrame
->getFrameArea().Left();
137 SwCharFormat
* pFormat
= m_rLineInf
.GetCharFormat( const_cast<IDocumentStylePoolAccess
&>(pFrame
->GetDoc().getIDocumentStylePoolAccess()) );
138 OSL_ENSURE( pFormat
, "PaintExtraData without CharFormat" );
139 m_pFnt
.reset( new SwFont(&pFormat
->GetAttrSet(), &pFrame
->GetDoc().getIDocumentSettingAccess()) );
140 m_pFnt
->Invalidate();
141 m_pFnt
->ChgPhysFnt( m_pSh
, *m_pSh
->GetOut() );
142 m_pFnt
->SetVertical( 0_deg10
, pFrame
->IsVertical() );
147 m_nLineNr
+= pFrame
->GetAllLines() - pFrame
->GetThisLines();
148 LineNumberPosition ePos
= m_rLineInf
.GetPos();
149 if( ePos
!= LINENUMBER_POS_LEFT
&& ePos
!= LINENUMBER_POS_RIGHT
)
151 if( pFrame
->FindPageFrame()->OnRightPage() )
154 ePos
= ePos
== LINENUMBER_POS_INSIDE
?
155 LINENUMBER_POS_LEFT
: LINENUMBER_POS_RIGHT
;
159 oIsRightPage
= false;
160 ePos
= ePos
== LINENUMBER_POS_OUTSIDE
?
161 LINENUMBER_POS_LEFT
: LINENUMBER_POS_RIGHT
;
164 if( LINENUMBER_POS_LEFT
== ePos
)
167 m_nX
-= m_rLineInf
.GetPosFromLeft();
172 m_nX
+= pFrame
->getFrameArea().Width() + m_rLineInf
.GetPosFromLeft();
175 if( eHor
== text::HoriOrientation::NONE
)
178 if( text::HoriOrientation::INSIDE
== eHor
|| text::HoriOrientation::OUTSIDE
== eHor
)
181 oIsRightPage
= pFrame
->FindPageFrame()->OnRightPage();
183 eHor
= eHor
== text::HoriOrientation::INSIDE
? text::HoriOrientation::LEFT
: text::HoriOrientation::RIGHT
;
185 eHor
= eHor
== text::HoriOrientation::OUTSIDE
? text::HoriOrientation::LEFT
: text::HoriOrientation::RIGHT
;
187 const SwFrame
* pTmpFrame
= pFrame
->FindTabFrame();
190 m_nRedX
= text::HoriOrientation::LEFT
== eHor
? pTmpFrame
->getFrameArea().Left() - REDLINE_DISTANCE
:
191 pTmpFrame
->getFrameArea().Right() + REDLINE_DISTANCE
;
194 void SwExtraPainter::PaintExtra( SwTwips nY
, tools::Long nAsc
, tools::Long nMax
, bool bRed
, const OUString
* pRedlineText
)
196 const OUString
aTmp( pRedlineText
197 // Tracked change is stronger than the line number
200 // Line number is stronger than the divider
201 ? m_rLineInf
.GetNumType().GetNumStr( m_nLineNr
)
202 : m_rLineInf
.GetDivider() ) );
204 // Get script type of line numbering:
205 m_pFnt
->SetActual( SwScriptInfo::WhichFont(0, aTmp
) );
209 m_pFnt
->SetColor(NON_PRINTING_CHARACTER_COLOR
);
210 // don't strike out text in Insertions In Margin mode
211 if ( !m_pSh
->GetViewOptions()->IsShowChangesInMargin2() )
212 m_pFnt
->SetStrikeout( STRIKEOUT_SINGLE
);
213 m_pFnt
->SetSize( Size( 0, 200), m_pFnt
->GetActual() );
216 SwDrawTextInfo
aDrawInf( m_pSh
, *m_pSh
->GetOut(), aTmp
, 0, aTmp
.getLength() );
217 aDrawInf
.SetSpace( 0 );
218 aDrawInf
.SetWrong( nullptr );
219 aDrawInf
.SetGrammarCheck( nullptr );
220 aDrawInf
.SetSmartTags( nullptr );
221 aDrawInf
.SetFrame( m_pTextFrame
);
222 aDrawInf
.SetFont( m_pFnt
.get() );
223 aDrawInf
.SetSnapToGrid( false );
224 aDrawInf
.SetIgnoreFrameRTL( true );
226 bool bTooBig
= m_pFnt
->GetSize( m_pFnt
->GetActual() ).Height() > nMax
&&
227 m_pFnt
->GetHeight( m_pSh
, *m_pSh
->GetOut() ) > nMax
;
231 pTmpFnt
= new SwFont( *GetFont() );
237 pTmpFnt
->SetSize( Size( 0, nMax
), pTmpFnt
->GetActual() );
241 Point
aTmpPos( m_nX
, nY
);
242 aTmpPos
.AdjustY(nAsc
);
245 Size aSize
= pTmpFnt
->GetTextSize_( aDrawInf
);
246 aTmpPos
.AdjustX( -(aSize
.Width()) - 200 );
251 Size aSize
= pTmpFnt
->GetTextSize_( aDrawInf
);
253 aTmpPos
.AdjustX( -(aSize
.Width()) );
254 // calculate rectangle containing the line number
255 SwRect
aRct( Point( aTmpPos
.X(),
256 aTmpPos
.Y() - pTmpFnt
->GetAscent( m_pSh
, *m_pSh
->GetOut() )
258 if( !m_aRect
.Contains( aRct
) )
260 if( aRct
.Intersection( m_aRect
).IsEmpty() )
263 m_aClip
.ChgClip( m_aRect
, m_pTextFrame
);
267 aTmpPos
.AdjustX( -(pTmpFnt
->GetTextSize_( aDrawInf
).Width()) );
268 aDrawInf
.SetPos( aTmpPos
);
270 pTmpFnt
->DrawText_( aDrawInf
);
276 tools::Long nDiff
= m_bGoLeft
? m_nRedX
- m_nX
: m_nX
- m_nRedX
;
277 if( nDiff
> REDLINE_MINDIST
)
278 PaintRedline( nY
, nMax
);
282 void SwExtraPainter::PaintRedline( SwTwips nY
, tools::Long nMax
)
284 Point
aStart( m_nRedX
, nY
);
285 Point
aEnd( m_nRedX
, nY
+ nMax
);
289 SwRect
aRct( aStart
, aEnd
);
290 if( !m_aRect
.Contains( aRct
) )
292 if( aRct
.Intersection( m_aRect
).IsEmpty() )
294 m_aClip
.ChgClip( m_aRect
, m_pTextFrame
);
297 const Color
aOldCol( m_pSh
->GetOut()->GetLineColor() );
298 m_pSh
->GetOut()->SetLineColor( SW_MOD()->GetRedlineMarkColor() );
300 if ( m_pTextFrame
->IsVertical() )
302 m_pTextFrame
->SwitchHorizontalToVertical( aStart
);
303 m_pTextFrame
->SwitchHorizontalToVertical( aEnd
);
306 m_pSh
->GetOut()->DrawLine( aStart
, aEnd
);
307 m_pSh
->GetOut()->SetLineColor( aOldCol
);
310 void SwTextFrame::PaintExtraData( const SwRect
&rRect
) const
312 if( getFrameArea().Top() > rRect
.Bottom() || getFrameArea().Bottom() < rRect
.Top() )
315 PaintOutlineContentVisibilityButton();
317 SwDoc
const& rDoc(GetDoc());
318 const IDocumentRedlineAccess
& rIDRA
= rDoc
.getIDocumentRedlineAccess();
319 const SwLineNumberInfo
&rLineInf
= rDoc
.GetLineNumberInfo();
320 const SwFormatLineNumber
&rLineNum
= GetAttrSet()->GetLineNumber();
321 bool bLineNum
= !IsInTab() && rLineInf
.IsPaintLineNumbers() &&
322 ( !IsInFly() || rLineInf
.IsCountInFlys() ) && rLineNum
.IsCount();
323 sal_Int16 eHor
= static_cast<sal_Int16
>(SW_MOD()->GetRedlineMarkPos());
324 if (eHor
!= text::HoriOrientation::NONE
325 && (!IDocumentRedlineAccess::IsShowChanges(rIDRA
.GetRedlineFlags())
326 || getRootFrame()->IsHideRedlines()))
328 eHor
= text::HoriOrientation::NONE
;
330 bool bRedLine
= eHor
!= text::HoriOrientation::NONE
;
331 if ( !bLineNum
&& !bRedLine
)
334 if( IsLocked() || IsHiddenNow() || !getFramePrintArea().Height() )
336 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
338 SwSwapIfNotSwapped
swap(const_cast<SwTextFrame
*>(this));
339 SwRect
rOldRect( rRect
);
342 SwitchVerticalToHorizontal( const_cast<SwRect
&>(rRect
) );
344 SwLayoutModeModifier
aLayoutModeModifier( *pSh
->GetOut() );
345 aLayoutModeModifier
.Modify( false );
347 // #i16816# tagged pdf support
348 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh
->GetOut() );
350 SwExtraPainter
aExtra( this, pSh
, rLineInf
, rRect
, eHor
, bLineNum
);
354 TextFrameLockGuard
aLock(const_cast<SwTextFrame
*>(this));
356 SwTextLineAccess
aAccess( this );
359 SwTextPaintInfo
aInf( const_cast<SwTextFrame
*>(this), rRect
);
361 aLayoutModeModifier
.Modify( false );
363 SwTextPainter
aLine( const_cast<SwTextFrame
*>(this), &aInf
);
364 bool bNoDummy
= !aLine
.GetNext(); // Only one empty line!
366 while( aLine
.Y() + aLine
.GetLineHeight() <= rRect
.Top() )
368 if( !aLine
.GetCurr()->IsDummy() &&
369 ( rLineInf
.IsCountBlankLines() ||
370 aLine
.GetCurr()->HasContent() ) )
374 const_cast<SwRect
&>(rRect
) = rOldRect
;
379 tools::Long nBottom
= rRect
.Bottom();
381 bool bNoPrtLine
= 0 == GetMinPrtLine();
384 while ( aLine
.Y() < GetMinPrtLine() )
386 if( ( rLineInf
.IsCountBlankLines() || aLine
.GetCurr()->HasContent() )
387 && !aLine
.GetCurr()->IsDummy() )
392 bNoPrtLine
= aLine
.Y() >= GetMinPrtLine();
394 const bool bIsShowChangesInMargin
= pSh
->GetViewOptions()->IsShowChangesInMargin();
399 if( bNoDummy
|| !aLine
.GetCurr()->IsDummy() )
401 bool bRed
= bRedLine
&& aLine
.GetCurr()->HasRedline();
402 if( rLineInf
.IsCountBlankLines() || aLine
.GetCurr()->HasContent() )
404 bool bRedInMargin
= bIsShowChangesInMargin
&& bRed
;
405 bool bNum
= bLineNum
&& ( aExtra
.HasNumber() || aExtra
.HasDivider() );
406 if( bRedInMargin
|| bNum
)
408 SwTwips nTmpHeight
, nTmpAscent
;
409 aLine
.CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
412 const OUString
* pRedlineText
= aLine
.GetCurr()->GetRedlineText();
413 if( !pRedlineText
->isEmpty() )
415 aExtra
.PaintExtra( aLine
.Y(), nTmpAscent
,
416 nTmpHeight
, bRed
, pRedlineText
);
423 aExtra
.PaintExtra( aLine
.Y(), nTmpAscent
, nTmpHeight
, bRed
);
430 aExtra
.PaintRedline( aLine
.Y(), aLine
.GetLineHeight() );
432 } while( aLine
.Next() && aLine
.Y() <= nBottom
);
437 if (SwRedlineTable::npos
== rIDRA
.GetRedlinePos(*GetTextNodeFirst(), RedlineType::Any
))
442 if( bLineNum
&& rLineInf
.IsCountBlankLines() &&
443 ( aExtra
.HasNumber() || aExtra
.HasDivider() ) )
445 aExtra
.PaintExtra( getFrameArea().Top()+getFramePrintArea().Top(), aExtra
.GetFont()
446 ->GetAscent( pSh
, *pSh
->GetOut() ), getFramePrintArea().Height(), bRedLine
);
449 aExtra
.PaintRedline( getFrameArea().Top()+getFramePrintArea().Top(), getFramePrintArea().Height() );
452 const_cast<SwRect
&>(rRect
) = rOldRect
;
456 SwRect
SwTextFrame::GetPaintSwRect()
459 OSL_ENSURE( isFrameAreaPositionValid(), "+SwTextFrame::GetPaintSwRect: no Calc()" );
461 SwRect
aRet( getFramePrintArea() );
462 if ( IsEmpty() || !HasPara() )
463 aRet
+= getFrameArea().Pos();
466 // We return the right paint rect. Use the calculated PaintOfst as the
468 SwRepaint
& rRepaint
= GetPara()->GetRepaint();
471 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
472 rRepaint
.Chg( GetUpper()->getFrameArea().Pos() + GetUpper()->getFramePrintArea().Pos(), GetUpper()->getFramePrintArea().SSize() );
474 if( rRepaint
.GetOffset() )
475 rRepaint
.Left( rRepaint
.GetOffset() );
477 l
= rRepaint
.GetRightOfst();
478 if( l
&& l
> rRepaint
.Right() )
480 rRepaint
.SetOffset( 0 );
483 // In case our left edge is the same as the body frame's left edge,
484 // then extend the rectangle to include the page margin as well,
485 // otherwise some font will be clipped.
486 SwLayoutFrame
* pBodyFrame
= GetUpper();
487 if (pBodyFrame
->IsBodyFrame() && aRet
.Left() == (pBodyFrame
->getFrameArea().Left() + pBodyFrame
->getFramePrintArea().Left()))
488 if (SwLayoutFrame
* pPageFrame
= pBodyFrame
->GetUpper())
489 aRet
.Left(pPageFrame
->getFrameArea().Left());
491 if ( IsRightToLeft() )
492 SwitchLTRtoRTL( aRet
);
495 SwitchHorizontalToVertical( aRet
);
502 bool SwTextFrame::PaintEmpty( const SwRect
&rRect
, bool bCheck
) const
504 PaintParagraphStylesHighlighting();
506 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
507 if( pSh
&& ( pSh
->GetViewOptions()->IsParagraph() || bInitFont
) )
510 SwTextFly
aTextFly( this );
511 aTextFly
.SetTopRule();
513 if( bCheck
&& aTextFly
.IsOn() && aTextFly
.IsAnyObj( aRect
) )
515 else if( pSh
->GetWin() )
517 std::unique_ptr
<SwFont
> pFnt
;
518 RedlineType eRedline
= RedlineType::None
;
519 const SwTextNode
& rTextNode
= *GetTextNodeForParaProps();
520 if ( rTextNode
.HasSwAttrSet() )
522 const SwAttrSet
*pAttrSet
= &( rTextNode
.GetSwAttrSet() );
523 pFnt
.reset(new SwFont( pAttrSet
, rTextNode
.getIDocumentSettingAccess() ));
527 SwFontAccess
aFontAccess( &rTextNode
.GetAnyFormatColl(), pSh
);
528 pFnt
.reset(new SwFont( aFontAccess
.Get()->GetFont() ));
531 const IDocumentRedlineAccess
& rIDRA
= rTextNode
.getIDocumentRedlineAccess();
532 if (IDocumentRedlineAccess::IsShowChanges(rIDRA
.GetRedlineFlags())
533 && !getRootFrame()->IsHideRedlines())
535 const SwRedlineTable::size_type nRedlPos
= rIDRA
.GetRedlinePos( rTextNode
, RedlineType::Any
);
536 if( SwRedlineTable::npos
!= nRedlPos
)
538 SwAttrHandler aAttrHandler
;
539 aAttrHandler
.Init( rTextNode
.GetSwAttrSet(),
540 *rTextNode
.getIDocumentSettingAccess() );
541 SwRedlineItr
aRedln(rTextNode
, *pFnt
, aAttrHandler
, nRedlPos
, SwRedlineItr::Mode::Show
);
542 const SwRangeRedline
* pRedline
= rIDRA
.GetRedlineTable()[nRedlPos
];
543 // show redlining only on the inserted/deleted empty paragraph, but not on the next one
544 if ( rTextNode
.GetIndex() != pRedline
->End()->GetNodeIndex() )
545 eRedline
= pRedline
->GetType();
546 // except if the next empty paragraph starts a new redline (e.g. deletion after insertion)
547 else if ( nRedlPos
+ 1 < rIDRA
.GetRedlineTable().size() )
549 const SwRangeRedline
* pNextRedline
= rIDRA
.GetRedlineTable()[nRedlPos
+ 1];
550 if ( rTextNode
.GetIndex() == pNextRedline
->Start()->GetNodeIndex() )
551 eRedline
= pNextRedline
->GetType();
556 if( pSh
->GetViewOptions()->IsParagraph() && getFramePrintArea().Height() )
558 if( RTL_TEXTENCODING_SYMBOL
== pFnt
->GetCharSet( SwFontScript::Latin
) &&
559 pFnt
->GetName( SwFontScript::Latin
) != numfunc::GetDefBulletFontname() )
561 pFnt
->SetFamily( FAMILY_DONTKNOW
, SwFontScript::Latin
);
562 pFnt
->SetName( numfunc::GetDefBulletFontname(), SwFontScript::Latin
);
563 pFnt
->SetStyleName(OUString(), SwFontScript::Latin
);
564 pFnt
->SetCharSet( RTL_TEXTENCODING_SYMBOL
, SwFontScript::Latin
);
566 pFnt
->SetVertical( 0_deg10
, IsVertical() );
567 SwFrameSwapper
aSwapper( this, true );
568 SwLayoutModeModifier
aLayoutModeModifier( *pSh
->GetOut() );
569 aLayoutModeModifier
.Modify( IsRightToLeft() );
572 pFnt
->ChgPhysFnt( pSh
, *pSh
->GetOut() );
573 Point aPos
= getFrameArea().Pos() + getFramePrintArea().Pos();
575 const SvxFirstLineIndentItem
& rFirstLine(
576 GetTextNodeForParaProps()->GetSwAttrSet().GetFirstLineIndent());
578 if (0 < rFirstLine
.GetTextFirstLineOffset())
580 aPos
.AdjustX(rFirstLine
.GetTextFirstLineOffset());
583 std::unique_ptr
<SwSaveClip
, o3tl::default_delete
<SwSaveClip
>> xClip
;
586 xClip
.reset(new SwSaveClip( pSh
->GetOut() ));
587 xClip
->ChgClip( rRect
);
590 aPos
.AdjustY(pFnt
->GetAscent( pSh
, *pSh
->GetOut() ) );
592 if (GetTextNodeForParaProps()->GetSwAttrSet().GetParaGrid().GetValue() &&
595 SwTextGridItem
const*const pGrid(GetGridItem(FindPageFrame()));
598 // center character in grid line
599 aPos
.AdjustY(( pGrid
->GetBaseHeight() -
600 pFnt
->GetHeight( pSh
, *pSh
->GetOut() ) ) / 2 );
602 if ( ! pGrid
->GetRubyTextBelow() )
603 aPos
.AdjustY(pGrid
->GetRubyHeight() );
607 // Don't show the paragraph mark for collapsed paragraphs, when they are hidden
608 // No paragraph marker in the non-last part of a split fly anchor, either.
609 if ( EmptyHeight( ) > 1 && !HasNonLastSplitFlyDrawObj() )
611 SwDrawTextInfo
aDrawInf( pSh
, *pSh
->GetOut(), CH_PAR
, 0, 1 );
612 aDrawInf
.SetPos( aPos
);
613 aDrawInf
.SetSpace( 0 );
614 aDrawInf
.SetKanaComp( 0 );
615 aDrawInf
.SetWrong( nullptr );
616 aDrawInf
.SetGrammarCheck( nullptr );
617 aDrawInf
.SetSmartTags( nullptr );
618 aDrawInf
.SetFrame( this );
619 aDrawInf
.SetFont( pFnt
.get() );
620 aDrawInf
.SetSnapToGrid( false );
622 // show redline color and settings drawing a background pilcrow,
623 // but keep also other formattings (with neutral pilcrow color)
624 if ( eRedline
!= RedlineType::None
)
626 pFnt
->DrawText_( aDrawInf
);
627 if ( eRedline
== RedlineType::Delete
)
628 pFnt
->SetStrikeout( STRIKEOUT_NONE
);
630 pFnt
->SetUnderline( LINESTYLE_NONE
);
633 pFnt
->SetColor(NON_PRINTING_CHARACTER_COLOR
);
634 pFnt
->DrawText_( aDrawInf
);
645 void SwTextFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, SwPrintData
const*const) const
649 // #i16816# tagged pdf support
650 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
652 if( IsEmpty() && PaintEmpty( rRect
, true ) )
655 if( IsLocked() || IsHiddenNow() || ! getFramePrintArea().HasArea() )
658 // It can happen that the IdleCollector withdrew my cached information
661 OSL_ENSURE( isFrameAreaPositionValid(), "+SwTextFrame::PaintSwFrame: no Calc()" );
663 // #i29062# pass info that we are currently
665 const_cast<SwTextFrame
*>(this)->GetFormatted( true );
668 PaintEmpty( rRect
, false );
673 OSL_ENSURE( false, "+SwTextFrame::PaintSwFrame: missing format information" );
678 // tdf140219-2.odt text frame with only fly portions and a follow is not
679 // actually a paragraph - delay creating all structured elements to follow.
680 bool const isPDFTaggingEnabled(!HasFollow() || GetPara()->HasContentPortions());
681 ::std::optional
<SwTaggedPDFHelper
> oTaggedPDFHelperNumbering
;
682 if (isPDFTaggingEnabled
)
684 Num_Info
aNumInfo(*this);
685 oTaggedPDFHelperNumbering
.emplace(&aNumInfo
, nullptr, nullptr, rRenderContext
);
688 // Lbl unfortunately must be able to contain multiple numbering portions
689 // that may be on multiple lines of text (but apparently always in the
690 // master frame), so it gets complicated.
691 ::std::optional
<SwTaggedPDFHelper
> oTaggedLabel
;
692 // Paragraph tag - if there is a list label, opening should be delayed.
693 ::std::optional
<SwTaggedPDFHelper
> oTaggedParagraph
;
695 if (isPDFTaggingEnabled
696 && (GetTextNodeForParaProps()->IsOutline()
697 || !GetPara()->HasNumberingPortion(SwParaPortion::FootnoteToo
)))
698 { // no Lbl needed => open paragraph tag now
699 Frame_Info
aFrameInfo(*this, false);
700 oTaggedParagraph
.emplace(nullptr, &aFrameInfo
, nullptr, rRenderContext
);
703 // We don't want to be interrupted while painting.
704 // Do that after thr Format()!
705 TextFrameLockGuard
aLock(const_cast<SwTextFrame
*>(this));
707 // We only paint the part of the TextFrame which changed, is within the
708 // range and was requested to paint.
709 // One could think that the area rRect _needs_ to be painted, although
710 // rRepaint is set. Indeed, we cannot avoid this problem from a formal
711 // perspective. Luckily we can assume rRepaint to be empty when we need
712 // paint the while Frame.
713 SwTextLineAccess
aAccess( this );
714 SwParaPortion
*pPara
= aAccess
.GetPara();
716 SwRepaint
&rRepaint
= pPara
->GetRepaint();
718 // Switch off recycling when in the FlyContentFrame.
719 // A DrawRect is called for repainting the line anyways.
720 if( rRepaint
.GetOffset() )
722 const SwFlyFrame
*pFly
= FindFlyFrame();
723 if( pFly
&& pFly
->IsFlyInContentFrame() )
724 rRepaint
.SetOffset( 0 );
727 // Ge the String for painting. The length is of special interest.
730 OSL_ENSURE( ! IsSwapped(), "A frame is swapped before Paint" );
731 SwRect
aOldRect( rRect
);
734 SwSwapIfNotSwapped
swap(const_cast<SwTextFrame
*>(this));
737 SwitchVerticalToHorizontal( const_cast<SwRect
&>(rRect
) );
739 if ( IsRightToLeft() )
740 SwitchRTLtoLTR( const_cast<SwRect
&>(rRect
) );
742 SwTextPaintInfo
aInf( const_cast<SwTextFrame
*>(this), rRect
);
743 sw::WrongListIterator
iterWrong(*this, &SwTextNode::GetWrong
);
744 sw::WrongListIterator
iterGrammar(*this, &SwTextNode::GetGrammarCheck
);
745 sw::WrongListIterator
iterSmartTags(*this, &SwTextNode::GetSmartTags
);
746 if (iterWrong
.LooksUseful())
748 aInf
.SetWrongList( &iterWrong
);
750 if (iterGrammar
.LooksUseful())
752 aInf
.SetGrammarCheckList( &iterGrammar
);
754 if (iterSmartTags
.LooksUseful())
756 aInf
.SetSmartTags( &iterSmartTags
);
758 aInf
.GetTextFly().SetTopRule();
760 SwTextPainter
aLine( const_cast<SwTextFrame
*>(this), &aInf
);
761 // Optimization: if no free flying Frame overlaps into our line, the
762 // SwTextFly just switches off
763 aInf
.GetTextFly().Relax();
765 OutputDevice
* pOut
= aInf
.GetOut();
766 const bool bOnWin
= pSh
->GetWin() != nullptr;
768 SwSaveClip
aClip( bOnWin
|| IsUndersized() ? pOut
: nullptr );
770 // Output loop: For each Line ... (which is still visible) ...
771 // adapt rRect (Top + 1, Bottom - 1)
772 // Because the Iterator attaches the Lines without a gap to each other
773 aLine
.TwipsToLine( rRect
.Top() + 1 );
774 tools::Long nBottom
= rRect
.Bottom();
776 bool bNoPrtLine
= 0 == GetMinPrtLine();
779 while ( aLine
.Y() < GetMinPrtLine() && aLine
.Next() )
781 bNoPrtLine
= aLine
.Y() >= GetMinPrtLine();
787 aLine
.DrawTextLine(rRect
, aClip
, IsUndersized(), oTaggedLabel
, oTaggedParagraph
, isPDFTaggingEnabled
);
789 } while( aLine
.Next() && aLine
.Y() <= nBottom
);
793 if( aLine
.IsPaintDrop() )
794 aLine
.PaintDropPortion();
796 if( rRepaint
.HasArea() )
800 PaintParagraphStylesHighlighting();
802 const_cast<SwRect
&>(rRect
) = aOldRect
;
804 OSL_ENSURE( ! IsSwapped(), "A frame is swapped after Paint" );
806 assert(!oTaggedLabel
); // must have been closed if opened
807 assert(!isPDFTaggingEnabled
|| oTaggedParagraph
|| rRect
.GetIntersection(getFrameArea()) != getFrameArea()); // must have been created during complete paint (PDF export is always complete paint)
810 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */