diff options
Diffstat (limited to 'sw/source/core/text/frmpaint.cxx')
-rw-r--r-- | sw/source/core/text/frmpaint.cxx | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx new file mode 100644 index 000000000..ec3fd196d --- /dev/null +++ b/sw/source/core/text/frmpaint.cxx @@ -0,0 +1,714 @@ +/* -*- 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 <swmodule.hxx> +#include <tabfrm.hxx> +#include <numrule.hxx> +#include <wrong.hxx> + +#include <EnhancedPDFExportHelper.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_uLong 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 { return !( m_nLineNr % m_rLineInf.GetCountBy() ); } + bool HasDivider() const { + if( !m_nDivider ) return false; + return !(m_nLineNr % m_rLineInf.GetDividerCountBy()); + } + + void PaintExtra( SwTwips nY, long nAsc, long nMax, bool bRed ); + void PaintRedline( SwTwips nY, 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; + if( bLineNum ) + { + /* 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, pFrame->IsVertical() ); + 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 ) + { + if( text::HoriOrientation::INSIDE == eHor || text::HoriOrientation::OUTSIDE == eHor ) + { + if (!oIsRightPage) + 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, long nAsc, long nMax, bool bRed ) +{ + // Line number is stronger than the divider + const OUString aTmp( HasNumber() ? m_rLineInf.GetNumType().GetNumStr( m_nLineNr ) + : m_rLineInf.GetDivider() ); + + // Get script type of line numbering: + m_pFnt->SetActual( SwScriptInfo::WhichFont(0, aTmp) ); + + 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 ); + 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.IsInside( 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 ) + { + long nDiff = m_bGoLeft ? m_nRedX - m_nX : m_nX - m_nRedX; + if( nDiff > REDLINE_MINDIST ) + PaintRedline( nY, nMax ); + } +} + +void SwExtraPainter::PaintRedline( SwTwips nY, long nMax ) +{ + Point aStart( m_nRedX, nY ); + Point aEnd( m_nRedX, nY + nMax ); + + if( !IsClipChg() ) + { + SwRect aRct( aStart, aEnd ); + if( !m_aRect.IsInside( 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; + + 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; + } + } + + 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(); + } + if( bNoPrtLine ) + { + do + { + if( bNoDummy || !aLine.GetCurr()->IsDummy() ) + { + bool bRed = bRedLine && aLine.GetCurr()->HasRedline(); + if( rLineInf.IsCountBlankLines() || aLine.GetCurr()->HasContent() ) + { + if( bLineNum && + ( aExtra.HasNumber() || aExtra.HasDivider() ) ) + { + sal_uInt16 nTmpHeight, nTmpAscent; + aLine.CalcAscentAndHeight( nTmpAscent, nTmpHeight ); + 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 (!GetMergedPara() && + 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(); + 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 +{ + 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; + 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); + } + } + + 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, 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 SvxLRSpaceItem &rSpace = + GetTextNodeForParaProps()->GetSwAttrSet().GetLRSpace(); + + if ( rSpace.GetTextFirstLineOffset() > 0 ) + aPos.AdjustX(rSpace.GetTextFirstLineOffset() ); + + std::unique_ptr<SwSaveClip> pClip; + if( IsUndersized() ) + { + pClip.reset(new SwSaveClip( pSh->GetOut() )); + pClip->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 + if ( EmptyHeight( ) > 1 ) + { + const OUString aTmp( CH_PAR ); + SwDrawTextInfo aDrawInf( pSh, *pSh->GetOut(), aTmp, 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 ); + + 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(); + + Num_Info aNumInfo( *this ); + SwTaggedPDFHelper aTaggedPDFHelperNumbering( &aNumInfo, nullptr, nullptr, rRenderContext ); + + Frame_Info aFrameInfo( *this ); + SwTaggedPDFHelper aTaggedPDFHelperParagraph( nullptr, &aFrameInfo, nullptr, rRenderContext ); + + 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; + } + } + + // 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 ); + 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() ); + + } while( aLine.Next() && aLine.Y() <= nBottom ); + } + + // Once is enough: + if( aLine.IsPaintDrop() ) + aLine.PaintDropPortion(); + + if( rRepaint.HasArea() ) + rRepaint.Clear(); + } + + const_cast<SwRect&>(rRect) = aOldRect; + + OSL_ENSURE( ! IsSwapped(), "A frame is swapped after Paint" ); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |