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 .
20 #include <sal/config.h>
22 #include <string_view>
27 #include <IDocumentLayoutAccess.hxx>
28 #include <pagefrm.hxx>
29 #include <rootfrm.hxx>
31 #include <SwPortionHandler.hxx>
35 #include <fmtsrnd.hxx>
36 #include <ftninfo.hxx>
37 #include <charfmt.hxx>
39 #include <editeng/brushitem.hxx>
40 #include <editeng/charrotateitem.hxx>
42 #include <sortedobjs.hxx>
49 #include "itrform2.hxx"
51 #include <pagedesc.hxx>
52 #include "redlnitr.hxx"
53 #include <sectfrm.hxx>
54 #include <layouter.hxx>
55 #include <frmtool.hxx>
56 #include <ndindex.hxx>
57 #include <IDocumentSettingAccess.hxx>
58 #include <IDocumentRedlineAccess.hxx>
59 #include <swmodule.hxx>
60 #include <unotextrange.hxx>
61 #include <redline.hxx>
62 #include <editeng/colritem.hxx>
63 #include <editeng/udlnitem.hxx>
64 #include <editeng/crossedoutitem.hxx>
66 #include <com/sun/star/beans/XPropertySet.hpp>
67 #include <com/sun/star/awt/CharSet.hpp>
68 #include <com/sun/star/text/XTextRange.hpp>
70 using namespace ::com::sun::star
;
72 bool SwTextFrame::IsFootnoteNumFrame_() const
75 return false; // tdf#102073 first frame in cell doesn't have mpPrev set
76 const SwFootnoteFrame
* pFootnote
= FindFootnoteFrame()->GetMaster();
77 while( pFootnote
&& !pFootnote
->ContainsContent() )
78 pFootnote
= pFootnote
->GetMaster();
83 * Looks for the TextFrame matching the SwTextFootnote within a master-follow chain
85 SwTextFrame
*SwTextFrame::FindFootnoteRef( const SwTextFootnote
*pFootnote
)
87 SwTextFrame
*pFrame
= this;
88 const bool bFwd
= MapModelToView(&pFootnote
->GetTextNode(), pFootnote
->GetStart()) >= GetOffset();
91 if( SwFootnoteBossFrame::FindFootnote( pFrame
, pFootnote
) )
93 pFrame
= bFwd
? pFrame
->GetFollow() :
94 pFrame
->IsFollow() ? pFrame
->FindMaster() : nullptr;
99 void SwTextFrame::SetHasRotatedPortions(bool bHasRotatedPortions
)
101 mbHasRotatedPortions
= bHasRotatedPortions
;
105 void SwTextFrame::CalcFootnoteFlag(TextFrameIndex nStop
) // For testing the SplitFrame
107 void SwTextFrame::CalcFootnoteFlag()
113 const TextFrameIndex nEnd
= nStop
!= TextFrameIndex(COMPLETE_STRING
)
115 : GetFollow() ? GetFollow()->GetOffset() : TextFrameIndex(COMPLETE_STRING
);
117 const TextFrameIndex nEnd
= GetFollow()
118 ? GetFollow()->GetOffset()
119 : TextFrameIndex(COMPLETE_STRING
);
122 SwTextNode
const* pNode(nullptr);
123 sw::MergedAttrIter
iter(*this);
124 for (SwTextAttr
const* pHt
= iter
.NextAttr(&pNode
); pHt
; pHt
= iter
.NextAttr(&pNode
))
126 if ( pHt
->Which() == RES_TXTATR_FTN
)
128 TextFrameIndex
const nIdx(MapModelToView(pNode
, pHt
->GetStart()));
131 if( GetOffset() <= nIdx
)
140 bool SwTextFrame::CalcPrepFootnoteAdjust()
142 OSL_ENSURE( HasFootnote(), "Who´s calling me?" );
143 SwFootnoteBossFrame
*pBoss
= FindFootnoteBossFrame( true );
144 const SwFootnoteFrame
*pFootnote
= pBoss
->FindFirstFootnote( this );
145 if (pFootnote
&& FTNPOS_CHAPTER
!= GetDoc().GetFootnoteInfo().m_ePos
&&
146 ( !pBoss
->GetUpper()->IsSctFrame() ||
147 !static_cast<SwSectionFrame
*>(pBoss
->GetUpper())->IsFootnoteAtEnd() ) )
149 const SwFootnoteContFrame
*pCont
= pBoss
->FindFootnoteCont();
150 bool bReArrange
= true;
152 SwRectFnSet
aRectFnSet(this);
153 if ( pCont
&& aRectFnSet
.YDiff( aRectFnSet
.GetTop(pCont
->getFrameArea()),
154 aRectFnSet
.GetBottom(getFrameArea()) ) > 0 )
156 pBoss
->RearrangeFootnotes( aRectFnSet
.GetBottom(getFrameArea()), false,
157 pFootnote
->GetAttr() );
160 pFootnote
= pBoss
->FindFirstFootnote( this );
164 if( !pCont
|| !pFootnote
|| bReArrange
!= (pFootnote
->FindFootnoteBossFrame() == pBoss
) )
166 SwTextFormatInfo
aInf( getRootFrame()->GetCurrShell()->GetOut(), this );
167 SwTextFormatter
aLine( this, &aInf
);
169 SetPara( nullptr ); // May be deleted!
178 * Local helper function. Checks if nLower should be taken as the boundary
181 static SwTwips
lcl_GetFootnoteLower( const SwTextFrame
* pFrame
, SwTwips nLower
)
183 // nLower is an absolute value. It denotes the bottom of the line
184 // containing the footnote.
185 SwRectFnSet
aRectFnSet(pFrame
);
187 OSL_ENSURE( !pFrame
->IsVertical() || !pFrame
->IsSwapped(),
188 "lcl_GetFootnoteLower with swapped frame" );
191 SwTwips nRet
= nLower
;
193 // Check if text is inside a table.
194 if ( pFrame
->IsInTab() )
196 // If pFrame is inside a table, we have to check if
197 // a) The table is not allowed to split or
198 // b) The table row is not allowed to split
200 // Inside a table, there are no footnotes,
201 // see SwFrame::FindFootnoteBossFrame. So we don't have to check
202 // the case that pFrame is inside a (footnote collecting) section
204 const SwFrame
* pRow
= pFrame
;
205 while( !pRow
->IsRowFrame() || !pRow
->GetUpper()->IsTabFrame() )
206 pRow
= pRow
->GetUpper();
207 const SwTabFrame
* pTabFrame
= static_cast<const SwTabFrame
*>(pRow
->GetUpper());
209 OSL_ENSURE( pTabFrame
&& pRow
&&
210 pRow
->GetUpper()->IsTabFrame(), "Upper of row should be tab" );
212 const bool bDontSplit
= !pTabFrame
->IsFollow() &&
213 !pTabFrame
->IsLayoutSplitAllowed();
217 nMin
= aRectFnSet
.GetBottom(pTabFrame
->getFrameArea());
218 else if ( !static_cast<const SwRowFrame
*>(pRow
)->IsRowSplitAllowed() )
219 nMin
= aRectFnSet
.GetBottom(pRow
->getFrameArea());
221 if ( nMin
&& aRectFnSet
.YDiff( nMin
, nLower
) > 0 )
224 nAdd
= aRectFnSet
.GetBottomMargin(*pRow
->GetUpper());
227 nAdd
= aRectFnSet
.GetBottomMargin(*pFrame
);
231 if ( aRectFnSet
.IsVert() )
237 // #i10770#: If there are fly frames anchored at previous paragraphs,
238 // the deadline should consider their lower borders.
239 const SwFrame
* pStartFrame
= pFrame
->GetUpper()->GetLower();
240 OSL_ENSURE( pStartFrame
, "Upper has no lower" );
241 SwTwips nFlyLower
= aRectFnSet
.IsVert() ? LONG_MAX
: 0;
242 while ( pStartFrame
!= pFrame
)
244 assert(pStartFrame
&& "Frame chain is broken");
245 if ( pStartFrame
->GetDrawObjs() )
247 const SwSortedObjs
&rObjs
= *pStartFrame
->GetDrawObjs();
248 for (SwAnchoredObject
* pAnchoredObj
: rObjs
)
250 if (pAnchoredObj
->GetFrameFormat()->GetSurround().GetSurround()
251 == text::WrapTextMode_THROUGH
)
253 continue; // tdf#161718 no effect on text flow, skip
256 SwRect
aRect( pAnchoredObj
->GetObjRect() );
258 auto pFlyFrame
= pAnchoredObj
->DynCastFlyFrame();
260 pFlyFrame
->isFrameAreaDefinitionValid() )
262 const SwTwips nBottom
= aRectFnSet
.GetBottom(aRect
);
263 if ( aRectFnSet
.YDiff( nBottom
, nFlyLower
) > 0 )
269 pStartFrame
= pStartFrame
->GetNext();
272 if ( aRectFnSet
.IsVert() )
273 nRet
= std::min( nRet
, nFlyLower
);
275 nRet
= std::max( nRet
, nFlyLower
);
280 SwTwips
SwTextFrame::GetFootnoteLine( const SwTextFootnote
*pFootnote
) const
282 OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
283 "SwTextFrame::GetFootnoteLine with swapped frame" );
285 SwTextFrame
*pThis
= const_cast<SwTextFrame
*>(this);
289 // #109071# GetFormatted() does not work here, because most probably
290 // the frame is currently locked. We return the previous value.
291 return pThis
->mnFootnoteLine
> 0 ?
292 pThis
->mnFootnoteLine
:
293 IsVertical() ? getFrameArea().Left() : getFrameArea().Bottom();
298 SwSwapIfNotSwapped
swap(const_cast<SwTextFrame
*>(this));
300 SwTextInfo
aInf( pThis
);
301 SwTextIter
aLine( pThis
, &aInf
);
302 TextFrameIndex
const nPos(MapModelToView(
303 &pFootnote
->GetTextNode(), pFootnote
->GetStart()));
304 aLine
.CharToLine( nPos
);
306 nRet
= aLine
.Y() + aLine
.GetLineHeight();
308 nRet
= SwitchHorizontalToVertical( nRet
);
311 nRet
= lcl_GetFootnoteLower( pThis
, nRet
);
313 pThis
->mnFootnoteLine
= nRet
;
318 * Calculates the maximum reachable height for the TextFrame in the Footnote Area.
319 * The cell's bottom margin with the Footnote Reference limit's this height.
321 SwTwips
SwTextFrame::GetFootnoteFrameHeight_() const
323 OSL_ENSURE( !IsFollow() && IsInFootnote(), "SwTextFrame::SetFootnoteLine: moon walk" );
325 const SwFootnoteFrame
*pFootnoteFrame
= FindFootnoteFrame();
326 const SwTextFrame
*pRef
= static_cast<const SwTextFrame
*>(pFootnoteFrame
->GetRef());
327 const SwFootnoteBossFrame
*pBoss
= FindFootnoteBossFrame();
328 if( pBoss
!= pRef
->FindFootnoteBossFrame( !pFootnoteFrame
->GetAttr()->
329 GetFootnote().IsEndNote() ) )
332 SwSwapIfSwapped
swap(const_cast<SwTextFrame
*>(this));
334 SwTwips nHeight
= pRef
->IsInFootnoteConnect() ?
335 1 : pRef
->GetFootnoteLine( pFootnoteFrame
->GetAttr() );
338 // As odd as it may seem: the first Footnote on the page may not touch the
339 // Footnote Reference, when entering text in the Footnote Area.
340 const SwFrame
*pCont
= pFootnoteFrame
->GetUpper();
342 // Height within the Container which we're allowed to consume anyways
343 SwRectFnSet
aRectFnSet(pCont
);
344 SwTwips nTmp
= aRectFnSet
.YDiff( aRectFnSet
.GetPrtBottom(*pCont
),
345 aRectFnSet
.GetTop(getFrameArea()) );
347 #if OSL_DEBUG_LEVEL > 0
350 bool bInvalidPos
= false;
351 const SwLayoutFrame
* pTmp
= GetUpper();
352 while( !bInvalidPos
&& pTmp
)
354 const SwFrame
* pLower
= pTmp
->Lower();
355 bInvalidPos
= !pTmp
->isFrameAreaPositionValid() ||
356 !pLower
|| !pLower
->isFrameAreaPositionValid();
359 pTmp
= pTmp
->GetUpper();
361 OSL_ENSURE( bInvalidPos
, "Hanging below FootnoteCont" );
365 if ( aRectFnSet
.YDiff( aRectFnSet
.GetTop(pCont
->getFrameArea()), nHeight
) > 0 )
367 // Growth potential of the container
368 if ( !pRef
->IsInFootnoteConnect() )
370 SwSaveFootnoteHeight
aSave( const_cast<SwFootnoteBossFrame
*>(pBoss
), nHeight
);
371 nHeight
= const_cast<SwFootnoteContFrame
*>(static_cast<const SwFootnoteContFrame
*>(pCont
))->Grow( LONG_MAX
, true );
374 nHeight
= const_cast<SwFootnoteContFrame
*>(static_cast<const SwFootnoteContFrame
*>(pCont
))->Grow( LONG_MAX
, true );
381 { // The container has to shrink
382 nTmp
+= aRectFnSet
.YDiff( aRectFnSet
.GetTop(pCont
->getFrameArea()), nHeight
);
393 SwTextFrame
*SwTextFrame::FindQuoVadisFrame()
395 // Check whether we're in a FootnoteFrame
396 if( GetIndPrev() || !IsInFootnote() )
399 // To the preceding FootnoteFrame
400 SwFootnoteFrame
*pFootnoteFrame
= FindFootnoteFrame()->GetMaster();
401 if( !pFootnoteFrame
)
404 // Now the last Content
405 SwContentFrame
*pCnt
= pFootnoteFrame
->ContainsContent();
408 SwContentFrame
*pLast
;
411 pCnt
= pCnt
->GetNextContentFrame();
412 } while( pCnt
&& pFootnoteFrame
->IsAnLower( pCnt
) );
413 return static_cast<SwTextFrame
*>(pLast
);
416 void SwTextFrame::RemoveFootnote(TextFrameIndex
const nStart
, TextFrameIndex
const nLen
)
418 if ( !IsFootnoteAllowed() )
421 bool bRollBack
= nLen
!= TextFrameIndex(COMPLETE_STRING
);
423 SwTextFrame
* pSource
;
426 nEnd
= nStart
+ nLen
;
427 pSource
= GetFollow();
433 nEnd
= TextFrameIndex(COMPLETE_STRING
);
437 SwPageFrame
* pUpdate
= nullptr;
438 bool bRemove
= false;
439 SwFootnoteBossFrame
*pFootnoteBoss
= nullptr;
440 SwFootnoteBossFrame
*pEndBoss
= nullptr;
441 bool bFootnoteEndDoc
= FTNPOS_CHAPTER
== GetDoc().GetFootnoteInfo().m_ePos
;
442 SwTextNode
const* pNode(nullptr);
443 sw::MergedAttrIterReverse
iter(*this);
444 for (SwTextAttr
const* pHt
= iter
.PrevAttr(&pNode
); pHt
; pHt
= iter
.PrevAttr(&pNode
))
446 if (RES_TXTATR_FTN
!= pHt
->Which())
449 TextFrameIndex
const nIdx(MapModelToView(pNode
, pHt
->GetStart()));
455 SwTextFootnote
const*const pFootnote(static_cast<SwTextFootnote
const*>(pHt
));
456 const bool bEndn
= pFootnote
->GetFootnote().IsEndNote();
461 pEndBoss
= pSource
->FindFootnoteBossFrame();
467 pFootnoteBoss
= pSource
->FindFootnoteBossFrame( true );
468 if( pFootnoteBoss
->GetUpper()->IsSctFrame() )
470 SwSectionFrame
* pSect
= static_cast<SwSectionFrame
*>(
471 pFootnoteBoss
->GetUpper());
472 if (pSect
->IsFootnoteAtEnd())
473 bFootnoteEndDoc
= false;
478 // We don't delete, but move instead.
479 // Three cases are to be considered:
480 // 1) There's neither Follow nor PrevFollow:
481 // -> RemoveFootnote() (maybe even a OSL_ENSURE(value))
483 // 2) nStart > GetOffset, I have a Follow
484 // -> Footnote moves into Follow
486 // 3) nStart < GetOffset, I am a Follow
487 // -> Footnote moves into the PrevFollow
489 // Both need to be on one Page/in one Column
490 SwFootnoteFrame
*pFootnoteFrame
= SwFootnoteBossFrame::FindFootnote(pSource
, pFootnote
);
494 const bool bEndDoc
= bEndn
|| bFootnoteEndDoc
;
497 while (pFootnoteFrame
)
499 pFootnoteFrame
->SetRef( this );
500 pFootnoteFrame
= pFootnoteFrame
->GetFollow();
504 else if (GetFollow())
506 SwContentFrame
*pDest
= GetFollow();
507 while (pDest
->GetFollow() && static_cast<SwTextFrame
*>(pDest
->
508 GetFollow())->GetOffset() <= nIdx
)
509 pDest
= pDest
->GetFollow();
510 OSL_ENSURE( !SwFootnoteBossFrame::FindFootnote(
511 pDest
,pFootnote
),"SwTextFrame::RemoveFootnote: footnote exists");
513 // Never deregister; always move
515 !pFootnoteFrame
->FindFootnoteBossFrame()->IsBefore(pDest
->FindFootnoteBossFrame(!bEndn
))
518 SwPageFrame
* pTmp
= pFootnoteFrame
->FindPageFrame();
519 if( pUpdate
&& pUpdate
!= pTmp
)
520 pUpdate
->UpdateFootnoteNum();
522 while ( pFootnoteFrame
)
524 pFootnoteFrame
->SetRef( pDest
);
525 pFootnoteFrame
= pFootnoteFrame
->GetFollow();
530 pFootnoteBoss
->MoveFootnotes( this, pDest
, pFootnote
);
533 static_cast<SwTextFrame
*>(pDest
)->SetFootnote( true );
535 OSL_ENSURE( SwFootnoteBossFrame::FindFootnote( pDest
,
536 pFootnote
),"SwTextFrame::RemoveFootnote: footnote ChgRef failed");
540 if (!bEndDoc
|| ( bEndn
&& pEndBoss
->IsInSct() &&
541 !SwLayouter::Collecting( &GetDoc(),
542 pEndBoss
->FindSctFrame(), nullptr ) ))
545 pEndBoss
->RemoveFootnote( this, pFootnote
);
547 pFootnoteBoss
->RemoveFootnote( this, pFootnote
);
548 bRemove
= bRemove
|| !bEndDoc
;
549 OSL_ENSURE( !SwFootnoteBossFrame::FindFootnote( this, pFootnote
),
550 "SwTextFrame::RemoveFootnote: can't get off that footnote" );
557 pUpdate
->UpdateFootnoteNum();
559 // We break the oscillation
560 if (bRemove
&& !bFootnoteEndDoc
&& HasPara())
566 // We call the RemoveFootnote from within the FindBreak, because the last line is
567 // to be passed to the Follow. The Offset of the Follow is, however, outdated;
568 // it'll be set soon. CalcFntFlag depends on a correctly set Follow Offset.
569 // Therefore we temporarily calculate the Follow Offset here
570 TextFrameIndex
nOldOfst(COMPLETE_STRING
);
571 if( HasFollow() && nStart
> GetOffset() )
573 nOldOfst
= GetFollow()->GetOffset();
574 GetFollow()->ManipOfst(nStart
+ (bRollBack
? nLen
: TextFrameIndex(0)));
576 pSource
->CalcFootnoteFlag();
577 if (nOldOfst
< TextFrameIndex(COMPLETE_STRING
))
578 GetFollow()->ManipOfst( nOldOfst
);
583 * We basically only have two possibilities:
585 * a) The Footnote is already present
586 * => we move it, if another pSrcFrame has been found
588 * b) The Footnote is not present
589 * => we have it created for us
591 * Whether the Footnote ends up on our Page/Column, doesn't matter in this
594 * Optimization for Endnotes.
596 * Another problem: if the Deadline falls within the Footnote Area, we need
597 * to move the Footnote.
599 * @returns false on any type of error
601 void SwTextFrame::ConnectFootnote( SwTextFootnote
*pFootnote
, const SwTwips nDeadLine
)
603 OSL_ENSURE( !IsVertical() || !IsSwapped(),
604 "SwTextFrame::ConnectFootnote with swapped frame" );
607 mbInFootnoteConnect
= true; // Just reset!
608 // See if pFootnote is an endnote on a separate endnote page.
609 const bool bEnd
= pFootnote
->GetFootnote().IsEndNote();
611 // We want to store this value, because it is needed as a fallback
612 // in GetFootnoteLine(), if there is no paragraph information available
613 mnFootnoteLine
= nDeadLine
;
615 // We always need a parent (Page/Column)
616 SwSectionFrame
*pSect
;
617 SwContentFrame
*pContent
= this;
618 if( bEnd
&& IsInSct() )
620 pSect
= FindSctFrame();
621 if( pSect
->IsEndnAtEnd() )
622 pContent
= pSect
->FindLastContent( SwFindMode::EndNote
);
627 SwFootnoteBossFrame
*pBoss
= pContent
->FindFootnoteBossFrame( !bEnd
);
629 pSect
= pBoss
->FindSctFrame();
630 bool bDocEnd
= bEnd
? !( pSect
&& pSect
->IsEndnAtEnd() ) :
631 ( !( pSect
&& pSect
->IsFootnoteAtEnd() ) &&
632 FTNPOS_CHAPTER
== GetDoc().GetFootnoteInfo().m_ePos
);
634 // Footnote can be registered with the Follow
635 SwContentFrame
*pSrcFrame
= FindFootnoteRef( pFootnote
);
639 if (pSect
&& pSrcFrame
)
641 SwFootnoteFrame
*pFootnoteFrame
= SwFootnoteBossFrame::FindFootnote( pSrcFrame
, pFootnote
);
642 if (pFootnoteFrame
&& pFootnoteFrame
->IsInSct())
644 pBoss
->RemoveFootnote( pSrcFrame
, pFootnote
);
649 else if( bEnd
&& pSect
)
651 SwFootnoteFrame
*pFootnoteFrame
= pSrcFrame
? SwFootnoteBossFrame::FindFootnote( pSrcFrame
, pFootnote
) : nullptr;
652 if( pFootnoteFrame
&& !pFootnoteFrame
->GetUpper() )
653 pFootnoteFrame
= nullptr;
654 SwDoc
*const pDoc
= &GetDoc();
655 if( SwLayouter::Collecting( pDoc
, pSect
, pFootnoteFrame
) )
659 SwFootnoteFrame
*pNew
= new SwFootnoteFrame(pDoc
->GetDfltFrameFormat(),this,this,pFootnote
);
660 SwNodeIndex
aIdx( *pFootnote
->GetStartNode(), 1 );
661 ::InsertCnt_( pNew
, pDoc
, aIdx
.GetIndex() );
662 pDoc
->getIDocumentLayoutAccess().GetLayouter()->CollectEndnote( pNew
);
664 else if( pSrcFrame
!= this )
665 SwFootnoteBossFrame::ChangeFootnoteRef( pSrcFrame
, pFootnote
, this );
666 mbInFootnoteConnect
= false;
669 else if (pSrcFrame
&& pFootnoteFrame
)
671 SwFootnoteBossFrame
*pFootnoteBoss
= pFootnoteFrame
->FindFootnoteBossFrame();
672 if( !pFootnoteBoss
->IsInSct() ||
673 pFootnoteBoss
->ImplFindSctFrame()->GetSection()!=pSect
->GetSection() )
675 pBoss
->RemoveFootnote( pSrcFrame
, pFootnote
);
681 if( bDocEnd
|| bEnd
)
684 pBoss
->AppendFootnote( this, pFootnote
);
685 else if( pSrcFrame
!= this )
686 SwFootnoteBossFrame::ChangeFootnoteRef( pSrcFrame
, pFootnote
, this );
687 mbInFootnoteConnect
= false;
691 SwSaveFootnoteHeight
aHeight( pBoss
, nDeadLine
);
693 if( !pSrcFrame
) // No Footnote was found at all
694 pBoss
->AppendFootnote( this, pFootnote
);
697 SwFootnoteFrame
*pFootnoteFrame
= SwFootnoteBossFrame::FindFootnote( pSrcFrame
, pFootnote
);
698 SwFootnoteBossFrame
*pFootnoteBoss
= pFootnoteFrame
->FindFootnoteBossFrame();
700 bool bBrutal
= false;
702 if( pFootnoteBoss
== pBoss
) // Ref and Footnote are on the same Page/Column
704 SwFrame
*pCont
= pFootnoteFrame
->GetUpper();
706 SwRectFnSet
aRectFnSet(pCont
);
707 tools::Long nDiff
= aRectFnSet
.YDiff( aRectFnSet
.GetTop(pCont
->getFrameArea()),
712 // If the Footnote has been registered to a Follow, we need to
714 if ( pSrcFrame
!= this )
715 SwFootnoteBossFrame::ChangeFootnoteRef( pSrcFrame
, pFootnote
, this );
717 // We have some room left, so the Footnote can grow
718 if ( pFootnoteFrame
->GetFollow() && nDiff
> 0 )
720 SwFrameDeleteGuard
aDeleteGuard(pCont
);
721 SwTwips nHeight
= aRectFnSet
.GetHeight(pCont
->getFrameArea());
722 pBoss
->RearrangeFootnotes( nDeadLine
, false, pFootnote
);
725 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
726 if ( pSh
&& nHeight
== aRectFnSet
.GetHeight(pCont
->getFrameArea()) )
727 // So that we don't miss anything
728 pSh
->InvalidateWindows( pCont
->getFrameArea() );
730 mbInFootnoteConnect
= false;
738 // Ref and Footnote are not on one Page; attempt to move is necessary
739 SwFrame
* pTmp
= this;
740 while( pTmp
->GetNext() && pSrcFrame
!= pTmp
)
741 pTmp
= pTmp
->GetNext();
742 if( pSrcFrame
== pTmp
)
745 { // If our Parent is in a column Area, but the Page already has a
746 // FootnoteContainer, we can only brute force it
747 if( pSect
&& pSect
->FindFootnoteBossFrame( !bEnd
)->FindFootnoteCont() )
750 else if ( !pFootnoteFrame
->GetPrev() ||
751 pFootnoteBoss
->IsBefore( pBoss
)
754 SwFootnoteBossFrame
*pSrcBoss
= pSrcFrame
->FindFootnoteBossFrame( !bEnd
);
755 pSrcBoss
->MoveFootnotes( pSrcFrame
, this, pFootnote
);
758 SwFootnoteBossFrame::ChangeFootnoteRef( pSrcFrame
, pFootnote
, this );
762 // The brute force method: Remove Footnote and append.
763 // We need to call SetFootnoteDeadLine(), as we can more easily adapt the
764 // nMaxFootnoteHeight after RemoveFootnote
767 pBoss
->RemoveFootnote( pSrcFrame
, pFootnote
, false );
768 std::unique_ptr
<SwSaveFootnoteHeight
> pHeight(bEnd
? nullptr : new SwSaveFootnoteHeight( pBoss
, nDeadLine
));
769 pBoss
->AppendFootnote( this, pFootnote
);
773 // In column Areas, that not yet reach the Page's border a RearrangeFootnotes is not
774 // useful yet, as the Footnote container has not yet been calculated
775 if( !pSect
|| !pSect
->Growable() )
777 // Validate environment, to avoid oscillation
778 SwSaveFootnoteHeight
aNochmal( pBoss
, nDeadLine
);
780 pBoss
->RearrangeFootnotes( nDeadLine
, true );
783 else if( pSect
->IsFootnoteAtEnd() )
789 mbInFootnoteConnect
= false;
793 * The portion for the Footnote Reference in the Text
795 SwFootnotePortion
*SwTextFormatter::NewFootnotePortion( SwTextFormatInfo
&rInf
,
798 OSL_ENSURE( ! m_pFrame
->IsVertical() || m_pFrame
->IsSwapped(),
799 "NewFootnotePortion with unswapped frame" );
801 if (!m_pFrame
->IsFootnoteAllowed())
802 return new SwFootnotePortion(u
""_ustr
, nullptr);
804 SwTextFootnote
*pFootnote
= static_cast<SwTextFootnote
*>(pHint
);
806 const SwFormatFootnote
& rFootnote
= pFootnote
->GetFootnote();
807 SwDoc
*const pDoc
= &m_pFrame
->GetDoc();
810 return new SwFootnotePortion(rFootnote
.GetViewNumStr(*pDoc
, m_pFrame
->getRootFrame()), pFootnote
);
812 SwSwapIfSwapped
swap(m_pFrame
);
816 SwTwips nOldReal
= m_pCurr
->GetRealHeight();
817 SwTwips nOldAscent
= m_pCurr
->GetAscent();
818 SwTwips nOldHeight
= m_pCurr
->Height();
820 nReal
= m_pCurr
->GetRealHeight();
821 if( nReal
< nOldReal
)
823 m_pCurr
->SetRealHeight( nOldReal
);
824 m_pCurr
->Height( nOldHeight
);
825 m_pCurr
->SetAscent( nOldAscent
);
828 SwTwips nLower
= Y() + nReal
;
830 const bool bVertical
= m_pFrame
->IsVertical();
832 nLower
= m_pFrame
->SwitchHorizontalToVertical( nLower
);
834 nLower
= lcl_GetFootnoteLower( m_pFrame
, nLower
);
837 // The Connect does not do anything useful in this case, but will
838 // mostly throw away the Footnote and create it anew.
839 if( !rInf
.IsQuick() )
840 m_pFrame
->ConnectFootnote( pFootnote
, nLower
);
842 SwTextFrame
*pScrFrame
= m_pFrame
->FindFootnoteRef( pFootnote
);
843 SwFootnoteBossFrame
*pBoss
= m_pFrame
->FindFootnoteBossFrame( !rFootnote
.IsEndNote() );
844 SwFootnoteFrame
*pFootnoteFrame
= nullptr;
846 pFootnoteFrame
= SwFootnoteBossFrame::FindFootnote( pScrFrame
, pFootnote
);
848 // We see whether our Append has caused some Footnote to
849 // still be on the Page/Column. If not, our line disappears too,
850 // which will lead to the following undesired behaviour:
851 // Footnote1 still fits onto the Page/Column, but Footnote2 doesn't.
852 // The Footnote2 Reference remains on the Page/Column. The Footnote itself
853 // is on the next Page/Column.
855 // Exception: If the Page/Column cannot accommodate another line,
856 // the Footnote Reference should be moved to the next one.
857 if( !rFootnote
.IsEndNote() )
859 SwSectionFrame
*pSct
= pBoss
->FindSctFrame();
860 bool bAtSctEnd
= pSct
&& pSct
->IsFootnoteAtEnd();
861 if( FTNPOS_CHAPTER
!= pDoc
->GetFootnoteInfo().m_ePos
|| bAtSctEnd
)
863 SwFrame
* pFootnoteCont
= pBoss
->FindFootnoteCont();
864 // If the Parent is within an Area, it can only be a Column of this
865 // Area. If this one is not the first Column, we can avoid it.
866 if( !m_pFrame
->IsInTab() && ( GetLineNr() > 1 || m_pFrame
->GetPrev() ||
867 ( !bAtSctEnd
&& m_pFrame
->GetIndPrev() ) ||
868 ( pSct
&& pBoss
->GetPrev() ) ) )
872 rInf
.SetStop( true );
877 // There must not be any Footnote Containers in column Areas and at the same time on the
879 if( pSct
&& !bAtSctEnd
) // Is the Container in a (column) Area?
881 SwFootnoteBossFrame
* pTmp
= pBoss
->FindSctFrame()->FindFootnoteBossFrame( true );
882 SwFootnoteContFrame
* pFootnoteC
= pTmp
->FindFootnoteCont();
885 SwFootnoteFrame
* pTmpFrame
= static_cast<SwFootnoteFrame
*>(pFootnoteC
->Lower());
886 if( pTmpFrame
&& *pTmpFrame
< pFootnote
)
888 rInf
.SetStop( true );
893 // Is this the last Line that fits?
894 SwTwips nTmpBot
= Y() + nReal
* 2;
897 nTmpBot
= m_pFrame
->SwitchHorizontalToVertical( nTmpBot
);
899 SwRectFnSet
aRectFnSet(pFootnoteCont
);
901 const tools::Long nDiff
= aRectFnSet
.YDiff(
902 aRectFnSet
.GetTop(pFootnoteCont
->getFrameArea()),
905 if( pScrFrame
&& nDiff
< 0 )
909 SwFootnoteBossFrame
*pFootnoteBoss
= pFootnoteFrame
->FindFootnoteBossFrame();
910 if( pFootnoteBoss
!= pBoss
)
912 // We're in the last Line and the Footnote has moved
913 // to another Page. We also want to be on that Page!
914 rInf
.SetStop( true );
923 // Finally: Create FootnotePortion and exit ...
924 SwFootnotePortion
*pRet
= new SwFootnotePortion(
925 rFootnote
.GetViewNumStr(*pDoc
, m_pFrame
->getRootFrame()),
927 rInf
.SetFootnoteInside( true );
933 * The portion for the Footnote Numbering in the Footnote Area
935 SwNumberPortion
*SwTextFormatter::NewFootnoteNumPortion( SwTextFormatInfo
const &rInf
) const
937 OSL_ENSURE( m_pFrame
->IsInFootnote() && !m_pFrame
->GetIndPrev() && !rInf
.IsFootnoteDone(),
938 "This is the wrong place for a ftnnumber" );
939 if( rInf
.GetTextStart() != m_nStart
||
940 rInf
.GetTextStart() != rInf
.GetIdx() )
943 const SwFootnoteFrame
* pFootnoteFrame
= m_pFrame
->FindFootnoteFrame();
944 const SwTextFootnote
* pFootnote
= pFootnoteFrame
->GetAttr();
946 // Aha! So we're in the Footnote Area!
947 SwFormatFootnote
& rFootnote
= const_cast<SwFormatFootnote
&>(pFootnote
->GetFootnote());
949 SwDoc
*const pDoc
= &m_pFrame
->GetDoc();
950 OUString
aFootnoteText(rFootnote
.GetViewNumStr(*pDoc
, m_pFrame
->getRootFrame(), true));
952 const SwEndNoteInfo
* pInfo
;
953 if( rFootnote
.IsEndNote() )
954 pInfo
= &pDoc
->GetEndNoteInfo();
956 pInfo
= &pDoc
->GetFootnoteInfo();
958 const SwAttrSet
* pParSet
= &rInf
.GetCharAttr();
959 const IDocumentSettingAccess
* pIDSA
= &pDoc
->getIDocumentSettingAccess();
960 std::unique_ptr
<SwFont
> pNumFnt(new SwFont( pParSet
, pIDSA
));
963 // Underline style of paragraph font should not be considered
964 // Overline style of paragraph font should not be considered
965 // Weight style of paragraph font should not be considered
966 // Posture style of paragraph font should not be considered
967 // See also #i18463# and SwTextFormatter::NewNumberPortion()
968 pNumFnt
->SetUnderline( LINESTYLE_NONE
);
969 pNumFnt
->SetOverline( LINESTYLE_NONE
);
970 pNumFnt
->SetItalic( ITALIC_NONE
, SwFontScript::Latin
);
971 pNumFnt
->SetItalic( ITALIC_NONE
, SwFontScript::CJK
);
972 pNumFnt
->SetItalic( ITALIC_NONE
, SwFontScript::CTL
);
973 pNumFnt
->SetWeight( WEIGHT_NORMAL
, SwFontScript::Latin
);
974 pNumFnt
->SetWeight( WEIGHT_NORMAL
, SwFontScript::CJK
);
975 pNumFnt
->SetWeight( WEIGHT_NORMAL
, SwFontScript::CTL
);
977 const rtl::Reference
<SwXTextRange
> xAnchor
= rFootnote
.getAnchor(*pDoc
);
980 auto aAny
= xAnchor
->getPropertyValue(u
"CharFontCharSet"_ustr
);
982 if ((aAny
>>= eCharSet
) && eCharSet
== awt::CharSet::SYMBOL
)
985 aAny
= xAnchor
->getPropertyValue(u
"CharFontName"_ustr
);
986 if (aAny
>>= aFontName
)
988 pNumFnt
->SetName(aFontName
, SwFontScript::Latin
);
989 pNumFnt
->SetName(aFontName
, SwFontScript::CJK
);
990 pNumFnt
->SetName(aFontName
, SwFontScript::CTL
);
991 pNumFnt
->SetCharSet(RTL_TEXTENCODING_SYMBOL
, SwFontScript::Latin
);
992 pNumFnt
->SetCharSet(RTL_TEXTENCODING_SYMBOL
, SwFontScript::CJK
);
993 pNumFnt
->SetCharSet(RTL_TEXTENCODING_SYMBOL
, SwFontScript::CTL
);
998 const SwAttrSet
& rSet
= pInfo
->GetCharFormat(*pDoc
)->GetAttrSet();
999 pNumFnt
->SetDiffFnt(&rSet
, pIDSA
);
1000 pNumFnt
->SetVertical( pNumFnt
->GetOrientation(), m_pFrame
->IsVertical() );
1002 // tdf#85610 apply redline coloring to the footnote numbering in the footnote area
1003 SwUnoInternalPaM
aPam(*pDoc
);
1004 if ( ::sw::XTextRangeToSwPaM(aPam
, xAnchor
) )
1006 SwRedlineTable::size_type nRedlinePos
= 0;
1007 const SwRedlineTable
& rTable
= pDoc
->getIDocumentRedlineAccess().GetRedlineTable();
1008 const SwRangeRedline
* pRedline
= rTable
.FindAtPosition( *aPam
.Start(), nRedlinePos
);
1011 SwAttrPool
& rPool
= pDoc
->GetAttrPool();
1012 SfxItemSetFixed
<RES_CHRATR_BEGIN
, RES_CHRATR_END
-1> aSet(rPool
);
1014 std::size_t aAuthor
= (1 < pRedline
->GetStackCount())
1015 ? pRedline
->GetAuthor( 1 )
1016 : pRedline
->GetAuthor();
1018 if ( RedlineType::Delete
== pRedline
->GetType() )
1019 SwModule::get()->GetDeletedAuthorAttr(aAuthor
, aSet
);
1021 SwModule::get()->GetInsertAuthorAttr(aAuthor
, aSet
);
1023 if (const SvxColorItem
* pItem
= aSet
.GetItemIfSet(RES_CHRATR_COLOR
))
1024 pNumFnt
->SetColor(pItem
->GetValue());
1025 if (const SvxUnderlineItem
* pItem
= aSet
.GetItemIfSet(RES_CHRATR_UNDERLINE
))
1026 pNumFnt
->SetUnderline(pItem
->GetLineStyle());
1027 if (const SvxCrossedOutItem
* pItem
= aSet
.GetItemIfSet(RES_CHRATR_CROSSEDOUT
))
1028 pNumFnt
->SetStrikeout( pItem
->GetStrikeout() );
1032 SwFootnoteNumPortion
* pNewPor
= new SwFootnoteNumPortion( aFootnoteText
, std::move(pNumFnt
) );
1033 pNewPor
->SetLeft( !m_pFrame
->IsRightToLeft() );
1037 static OUString
lcl_GetPageNumber( const SwPageFrame
* pPage
)
1039 assert(pPage
&& "GetPageNumber: Homeless TextFrame");
1040 const sal_uInt16 nVirtNum
= pPage
->GetVirtPageNum();
1041 const SvxNumberType
& rNum
= pPage
->GetPageDesc()->GetNumType();
1042 return rNum
.GetNumStr( nVirtNum
);
1045 SwErgoSumPortion
*SwTextFormatter::NewErgoSumPortion( SwTextFormatInfo
const &rInf
) const
1047 // We cannot assume we're a Follow
1048 if( !m_pFrame
->IsInFootnote() || m_pFrame
->GetPrev() ||
1049 rInf
.IsErgoDone() || rInf
.GetIdx() != m_pFrame
->GetOffset() ||
1050 m_pFrame
->ImplFindFootnoteFrame()->GetAttr()->GetFootnote().IsEndNote() )
1053 // we are in the footnote container
1054 const SwFootnoteInfo
&rFootnoteInfo
= m_pFrame
->GetDoc().GetFootnoteInfo();
1055 SwTextFrame
*pQuoFrame
= m_pFrame
->FindQuoVadisFrame();
1058 const SwPageFrame
* pPage
= m_pFrame
->FindPageFrame();
1059 const SwPageFrame
* pQuoPage
= pQuoFrame
->FindPageFrame();
1060 if( pPage
== pQuoFrame
->FindPageFrame() )
1061 return nullptr; // If the QuoVadis is on the same Column/Page
1062 const OUString aPage
= lcl_GetPageNumber( pPage
);
1063 SwParaPortion
*pPara
= pQuoFrame
->GetPara();
1065 pPara
->SetErgoSumNum( aPage
);
1066 if( rFootnoteInfo
.m_aErgoSum
.isEmpty() )
1068 SwErgoSumPortion
*pErgo
= new SwErgoSumPortion( rFootnoteInfo
.m_aErgoSum
,
1069 lcl_GetPageNumber( pQuoPage
) );
1073 TextFrameIndex
SwTextFormatter::FormatQuoVadis(TextFrameIndex
const nOffset
)
1075 OSL_ENSURE( ! m_pFrame
->IsVertical() || ! m_pFrame
->IsSwapped(),
1076 "SwTextFormatter::FormatQuoVadis with swapped frame" );
1078 if( !m_pFrame
->IsInFootnote() || m_pFrame
->ImplFindFootnoteFrame()->GetAttr()->GetFootnote().IsEndNote() )
1081 const SwFrame
* pErgoFrame
= m_pFrame
->FindFootnoteFrame()->GetFollow();
1082 if( !pErgoFrame
&& m_pFrame
->HasFollow() )
1083 pErgoFrame
= m_pFrame
->GetFollow();
1087 if( pErgoFrame
== m_pFrame
->GetNext() )
1089 SwFrame
*pCol
= m_pFrame
->FindColFrame();
1090 while( pCol
&& !pCol
->GetNext() )
1091 pCol
= pCol
->GetUpper()->FindColFrame();
1097 const SwPageFrame
* pPage
= m_pFrame
->FindPageFrame();
1098 const SwPageFrame
* pErgoPage
= pErgoFrame
->FindPageFrame();
1099 if( pPage
== pErgoPage
)
1100 return nOffset
; // If the ErgoSum is on the same Page
1103 SwTextFormatInfo
&rInf
= GetInfo();
1104 const SwFootnoteInfo
&rFootnoteInfo
= m_pFrame
->GetDoc().GetFootnoteInfo();
1105 if( rFootnoteInfo
.m_aQuoVadis
.isEmpty() )
1108 // A remark on QuoVadis/ErgoSum:
1109 // We use the Font set for the Paragraph for these texts.
1110 // Thus, we initialize:
1111 // TODO: ResetFont();
1113 SeekStartAndChg( rInf
, true );
1114 if( GetRedln() && m_pCurr
->HasRedline() )
1116 std::pair
<SwTextNode
const*, sal_Int32
> const pos(
1117 GetTextFrame()->MapViewToModel(nOffset
));
1118 GetRedln()->Seek(*m_pFont
, pos
.first
->GetIndex(), pos
.second
, 0);
1121 // A tricky special case: Flyfrms extend into the Line and are at the
1122 // position we want to insert the Quovadis text
1123 // Let's see if it is that bad indeed:
1124 SwLinePortion
*pPor
= m_pCurr
->GetFirstPortion();
1125 SwTwips nLastLeft
= 0;
1128 if ( pPor
->IsFlyPortion() )
1129 nLastLeft
= static_cast<SwFlyPortion
*>(pPor
)->GetFix() +
1130 static_cast<SwFlyPortion
*>(pPor
)->Width();
1131 pPor
= pPor
->GetNextPortion();
1134 // The old game all over again: we want the Line to wrap around
1135 // at a certain point, so we adjust the width.
1136 // nLastLeft is now basically the right margin
1137 const SwTwips nOldRealWidth
= rInf
.RealWidth();
1138 rInf
.RealWidth( nOldRealWidth
- nLastLeft
);
1140 OUString aErgo
= lcl_GetPageNumber( pErgoFrame
->FindPageFrame() );
1141 SwQuoVadisPortion
*pQuo
= new SwQuoVadisPortion(rFootnoteInfo
.m_aQuoVadis
, aErgo
);
1142 pQuo
->SetAscent( rInf
.GetAscent() );
1143 pQuo
->Height( rInf
.GetTextHeight() );
1144 pQuo
->Format( rInf
);
1145 SwTwips nQuoWidth
= pQuo
->Width();
1146 SwLinePortion
* pCurrPor
= pQuo
;
1148 while ( rInf
.GetRest() )
1150 SwLinePortion
* pFollow
= rInf
.GetRest();
1151 rInf
.SetRest( nullptr );
1152 pCurrPor
->Move( rInf
);
1154 OSL_ENSURE( pFollow
->IsQuoVadisPortion(),
1155 "Quo Vadis, rest of QuoVadisPortion" );
1157 // format the rest and append it to the other QuoVadis parts
1158 pFollow
->Format( rInf
);
1159 nQuoWidth
= nQuoWidth
+ pFollow
->Width();
1161 pCurrPor
->Append( pFollow
);
1165 Right( Right() - nQuoWidth
);
1167 TextFrameIndex nRet
;
1169 SwSwapIfNotSwapped
swap(m_pFrame
);
1171 nRet
= FormatLine( m_nStart
);
1174 Right( rInf
.Left() + nOldRealWidth
- 1 );
1176 nLastLeft
= nOldRealWidth
- m_pCurr
->Width();
1179 // It's possible that there's a Margin Portion at the end, which would
1180 // just cause a lot of trouble, when respanning
1181 pPor
= m_pCurr
->FindLastPortion();
1182 SwGluePortion
*pGlue
= pPor
->IsMarginPortion() ? static_cast<SwMarginPortion
*>(pPor
) : nullptr;
1187 pGlue
->SetLen(TextFrameIndex(0));
1188 pGlue
->SetAscent( 0 );
1189 pGlue
->SetNextPortion( nullptr );
1190 pGlue
->SetFixWidth(0);
1193 // Luxury: We make sure the QuoVadis text appears on the right, by
1195 nLastLeft
= nLastLeft
- nQuoWidth
;
1198 if( nLastLeft
> pQuo
->GetAscent() ) // Minimum distance
1200 switch( GetAdjust() )
1202 case SvxAdjust::Block
:
1204 if( !m_pCurr
->GetLen() ||
1205 CH_BREAK
!= GetInfo().GetChar(m_nStart
+ m_pCurr
->GetLen() - TextFrameIndex(1)))
1206 nLastLeft
= pQuo
->GetAscent();
1207 nQuoWidth
= nQuoWidth
+ nLastLeft
;
1210 case SvxAdjust::Right
:
1212 nLastLeft
= pQuo
->GetAscent();
1213 nQuoWidth
= nQuoWidth
+ nLastLeft
;
1216 case SvxAdjust::Center
:
1218 nQuoWidth
= nQuoWidth
+ pQuo
->GetAscent();
1219 tools::Long nDiff
= nLastLeft
- nQuoWidth
;
1222 nLastLeft
= pQuo
->GetAscent();
1223 nQuoWidth
= -nDiff
+ nLastLeft
;
1228 nLastLeft
= (pQuo
->GetAscent() + nDiff
) / 2;
1233 nQuoWidth
= nQuoWidth
+ nLastLeft
;
1237 nQuoWidth
= nQuoWidth
+ nLastLeft
;
1240 pGlue
= new SwGluePortion(0);
1241 pGlue
->Width( nLastLeft
);
1242 pPor
->Append( pGlue
);
1243 pPor
= pPor
->GetNextPortion();
1247 // Finally: we insert the QuoVadis Portion
1251 // pPor->Append deletes the pPortion pointer of pPor.
1252 // Therefore we have to keep a pointer to the next portion
1253 pQuo
= static_cast<SwQuoVadisPortion
*>(pCurrPor
->GetNextPortion());
1254 pPor
->Append( pCurrPor
);
1255 pPor
= pPor
->GetNextPortion();
1259 m_pCurr
->Width( m_pCurr
->Width() + nQuoWidth
);
1261 // And adjust again, due to the adjustment and due to the following special
1263 // The DummyUser has set a smaller Font in the Line than the one used
1264 // by the QuoVadis text ...
1265 CalcAdjustLine( m_pCurr
);
1271 * This function creates a Line that reaches to the other Page Margin.
1272 * DummyLines or DummyPortions make sure, that oscillations stop, because
1273 * there's no way to flow back.
1274 * They are used for Footnotes in paragraph-bound Frames and for Footnote
1277 void SwTextFormatter::MakeDummyLine()
1279 SwTwips nRstHeight
= GetFrameRstHeight();
1280 if( m_pCurr
&& nRstHeight
> m_pCurr
->Height() )
1282 SwLineLayout
*pLay
= new SwLineLayout
;
1283 nRstHeight
= nRstHeight
- m_pCurr
->Height();
1284 pLay
->Height( nRstHeight
);
1285 pLay
->SetAscent( nRstHeight
);
1293 class SwFootnoteSave
1295 SwTextSizeInfo
* m_pInf
;
1297 std::unique_ptr
<SwFont
> m_pOld
;
1299 SwFootnoteSave(const SwFootnoteSave
&) = delete;
1300 SwFootnoteSave
& operator=(const SwFootnoteSave
&) = delete;
1303 SwFootnoteSave( const SwTextSizeInfo
&rInf
,
1304 const SwTextFootnote
*pTextFootnote
,
1305 const bool bApplyGivenScriptType
,
1306 const SwFontScript nGivenScriptType
);
1307 ~SwFootnoteSave() COVERITY_NOEXCEPT_FALSE
;
1312 SwFootnoteSave::SwFootnoteSave(const SwTextSizeInfo
& rInf
, const SwTextFootnote
* pTextFootnote
,
1313 const bool bApplyGivenScriptType
,
1314 const SwFontScript nGivenScriptType
)
1315 : m_pInf(&const_cast<SwTextSizeInfo
&>(rInf
))
1318 if( pTextFootnote
&& rInf
.GetTextFrame() )
1320 m_pFnt
= const_cast<SwTextSizeInfo
&>(rInf
).GetFont();
1321 m_pOld
.reset(new SwFont(*m_pFnt
));
1322 m_pOld
->GetTox() = m_pFnt
->GetTox();
1323 m_pFnt
->GetTox() = 0;
1324 SwFormatFootnote
& rFootnote
= const_cast<SwFormatFootnote
&>(pTextFootnote
->GetFootnote());
1325 const SwDoc
*const pDoc
= &rInf
.GetTextFrame()->GetDoc();
1328 if ( bApplyGivenScriptType
)
1330 m_pFnt
->SetActual(nGivenScriptType
);
1334 // examine text and set script
1335 OUString
aTmpStr(rFootnote
.GetViewNumStr(*pDoc
, rInf
.GetTextFrame()->getRootFrame()));
1336 m_pFnt
->SetActual(SwScriptInfo::WhichFont(0, aTmpStr
));
1339 const SwEndNoteInfo
* pInfo
;
1340 if( rFootnote
.IsEndNote() )
1341 pInfo
= &pDoc
->GetEndNoteInfo();
1343 pInfo
= &pDoc
->GetFootnoteInfo();
1344 const SwAttrSet
& rSet
= pInfo
->GetAnchorCharFormat(const_cast<SwDoc
&>(*pDoc
))->GetAttrSet();
1345 m_pFnt
->SetDiffFnt(&rSet
, &pDoc
->getIDocumentSettingAccess());
1347 // we reduce footnote size, if we are inside a double line portion
1348 if (!m_pOld
->GetEscapement() && 50 == m_pOld
->GetPropr())
1350 Size aSize
= m_pFnt
->GetSize(m_pFnt
->GetActual());
1351 m_pFnt
->SetSize(Size(aSize
.Width() / 2, aSize
.Height() / 2), m_pFnt
->GetActual());
1354 // set the correct rotation at the footnote font
1355 if( const SvxCharRotateItem
* pItem
= rSet
.GetItemIfSet( RES_CHRATR_ROTATE
) )
1356 m_pFnt
->SetVertical(pItem
->GetValue(),
1357 rInf
.GetTextFrame()->IsVertical());
1359 m_pFnt
->ChgPhysFnt(m_pInf
->GetVsh(), *m_pInf
->GetOut());
1361 if( const SvxBrushItem
* pItem
= rSet
.GetItemIfSet( RES_CHRATR_BACKGROUND
) )
1362 m_pFnt
->SetBackColor(pItem
->GetColor());
1368 SwFootnoteSave::~SwFootnoteSave() COVERITY_NOEXCEPT_FALSE
1374 m_pFnt
->GetTox() = m_pOld
->GetTox();
1375 m_pFnt
->ChgPhysFnt(m_pInf
->GetVsh(), *m_pInf
->GetOut());
1380 SwFootnotePortion::SwFootnotePortion(const OUString
& rExpand
, SwTextFootnote
* pFootn
, SwTwips nReal
)
1381 : SwFieldPortion( rExpand
, nullptr )
1382 , m_pFootnote(pFootn
)
1383 , m_nOrigHeight( nReal
)
1385 , mbPreferredScriptTypeSet( false )
1386 , mnPreferredScriptType( SwFontScript::Latin
)
1388 SetLen(TextFrameIndex(1));
1389 SetWhichPor( PortionType::Footnote
);
1392 bool SwFootnotePortion::GetExpText( const SwTextSizeInfo
&, OUString
&rText
) const
1398 bool SwFootnotePortion::Format( SwTextFormatInfo
&rInf
)
1401 // SwFootnoteSave aFootnoteSave( rInf, pFootnote );
1402 SwFootnoteSave
aFootnoteSave( rInf
, m_pFootnote
, mbPreferredScriptTypeSet
, mnPreferredScriptType
);
1403 // the idx is manipulated in SwExpandPortion::Format
1404 // this flag indicates, that a footnote is allowed to trigger
1405 // an underflow during SwTextGuess::Guess
1406 rInf
.SetFakeLineStart( rInf
.GetIdx() > rInf
.GetLineStart() );
1407 const bool bFull
= SwFieldPortion::Format( rInf
);
1408 rInf
.SetFakeLineStart( false );
1409 SetAscent( rInf
.GetAscent() );
1410 Height( rInf
.GetTextHeight() );
1411 rInf
.SetFootnoteDone( !bFull
);
1412 if (!bFull
&& m_pFootnote
)
1413 rInf
.SetParaFootnote();
1417 void SwFootnotePortion::Paint( const SwTextPaintInfo
&rInf
) const
1420 // SwFootnoteSave aFootnoteSave( rInf, pFootnote );
1421 SwFootnoteSave
aFootnoteSave( rInf
, m_pFootnote
, mbPreferredScriptTypeSet
, mnPreferredScriptType
);
1422 rInf
.DrawViewOpt( *this, PortionType::Footnote
);
1423 SwExpandPortion::Paint( rInf
);
1426 SwPosSize
SwFootnotePortion::GetTextSize( const SwTextSizeInfo
&rInfo
) const
1429 // SwFootnoteSave aFootnoteSave( rInfo, pFootnote );
1430 SwFootnoteSave
aFootnoteSave( rInfo
, m_pFootnote
, mbPreferredScriptTypeSet
, mnPreferredScriptType
);
1431 return SwExpandPortion::GetTextSize( rInfo
);
1435 void SwFootnotePortion::SetPreferredScriptType( SwFontScript nPreferredScriptType
)
1437 mbPreferredScriptTypeSet
= true;
1438 mnPreferredScriptType
= nPreferredScriptType
;
1441 SwFieldPortion
*SwQuoVadisPortion::Clone( const OUString
&rExpand
) const
1443 return new SwQuoVadisPortion( rExpand
, m_aErgo
);
1446 SwQuoVadisPortion::SwQuoVadisPortion( const OUString
&rExp
, OUString aStr
)
1447 : SwFieldPortion( rExp
), m_aErgo(std::move(aStr
))
1449 SetLen(TextFrameIndex(0));
1450 SetWhichPor( PortionType::QuoVadis
);
1453 bool SwQuoVadisPortion::Format( SwTextFormatInfo
&rInf
)
1455 // First try; maybe the Text fits
1456 CheckScript( rInf
);
1457 bool bFull
= SwFieldPortion::Format( rInf
);
1458 SetLen(TextFrameIndex(0));
1462 // Second try; we make the String shorter
1464 bFull
= SwFieldPortion::Format( rInf
);
1465 SetLen(TextFrameIndex(0));
1467 // Third try; we're done: we crush
1468 Width(rInf
.Width() - rInf
.X());
1470 // No multiline Fields for QuoVadis and ErgoSum
1471 if( rInf
.GetRest() )
1473 delete rInf
.GetRest();
1474 rInf
.SetRest( nullptr );
1480 bool SwQuoVadisPortion::GetExpText( const SwTextSizeInfo
&, OUString
&rText
) const
1483 // if this QuoVadisPortion has a follow, the follow is responsible for
1485 if ( ! HasFollow() )
1490 void SwQuoVadisPortion::HandlePortion( SwPortionHandler
& rPH
) const
1492 rPH
.Special( GetLen(), m_aExpand
+ m_aErgo
, GetWhichPor() );
1495 void SwQuoVadisPortion::Paint( const SwTextPaintInfo
&rInf
) const
1497 // We _always_ want to output per DrawStretchText, because nErgo
1498 // can quickly switch
1501 rInf
.DrawViewOpt( *this, PortionType::QuoVadis
);
1502 SwTextSlot
aDiffText( &rInf
, this, true, false );
1503 SwFontSave
aSave( rInf
, m_pFont
.get() );
1504 rInf
.DrawText( *this, rInf
.GetLen(), true );
1508 SwFieldPortion
*SwErgoSumPortion::Clone( const OUString
&rExpand
) const
1510 return new SwErgoSumPortion( rExpand
, std::u16string_view() );
1513 SwErgoSumPortion::SwErgoSumPortion(const OUString
&rExp
, std::u16string_view rStr
)
1514 : SwFieldPortion( rExp
)
1516 SetLen(TextFrameIndex(0));
1519 // One blank distance to the text
1521 SetWhichPor( PortionType::ErgoSum
);
1524 TextFrameIndex
SwErgoSumPortion::GetModelPositionForViewPoint(const SwTwips
) const
1526 return TextFrameIndex(0);
1529 bool SwErgoSumPortion::Format( SwTextFormatInfo
&rInf
)
1531 const bool bFull
= SwFieldPortion::Format( rInf
);
1532 SetLen(TextFrameIndex(0));
1533 rInf
.SetErgoDone( true );
1535 // No multiline Fields for QuoVadis and ErgoSum
1536 if( bFull
&& rInf
.GetRest() )
1538 delete rInf
.GetRest();
1539 rInf
.SetRest( nullptr );
1542 // We return false in order to get some text into the current line,
1543 // even if it's full (better than looping)
1547 void SwParaPortion::SetErgoSumNum( const OUString
& rErgo
)
1549 SwLineLayout
*pLay
= this;
1550 while( pLay
->GetNext() )
1552 pLay
= pLay
->GetNext();
1554 SwLinePortion
*pPor
= pLay
;
1555 SwQuoVadisPortion
*pQuo
= nullptr;
1556 while( pPor
&& !pQuo
)
1558 if ( pPor
->IsQuoVadisPortion() )
1559 pQuo
= static_cast<SwQuoVadisPortion
*>(pPor
);
1560 pPor
= pPor
->GetNextPortion();
1563 pQuo
->SetNumber( rErgo
);
1567 * Is called in SwTextFrame::Prepare()
1569 bool SwParaPortion::UpdateQuoVadis( std::u16string_view rQuo
)
1571 SwLineLayout
*pLay
= this;
1572 while( pLay
->GetNext() )
1574 pLay
= pLay
->GetNext();
1576 SwLinePortion
*pPor
= pLay
;
1577 SwQuoVadisPortion
*pQuo
= nullptr;
1578 while( pPor
&& !pQuo
)
1580 if ( pPor
->IsQuoVadisPortion() )
1581 pQuo
= static_cast<SwQuoVadisPortion
*>(pPor
);
1582 pPor
= pPor
->GetNextPortion();
1588 return pQuo
->GetQuoText() == rQuo
;
1591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */