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 assert(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
)
180 if (!oIsRightPage
.has_value())
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(m_pSh
->GetViewOptions()->GetNonPrintingCharacterColor());
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(SwModule::get()->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
>(SwModule::get()->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 const bool bIsShowChangesInMargin
= pSh
->GetViewOptions()->IsShowChangesInMargin();
384 if( bNoDummy
|| !aLine
.GetCurr()->IsDummy() )
386 bool bRed
= bRedLine
&& aLine
.GetCurr()->HasRedline();
387 if( rLineInf
.IsCountBlankLines() || aLine
.GetCurr()->HasContent() )
389 bool bRedInMargin
= bIsShowChangesInMargin
&& bRed
;
390 bool bNum
= bLineNum
&& ( aExtra
.HasNumber() || aExtra
.HasDivider() );
391 if( bRedInMargin
|| bNum
)
393 SwTwips nTmpHeight
, nTmpAscent
;
394 aLine
.CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
397 const OUString
* pRedlineText
= aLine
.GetCurr()->GetRedlineText();
398 if( !pRedlineText
->isEmpty() )
400 aExtra
.PaintExtra( aLine
.Y(), nTmpAscent
,
401 nTmpHeight
, bRed
, pRedlineText
);
408 aExtra
.PaintExtra( aLine
.Y(), nTmpAscent
, nTmpHeight
, bRed
);
415 aExtra
.PaintRedline( aLine
.Y(), aLine
.GetLineHeight() );
417 } while( aLine
.Next() && aLine
.Y() <= nBottom
);
421 if (SwRedlineTable::npos
== rIDRA
.GetRedlinePos(*GetTextNodeFirst(), RedlineType::Any
))
426 if( bLineNum
&& rLineInf
.IsCountBlankLines() &&
427 ( aExtra
.HasNumber() || aExtra
.HasDivider() ) )
429 aExtra
.PaintExtra( getFrameArea().Top()+getFramePrintArea().Top(), aExtra
.GetFont()
430 ->GetAscent( pSh
, *pSh
->GetOut() ), getFramePrintArea().Height(), bRedLine
);
433 aExtra
.PaintRedline( getFrameArea().Top()+getFramePrintArea().Top(), getFramePrintArea().Height() );
436 const_cast<SwRect
&>(rRect
) = rOldRect
;
440 SwRect
SwTextFrame::GetPaintSwRect()
443 OSL_ENSURE( isFrameAreaPositionValid(), "+SwTextFrame::GetPaintSwRect: no Calc()" );
445 SwRect
aRet( getFramePrintArea() );
446 if ( IsEmpty() || !HasPara() )
447 aRet
+= getFrameArea().Pos();
450 // We return the right paint rect. Use the calculated PaintOfst as the
452 SwRepaint
& rRepaint
= GetPara()->GetRepaint();
455 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
456 rRepaint
.Chg( GetUpper()->getFrameArea().Pos() + GetUpper()->getFramePrintArea().Pos(), GetUpper()->getFramePrintArea().SSize() );
458 if( rRepaint
.GetOffset() )
459 rRepaint
.Left( rRepaint
.GetOffset() );
461 l
= rRepaint
.GetRightOfst();
462 if( l
&& l
> rRepaint
.Right() )
464 rRepaint
.SetOffset( 0 );
467 // In case our left edge is the same as the body frame's left edge,
468 // then extend the rectangle to include the page margin as well,
469 // otherwise some font will be clipped.
470 SwLayoutFrame
* pBodyFrame
= GetUpper();
471 if (pBodyFrame
->IsBodyFrame() && aRet
.Left() == (pBodyFrame
->getFrameArea().Left() + pBodyFrame
->getFramePrintArea().Left()))
472 if (SwLayoutFrame
* pPageFrame
= pBodyFrame
->GetUpper())
473 aRet
.Left(pPageFrame
->getFrameArea().Left());
475 if ( IsRightToLeft() )
476 SwitchLTRtoRTL( aRet
);
479 SwitchHorizontalToVertical( aRet
);
486 bool SwTextFrame::PaintEmpty( const SwRect
&rRect
, bool bCheck
) const
488 PaintParagraphStylesHighlighting();
490 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
491 if( pSh
&& ( pSh
->GetViewOptions()->IsParagraph() || bInitFont
) )
494 SwTextFly
aTextFly( this );
495 aTextFly
.SetTopRule();
497 if( bCheck
&& aTextFly
.IsOn() && aTextFly
.IsAnyObj( aRect
) )
499 else if( pSh
->GetWin() )
501 std::unique_ptr
<SwFont
> pFnt
;
502 RedlineType eRedline
= RedlineType::None
;
503 const SwTextNode
& rTextNode
= *GetTextNodeForParaProps();
504 if ( rTextNode
.HasSwAttrSet() )
506 const SwAttrSet
*pAttrSet
= &( rTextNode
.GetSwAttrSet() );
507 pFnt
.reset(new SwFont( pAttrSet
, rTextNode
.getIDocumentSettingAccess() ));
511 SwFontAccess
aFontAccess( &rTextNode
.GetAnyFormatColl(), pSh
);
512 pFnt
.reset(new SwFont( aFontAccess
.Get()->GetFont() ));
515 const IDocumentRedlineAccess
& rIDRA
= rTextNode
.getIDocumentRedlineAccess();
516 if (IDocumentRedlineAccess::IsShowChanges(rIDRA
.GetRedlineFlags())
517 && !getRootFrame()->IsHideRedlines())
519 const SwRedlineTable::size_type nRedlPos
= rIDRA
.GetRedlinePos( rTextNode
, RedlineType::Any
);
520 if( SwRedlineTable::npos
!= nRedlPos
)
522 SwAttrHandler aAttrHandler
;
523 aAttrHandler
.Init( rTextNode
.GetSwAttrSet(),
524 *rTextNode
.getIDocumentSettingAccess() );
525 SwRedlineItr
aRedln(rTextNode
, *pFnt
, aAttrHandler
, nRedlPos
, SwRedlineItr::Mode::Show
);
526 const SwRangeRedline
* pRedline
= rIDRA
.GetRedlineTable()[nRedlPos
];
527 // show redlining only on the inserted/deleted empty paragraph, but not on the next one
528 if ( rTextNode
.GetIndex() != pRedline
->End()->GetNodeIndex() )
529 eRedline
= pRedline
->GetType();
530 // except if the next empty paragraph starts a new redline (e.g. deletion after insertion)
531 else if ( nRedlPos
+ 1 < rIDRA
.GetRedlineTable().size() )
533 const SwRangeRedline
* pNextRedline
= rIDRA
.GetRedlineTable()[nRedlPos
+ 1];
534 if ( rTextNode
.GetIndex() == pNextRedline
->Start()->GetNodeIndex() )
535 eRedline
= pNextRedline
->GetType();
540 if( pSh
->GetViewOptions()->IsParagraph() && getFramePrintArea().Height() )
542 if( RTL_TEXTENCODING_SYMBOL
== pFnt
->GetCharSet( SwFontScript::Latin
) &&
543 pFnt
->GetName( SwFontScript::Latin
) != numfunc::GetDefBulletFontname() )
545 pFnt
->SetFamily( FAMILY_DONTKNOW
, SwFontScript::Latin
);
546 pFnt
->SetName( numfunc::GetDefBulletFontname(), SwFontScript::Latin
);
547 pFnt
->SetStyleName(OUString(), SwFontScript::Latin
);
548 pFnt
->SetCharSet( RTL_TEXTENCODING_SYMBOL
, SwFontScript::Latin
);
550 pFnt
->SetVertical( 0_deg10
, IsVertical() );
551 SwFrameSwapper
aSwapper( this, true );
552 SwLayoutModeModifier
aLayoutModeModifier( *pSh
->GetOut() );
553 aLayoutModeModifier
.Modify( IsRightToLeft() );
556 pFnt
->ChgPhysFnt( pSh
, *pSh
->GetOut() );
557 Point aPos
= getFrameArea().Pos() + getFramePrintArea().Pos();
559 const SvxFirstLineIndentItem
& rFirstLine(
560 GetTextNodeForParaProps()->GetSwAttrSet().GetFirstLineIndent());
562 if (0.0 < rFirstLine
.GetTextFirstLineOffset().m_dValue
)
564 aPos
.AdjustX(rFirstLine
.ResolveTextFirstLineOffset({}));
567 std::unique_ptr
<SwSaveClip
, o3tl::default_delete
<SwSaveClip
>> xClip
;
570 xClip
.reset(new SwSaveClip( pSh
->GetOut() ));
571 xClip
->ChgClip( rRect
);
574 aPos
.AdjustY(pFnt
->GetAscent( pSh
, *pSh
->GetOut() ) );
576 if (GetTextNodeForParaProps()->GetSwAttrSet().GetParaGrid().GetValue() &&
579 SwTextGridItem
const*const pGrid(GetGridItem(FindPageFrame()));
582 // center character in grid line
583 aPos
.AdjustY(( pGrid
->GetBaseHeight() -
584 pFnt
->GetHeight( pSh
, *pSh
->GetOut() ) ) / 2 );
586 if ( ! pGrid
->GetRubyTextBelow() )
587 aPos
.AdjustY(pGrid
->GetRubyHeight() );
591 // Don't show the paragraph mark for collapsed paragraphs, when they are hidden
592 // No paragraph marker in the non-last part of a split fly anchor, either.
593 if ( EmptyHeight( ) > 1 && !HasNonLastSplitFlyDrawObj() )
595 SwDrawTextInfo
aDrawInf( pSh
, *pSh
->GetOut(), CH_PAR
, 0, 1 );
596 aDrawInf
.SetPos( aPos
);
597 aDrawInf
.SetSpace( 0 );
598 aDrawInf
.SetKanaComp( 0 );
599 aDrawInf
.SetWrong( nullptr );
600 aDrawInf
.SetGrammarCheck( nullptr );
601 aDrawInf
.SetSmartTags( nullptr );
602 aDrawInf
.SetFrame( this );
603 aDrawInf
.SetFont( pFnt
.get() );
604 aDrawInf
.SetSnapToGrid( false );
606 // show redline color and settings drawing a background pilcrow,
607 // but keep also other formattings (with neutral pilcrow color)
608 if ( eRedline
!= RedlineType::None
)
610 pFnt
->DrawText_( aDrawInf
);
611 if ( eRedline
== RedlineType::Delete
)
612 pFnt
->SetStrikeout( STRIKEOUT_NONE
);
614 pFnt
->SetUnderline( LINESTYLE_NONE
);
617 pFnt
->SetColor(pSh
->GetViewOptions()->GetNonPrintingCharacterColor());
618 pFnt
->DrawText_( aDrawInf
);
629 void SwTextFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, PaintFrameMode
) const
633 // #i16816# tagged pdf support
634 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
636 if( IsEmpty() && PaintEmpty( rRect
, true ) )
639 if( IsLocked() || IsHiddenNow() || ! getFramePrintArea().HasArea() )
642 // It can happen that the IdleCollector withdrew my cached information
645 OSL_ENSURE( isFrameAreaPositionValid(), "+SwTextFrame::PaintSwFrame: no Calc()" );
647 // #i29062# pass info that we are currently
649 const_cast<SwTextFrame
*>(this)->GetFormatted( true );
652 PaintEmpty( rRect
, false );
657 OSL_ENSURE( false, "+SwTextFrame::PaintSwFrame: missing format information" );
662 // tdf140219-2.odt text frame with only fly portions and a follow is not
663 // actually a paragraph - delay creating all structured elements to follow.
664 bool const isPDFTaggingEnabled(!HasFollow() || GetPara()->HasContentPortions());
665 ::std::optional
<SwTaggedPDFHelper
> oTaggedPDFHelperNumbering
;
666 if (isPDFTaggingEnabled
)
668 Num_Info
aNumInfo(*this);
669 oTaggedPDFHelperNumbering
.emplace(&aNumInfo
, nullptr, nullptr, rRenderContext
);
672 // Lbl unfortunately must be able to contain multiple numbering portions
673 // that may be on multiple lines of text (but apparently always in the
674 // master frame), so it gets complicated.
675 ::std::optional
<SwTaggedPDFHelper
> oTaggedLabel
;
676 // Paragraph tag - if there is a list label, opening should be delayed.
677 ::std::optional
<SwTaggedPDFHelper
> oTaggedParagraph
;
679 if (isPDFTaggingEnabled
680 && (GetTextNodeForParaProps()->IsOutline()
681 || !GetPara()->HasNumberingPortion(SwParaPortion::FootnoteToo
)))
682 { // no Lbl needed => open paragraph tag now
683 Frame_Info
aFrameInfo(*this, false);
684 oTaggedParagraph
.emplace(nullptr, &aFrameInfo
, nullptr, rRenderContext
);
687 // We don't want to be interrupted while painting.
688 // Do that after thr Format()!
689 TextFrameLockGuard
aLock(const_cast<SwTextFrame
*>(this));
691 // We only paint the part of the TextFrame which changed, is within the
692 // range and was requested to paint.
693 // One could think that the area rRect _needs_ to be painted, although
694 // rRepaint is set. Indeed, we cannot avoid this problem from a formal
695 // perspective. Luckily we can assume rRepaint to be empty when we need
696 // paint the while Frame.
697 SwTextLineAccess
aAccess( this );
698 SwParaPortion
*pPara
= aAccess
.GetPara();
700 SwRepaint
&rRepaint
= pPara
->GetRepaint();
702 // Switch off recycling when in the FlyContentFrame.
703 // A DrawRect is called for repainting the line anyways.
704 if( rRepaint
.GetOffset() )
706 const SwFlyFrame
*pFly
= FindFlyFrame();
707 if( pFly
&& pFly
->IsFlyInContentFrame() )
708 rRepaint
.SetOffset( 0 );
711 // Ge the String for painting. The length is of special interest.
714 OSL_ENSURE( ! IsSwapped(), "A frame is swapped before Paint" );
715 SwRect
aOldRect( rRect
);
718 SwSwapIfNotSwapped
swap(const_cast<SwTextFrame
*>(this));
721 SwitchVerticalToHorizontal( const_cast<SwRect
&>(rRect
) );
723 if ( IsRightToLeft() )
724 SwitchRTLtoLTR( const_cast<SwRect
&>(rRect
) );
726 SwTextPaintInfo
aInf( const_cast<SwTextFrame
*>(this), rRect
);
727 sw::WrongListIterator
iterWrong(*this, &SwTextNode::GetWrong
);
728 sw::WrongListIterator
iterGrammar(*this, &SwTextNode::GetGrammarCheck
);
729 sw::WrongListIterator
iterSmartTags(*this, &SwTextNode::GetSmartTags
);
730 if (iterWrong
.LooksUseful())
732 aInf
.SetWrongList( &iterWrong
);
734 if (iterGrammar
.LooksUseful())
736 aInf
.SetGrammarCheckList( &iterGrammar
);
738 if (iterSmartTags
.LooksUseful())
740 aInf
.SetSmartTags( &iterSmartTags
);
742 aInf
.GetTextFly().SetTopRule();
744 SwTextPainter
aLine( const_cast<SwTextFrame
*>(this), &aInf
);
745 // Optimization: if no free flying Frame overlaps into our line, the
746 // SwTextFly just switches off
747 aInf
.GetTextFly().Relax();
749 OutputDevice
* pOut
= aInf
.GetOut();
750 const bool bOnWin
= pSh
->GetWin() != nullptr;
752 SwSaveClip
aClip( bOnWin
|| IsUndersized() ? pOut
: nullptr );
754 // Output loop: For each Line ... (which is still visible) ...
755 // adapt rRect (Top + 1, Bottom - 1)
756 // Because the Iterator attaches the Lines without a gap to each other
757 aLine
.TwipsToLine( rRect
.Top() + 1 );
758 tools::Long nBottom
= rRect
.Bottom();
762 aLine
.DrawTextLine(rRect
, aClip
, IsUndersized(), oTaggedLabel
, oTaggedParagraph
, isPDFTaggingEnabled
);
764 } while( aLine
.Next() && aLine
.Y() <= nBottom
);
767 if( aLine
.IsPaintDrop() )
768 aLine
.PaintDropPortion();
770 if( rRepaint
.HasArea() )
774 PaintParagraphStylesHighlighting();
776 const_cast<SwRect
&>(rRect
) = aOldRect
;
778 OSL_ENSURE( ! IsSwapped(), "A frame is swapped after Paint" );
780 assert(!oTaggedLabel
); // must have been closed if opened
781 assert(!isPDFTaggingEnabled
|| oTaggedParagraph
|| rRect
.GetIntersection(getFrameArea()) != getFrameArea()); // must have been created during complete paint (PDF export is always complete paint)
784 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */