android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / text / frmpaint.cxx
blob906b18616ddd5431b192ae6b820c16042b04c470
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <memory>
21 #include <com/sun/star/text/HoriOrientation.hpp>
22 #include <editeng/pgrditem.hxx>
23 #include <editeng/lrspitem.hxx>
24 #include <tgrditem.hxx>
25 #include <paratr.hxx>
27 #include <fmtline.hxx>
28 #include <lineinfo.hxx>
29 #include <charfmt.hxx>
30 #include <rootfrm.hxx>
31 #include <pagefrm.hxx>
32 #include <viewsh.hxx>
33 #include <viewopt.hxx>
34 #include <frmatr.hxx>
35 #include <txtfrm.hxx>
36 #include "itrpaint.hxx"
37 #include "txtpaint.hxx"
38 #include "txtcache.hxx"
39 #include <flyfrm.hxx>
40 #include "redlnitr.hxx"
41 #include <redline.hxx>
42 #include <swmodule.hxx>
43 #include <tabfrm.hxx>
44 #include <numrule.hxx>
45 #include <wrong.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;
59 namespace {
61 class SwExtraPainter
63 SwSaveClip m_aClip;
64 SwRect m_aRect;
65 const SwTextFrame* m_pTextFrame;
66 SwViewShell *m_pSh;
67 std::unique_ptr<SwFont> m_pFnt;
68 const SwLineNumberInfo &m_rLineInf;
69 SwTwips m_nX;
70 SwTwips m_nRedX;
71 sal_Int32 m_nLineNr;
72 sal_uInt16 m_nDivider;
73 bool m_bGoLeft;
74 bool IsClipChg() const { return m_aClip.IsChg(); }
76 SwExtraPainter(const SwExtraPainter&) = delete;
77 SwExtraPainter& operator=(const SwExtraPainter&) = delete;
79 public:
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 )
88 return false;
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 )
94 return false;
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 )
108 , m_aRect( rRct )
109 , m_pTextFrame( pFrame )
110 , m_pSh( pVwSh )
111 , m_rLineInf( rLnInf )
112 , m_nX(0)
113 , m_nRedX(0)
114 , m_nLineNr( 1 )
115 , m_nDivider(0)
116 , m_bGoLeft(false)
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() );
145 if( bLineNum )
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() )
153 oIsRightPage = true;
154 ePos = ePos == LINENUMBER_POS_INSIDE ?
155 LINENUMBER_POS_LEFT : LINENUMBER_POS_RIGHT;
157 else
159 oIsRightPage = false;
160 ePos = ePos == LINENUMBER_POS_OUTSIDE ?
161 LINENUMBER_POS_LEFT : LINENUMBER_POS_RIGHT;
164 if( LINENUMBER_POS_LEFT == ePos )
166 m_bGoLeft = true;
167 m_nX -= m_rLineInf.GetPosFromLeft();
169 else
171 m_bGoLeft = false;
172 m_nX += pFrame->getFrameArea().Width() + m_rLineInf.GetPosFromLeft();
175 if( eHor == text::HoriOrientation::NONE )
176 return;
178 if( text::HoriOrientation::INSIDE == eHor || text::HoriOrientation::OUTSIDE == eHor )
180 if (!oIsRightPage)
181 oIsRightPage = pFrame->FindPageFrame()->OnRightPage();
182 if (*oIsRightPage)
183 eHor = eHor == text::HoriOrientation::INSIDE ? text::HoriOrientation::LEFT : text::HoriOrientation::RIGHT;
184 else
185 eHor = eHor == text::HoriOrientation::OUTSIDE ? text::HoriOrientation::LEFT : text::HoriOrientation::RIGHT;
187 const SwFrame* pTmpFrame = pFrame->FindTabFrame();
188 if( !pTmpFrame )
189 pTmpFrame = pFrame;
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
198 ? *pRedlineText
199 : ( HasNumber()
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) );
207 if ( pRedlineText )
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;
228 SwFont* pTmpFnt;
229 if( bTooBig )
231 pTmpFnt = new SwFont( *GetFont() );
232 if( nMax >= 20 )
234 nMax *= 17;
235 nMax /= 20;
237 pTmpFnt->SetSize( Size( 0, nMax ), pTmpFnt->GetActual() );
239 else
240 pTmpFnt = GetFont();
241 Point aTmpPos( m_nX, nY );
242 aTmpPos.AdjustY(nAsc );
243 if ( pRedlineText )
245 Size aSize = pTmpFnt->GetTextSize_( aDrawInf );
246 aTmpPos.AdjustX( -(aSize.Width()) - 200 );
248 bool bPaint = true;
249 if( !IsClipChg() )
251 Size aSize = pTmpFnt->GetTextSize_( aDrawInf );
252 if( m_bGoLeft )
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() )
257 ), aSize );
258 if( !m_aRect.Contains( aRct ) )
260 if( aRct.Intersection( m_aRect ).IsEmpty() )
261 bPaint = false;
262 else
263 m_aClip.ChgClip( m_aRect, m_pTextFrame );
266 else if( m_bGoLeft )
267 aTmpPos.AdjustX( -(pTmpFnt->GetTextSize_( aDrawInf ).Width()) );
268 aDrawInf.SetPos( aTmpPos );
269 if( bPaint )
270 pTmpFnt->DrawText_( aDrawInf );
272 if( bTooBig )
273 delete pTmpFnt;
274 if( bRed )
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 );
287 if( !IsClipChg() )
289 SwRect aRct( aStart, aEnd );
290 if( !m_aRect.Contains( aRct ) )
292 if( aRct.Intersection( m_aRect ).IsEmpty() )
293 return;
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() )
313 return;
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 )
332 return;
334 if( IsLocked() || IsHiddenNow() || !getFramePrintArea().Height() )
335 return;
336 SwViewShell *pSh = getRootFrame()->GetCurrShell();
338 SwSwapIfNotSwapped swap(const_cast<SwTextFrame *>(this));
339 SwRect rOldRect( rRect );
341 if ( IsVertical() )
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 );
352 if( HasPara() )
354 TextFrameLockGuard aLock(const_cast<SwTextFrame*>(this));
356 SwTextLineAccess aAccess( this );
357 aAccess.GetPara();
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() ) )
371 aExtra.IncLineNr();
372 if( !aLine.Next() )
374 const_cast<SwRect&>(rRect) = rOldRect;
375 return;
379 tools::Long nBottom = rRect.Bottom();
381 bool bNoPrtLine = 0 == GetMinPrtLine();
382 if( !bNoPrtLine )
384 while ( aLine.Y() < GetMinPrtLine() )
386 if( ( rLineInf.IsCountBlankLines() || aLine.GetCurr()->HasContent() )
387 && !aLine.GetCurr()->IsDummy() )
388 aExtra.IncLineNr();
389 if( !aLine.Next() )
390 break;
392 bNoPrtLine = aLine.Y() >= GetMinPrtLine();
394 const bool bIsShowChangesInMargin = pSh->GetViewOptions()->IsShowChangesInMargin();
395 if( bNoPrtLine )
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 );
410 if ( bRedInMargin )
412 const OUString* pRedlineText = aLine.GetCurr()->GetRedlineText();
413 if( !pRedlineText->isEmpty() )
415 aExtra.PaintExtra( aLine.Y(), nTmpAscent,
416 nTmpHeight, bRed, pRedlineText );
417 bRed = false;
418 bNum = false;
421 if ( bNum )
423 aExtra.PaintExtra( aLine.Y(), nTmpAscent, nTmpHeight, bRed );
424 bRed = false;
427 aExtra.IncLineNr();
429 if( bRed )
430 aExtra.PaintRedline( aLine.Y(), aLine.GetLineHeight() );
432 } while( aLine.Next() && aLine.Y() <= nBottom );
435 else
437 if (SwRedlineTable::npos == rIDRA.GetRedlinePos(*GetTextNodeFirst(), RedlineType::Any))
439 bRedLine = false;
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 );
448 else if( bRedLine )
449 aExtra.PaintRedline( getFrameArea().Top()+getFramePrintArea().Top(), getFramePrintArea().Height() );
452 const_cast<SwRect&>(rRect) = rOldRect;
456 SwRect SwTextFrame::GetPaintSwRect()
458 // finger layout
459 OSL_ENSURE( isFrameAreaPositionValid(), "+SwTextFrame::GetPaintSwRect: no Calc()" );
461 SwRect aRet( getFramePrintArea() );
462 if ( IsEmpty() || !HasPara() )
463 aRet += getFrameArea().Pos();
464 else
466 // We return the right paint rect. Use the calculated PaintOfst as the
467 // left margin
468 SwRepaint& rRepaint = GetPara()->GetRepaint();
469 tools::Long l;
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() )
479 rRepaint.Right( l );
480 rRepaint.SetOffset( 0 );
481 aRet = rRepaint;
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 );
494 if ( IsVertical() )
495 SwitchHorizontalToVertical( aRet );
497 ResetRepaint();
499 return 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 ) )
509 bInitFont = false;
510 SwTextFly aTextFly( this );
511 aTextFly.SetTopRule();
512 SwRect aRect;
513 if( bCheck && aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) )
514 return false;
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() ));
525 else
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() );
571 pFnt->Invalidate();
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;
584 if( IsUndersized() )
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() &&
593 IsInDocBody() )
595 SwTextGridItem const*const pGrid(GetGridItem(FindPageFrame()));
596 if ( pGrid )
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 );
629 else
630 pFnt->SetUnderline( LINESTYLE_NONE );
633 pFnt->SetColor(NON_PRINTING_CHARACTER_COLOR);
634 pFnt->DrawText_( aDrawInf );
637 return true;
640 else
641 return true;
642 return false;
645 void SwTextFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
647 ResetRepaint();
649 // #i16816# tagged pdf support
650 SwViewShell *pSh = getRootFrame()->GetCurrShell();
652 if( IsEmpty() && PaintEmpty( rRect, true ) )
653 return;
655 if( IsLocked() || IsHiddenNow() || ! getFramePrintArea().HasArea() )
656 return;
658 // It can happen that the IdleCollector withdrew my cached information
659 if( !HasPara() )
661 OSL_ENSURE( isFrameAreaPositionValid(), "+SwTextFrame::PaintSwFrame: no Calc()" );
663 // #i29062# pass info that we are currently
664 // painting.
665 const_cast<SwTextFrame*>(this)->GetFormatted( true );
666 if( IsEmpty() )
668 PaintEmpty( rRect, false );
669 return;
671 if( !HasPara() )
673 OSL_ENSURE( false, "+SwTextFrame::PaintSwFrame: missing format information" );
674 return;
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.
729 // Rectangle
730 OSL_ENSURE( ! IsSwapped(), "A frame is swapped before Paint" );
731 SwRect aOldRect( rRect );
734 SwSwapIfNotSwapped swap(const_cast<SwTextFrame *>(this));
736 if ( IsVertical() )
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();
777 if( !bNoPrtLine )
779 while ( aLine.Y() < GetMinPrtLine() && aLine.Next() )
781 bNoPrtLine = aLine.Y() >= GetMinPrtLine();
783 if( bNoPrtLine )
787 aLine.DrawTextLine(rRect, aClip, IsUndersized(), oTaggedLabel, oTaggedParagraph, isPDFTaggingEnabled);
789 } while( aLine.Next() && aLine.Y() <= nBottom );
792 // Once is enough:
793 if( aLine.IsPaintDrop() )
794 aLine.PaintDropPortion();
796 if( rRepaint.HasArea() )
797 rRepaint.Clear();
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: */