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 <config_wasm_strip.h>
22 #include <sal/config.h>
23 #include <sal/log.hxx>
25 #include <IDocumentRedlineAccess.hxx>
26 #include <anchoredobject.hxx>
27 #include <bodyfrm.hxx>
28 #include <hintids.hxx>
29 #include <editeng/keepitem.hxx>
30 #include <editeng/hyphenzoneitem.hxx>
31 #include <pagefrm.hxx>
37 #include <viewopt.hxx>
41 #include <fmtanchr.hxx>
42 #include "itrform2.hxx"
44 #include "txtcache.hxx"
45 #include <sectfrm.hxx>
46 #include <rootfrm.hxx>
48 #include <sortedobjs.hxx>
49 #include <editeng/tstpitem.hxx>
50 #include <redline.hxx>
51 #include <comphelper/lok.hxx>
52 #include <flyfrms.hxx>
53 #include <frmtool.hxx>
54 #include <layouter.hxx>
56 // Tolerance in formatting and text output
57 #define SLOPPY_TWIPS 5
63 static sal_uInt16 s_nLevel
;
65 FormatLevel() { ++s_nLevel
; }
66 ~FormatLevel() { --s_nLevel
; }
67 static sal_uInt16
GetLevel() { return s_nLevel
; }
68 static bool LastLevel() { return 10 < s_nLevel
; }
73 sal_uInt16
FormatLevel::s_nLevel
= 0;
75 void ValidateText( SwFrame
*pFrame
) // Friend of frame
77 if ( ( ! pFrame
->IsVertical() &&
78 pFrame
->getFrameArea().Width() == pFrame
->GetUpper()->getFramePrintArea().Width() ) ||
79 ( pFrame
->IsVertical() &&
80 pFrame
->getFrameArea().Height() == pFrame
->GetUpper()->getFramePrintArea().Height() ) )
82 pFrame
->setFrameAreaSizeValid(true);
86 void SwTextFrame::ValidateFrame()
88 vcl::RenderContext
* pRenderContext
= getRootFrame()->GetCurrShell()->GetOut();
89 // Validate surroundings to avoid oscillation
90 SwSwapIfSwapped
swap( this );
92 if ( !IsInFly() && !IsInTab() )
93 { // Only validate 'this' when inside a fly, the rest should actually only be
94 // needed for footnotes, which do not exist in flys.
95 SwSectionFrame
* pSct
= FindSctFrame();
98 if( !pSct
->IsColLocked() )
104 SwFrame
*pUp
= GetUpper();
105 pUp
->Calc(pRenderContext
);
109 ValidateText( this );
111 // We at least have to save the MustFit flag!
112 assert(HasPara() && "ResetPreps(), missing ParaPortion, SwCache bug?");
113 SwParaPortion
*pPara
= GetPara();
114 const bool bMustFit
= pPara
->IsPrepMustFit();
116 pPara
->SetPrepMustFit( bMustFit
);
119 // After a RemoveFootnote the BodyFrame and all Frames contained within it, need to be
120 // recalculated, so that the DeadLine is right.
121 // First we search outwards, on the way back we calculate everything.
122 static void ValidateBodyFrame_( SwFrame
*pFrame
)
124 vcl::RenderContext
* pRenderContext
= pFrame
? pFrame
->getRootFrame()->GetCurrShell()->GetOut() : nullptr;
125 if( !pFrame
|| pFrame
->IsCellFrame() )
128 if( !pFrame
->IsBodyFrame() && pFrame
->GetUpper() )
129 ValidateBodyFrame_( pFrame
->GetUpper() );
130 if( !pFrame
->IsSctFrame() )
131 pFrame
->Calc(pRenderContext
);
134 const bool bOld
= static_cast<SwSectionFrame
*>(pFrame
)->IsContentLocked();
135 static_cast<SwSectionFrame
*>(pFrame
)->SetContentLock( true );
136 pFrame
->Calc(pRenderContext
);
138 static_cast<SwSectionFrame
*>(pFrame
)->SetContentLock( false );
142 void SwTextFrame::ValidateBodyFrame()
144 SwSwapIfSwapped
swap( this );
146 // See comment in ValidateFrame()
147 if ( !IsInFly() && !IsInTab() &&
148 !( IsInSct() && FindSctFrame()->Lower()->IsColumnFrame() ) )
149 ValidateBodyFrame_( GetUpper() );
152 bool SwTextFrame::GetDropRect_( SwRect
&rRect
) const
154 SwSwapIfNotSwapped
swap(const_cast<SwTextFrame
*>(this));
156 OSL_ENSURE( HasPara(), "SwTextFrame::GetDropRect_: try again next year." );
157 SwTextSizeInfo
aInf( const_cast<SwTextFrame
*>(this) );
158 SwTextMargin
aLine( const_cast<SwTextFrame
*>(this), &aInf
);
159 if( aLine
.GetDropLines() )
161 rRect
.Top( aLine
.Y() );
162 rRect
.Left( aLine
.GetLineStart() );
163 rRect
.Height( aLine
.GetDropHeight() );
164 rRect
.Width( aLine
.GetDropLeft() );
166 if ( IsRightToLeft() )
167 SwitchLTRtoRTL( rRect
);
170 SwitchHorizontalToVertical( rRect
);
177 bool SwTextFrame::CalcFollow(TextFrameIndex
const nTextOfst
)
179 vcl::RenderContext
* pRenderContext
= getRootFrame()->GetCurrShell()->GetOut();
180 SwSwapIfSwapped
swap( this );
182 OSL_ENSURE( HasFollow(), "CalcFollow: missing Follow." );
184 SwTextFrame
* pMyFollow
= GetFollow();
186 SwParaPortion
*pPara
= GetPara();
187 const bool bFollowField
= pPara
&& pPara
->IsFollowField();
189 if( !pMyFollow
->GetOffset() || pMyFollow
->GetOffset() != nTextOfst
||
190 bFollowField
|| pMyFollow
->IsFieldFollow() ||
191 ( pMyFollow
->IsVertical() && !pMyFollow
->getFramePrintArea().Width() ) ||
192 ( ! pMyFollow
->IsVertical() && !pMyFollow
->getFramePrintArea().Height() ) )
194 #if OSL_DEBUG_LEVEL > 0
195 const SwFrame
*pOldUp
= GetUpper();
198 SwRectFnSet
aRectFnSet(this);
199 SwTwips nOldBottom
= aRectFnSet
.GetBottom(GetUpper()->getFrameArea());
200 SwTwips nMyPos
= aRectFnSet
.GetTop(getFrameArea());
202 const SwPageFrame
*pPage
= nullptr;
203 bool bOldInvaContent
= true;
204 if ( !IsInFly() && GetNext() )
206 pPage
= FindPageFrame();
207 // Minimize (reset if possible) invalidations: see below
208 bOldInvaContent
= pPage
->IsInvalidContent();
211 pMyFollow
->SetOffset_( nTextOfst
);
212 pMyFollow
->SetFieldFollow( bFollowField
);
213 if( HasFootnote() || pMyFollow
->HasFootnote() )
219 pPara
->GetReformat() = SwCharRange();
224 // The footnote area must not get larger
225 SwSaveFootnoteHeight
aSave( FindFootnoteBossFrame( true ), LONG_MAX
);
227 pMyFollow
->CalcFootnoteFlag();
228 if ( !pMyFollow
->GetNext() && !pMyFollow
->HasFootnote() )
229 nOldBottom
= aRectFnSet
.IsVert() ? 0 : LONG_MAX
;
231 // tdf#122892 check flag:
232 // 1. WidowsAndOrphans::FindWidows() determines follow is a widow
233 // 2. SwTextFrame::PrepWidows() calls SetPrepWidows() on master;
234 // if it can spare lines, master truncates one line
235 // 3. SwTextFrame::CalcPreps() on master (below);
236 // unless IsPrepMustFit(), if master hasn't shrunk via 2., it will SetWidow()
237 // 4. loop must exit then, because the follow didn't grow so nothing will ever change
240 if( !FormatLevel::LastLevel() )
242 // If the follow is contained within a column section or column
243 // frame, we need to calculate that first. This is because the
244 // FormatWidthCols() does not work if it is called from MakeAll
245 // of the _locked_ follow.
246 SwSectionFrame
* pSct
= pMyFollow
->FindSctFrame();
247 if( pSct
&& !pSct
->IsAnLower( this ) )
249 if( pSct
->GetFollow() )
250 pSct
->SimpleFormat();
251 else if( ( pSct
->IsVertical() && !pSct
->getFrameArea().Width() ) ||
252 ( ! pSct
->IsVertical() && !pSct
->getFrameArea().Height() ) )
255 // i#11760 - Intrinsic format of follow is controlled.
256 if ( FollowFormatAllowed() )
258 // i#11760 - No nested format of follows, if
259 // text frame is contained in a column frame.
260 // Thus, forbid intrinsic format of follow.
262 bool bIsFollowInColumn
= false;
263 SwFrame
* pFollowUpper
= pMyFollow
->GetUpper();
264 while ( pFollowUpper
)
266 if ( pFollowUpper
->IsColumnFrame() )
268 bIsFollowInColumn
= true;
271 if ( pFollowUpper
->IsPageFrame() ||
272 pFollowUpper
->IsFlyFrame() )
276 pFollowUpper
= pFollowUpper
->GetUpper();
278 if ( bIsFollowInColumn
)
280 pMyFollow
->ForbidFollowFormat();
284 pMyFollow
->Calc(pRenderContext
);
285 // The Follow can tell from its getFrameArea().Height() that something went wrong
286 OSL_ENSURE( !pMyFollow
->GetPrev(), "SwTextFrame::CalcFollow: cheesy follow" );
287 if( pMyFollow
->GetPrev() )
289 pMyFollow
->Prepare();
290 pMyFollow
->Calc(pRenderContext
);
291 OSL_ENSURE( !pMyFollow
->GetPrev(), "SwTextFrame::CalcFollow: very cheesy follow" );
294 // i#11760 - Reset control flag for follow format.
295 pMyFollow
->AllowFollowFormat();
298 // Make sure that the Follow gets painted
299 pMyFollow
->SetCompletePaint();
303 // As long as the Follow requests lines due to Orphans, it is
304 // passed these and is formatted again if possible
305 if( pPara
&& pPara
->IsPrepWidows() )
311 if( HasFootnote() || pMyFollow
->HasFootnote() )
317 pPara
->GetReformat() = SwCharRange();
322 if ( pPage
&& !bOldInvaContent
)
323 pPage
->ValidateContent();
325 #if OSL_DEBUG_LEVEL > 0
326 OSL_ENSURE( pOldUp
== GetUpper(), "SwTextFrame::CalcFollow: heavy follow" );
329 const tools::Long nRemaining
=
330 - aRectFnSet
.BottomDist( GetUpper()->getFrameArea(), nOldBottom
);
331 if ( nRemaining
> 0 &&
332 nRemaining
!= ( aRectFnSet
.IsVert() ?
333 nMyPos
- getFrameArea().Right() :
334 getFrameArea().Top() - nMyPos
) )
343 void SwTextFrame::MakePos()
345 Point aOldPos
= getFrameArea().Pos();
348 // Recalc split flys if our position changed.
349 if (aOldPos
!= getFrameArea().Pos())
351 // Find the master frame.
352 const SwTextFrame
* pMaster
= this;
353 while (pMaster
->IsFollow())
355 pMaster
= pMaster
->FindMaster();
357 // Find which flys are effectively anchored to this frame.
358 for (const auto& pFly
: pMaster
->GetSplitFlyDrawObjs())
360 SwTextFrame
* pFlyAnchor
= pFly
->FindAnchorCharFrame();
361 if (pFlyAnchor
!= this)
365 // Possibly this fly was positioned relative to us, invalidate its position now that our
366 // position is changed.
367 SwPageFrame
* pPageFrame
= pFly
->FindPageFrame();
368 bool bFlyNeedsPositioning
= false;
369 bool bFlyPageMismatch
= false;
372 // Was the position just adjusted to be inside the page frame?
373 bFlyNeedsPositioning
= pFly
->getFrameArea().Pos() == pPageFrame
->getFrameArea().Pos();
374 // Is the fly on a page different than the anchor frame?
375 bFlyPageMismatch
= pPageFrame
!= FindPageFrame();
377 if (bFlyNeedsPositioning
|| bFlyPageMismatch
)
379 // Not really positioned, unlock the position once to allow a recalc.
380 pFly
->UnlockPosition();
382 pFly
->InvalidatePos();
386 // Inform LOK clients about change in position of redlines (if any)
387 if(!comphelper::LibreOfficeKit::isActive())
390 SwTextNode
const* pTextNode
= GetTextNodeFirst();
391 const SwRedlineTable
& rTable
= pTextNode
->getIDocumentRedlineAccess().GetRedlineTable();
392 for (SwRedlineTable::size_type nRedlnPos
= 0; nRedlnPos
< rTable
.size(); ++nRedlnPos
)
394 SwRangeRedline
* pRedln
= rTable
[nRedlnPos
];
395 if (pTextNode
->GetIndex() == pRedln
->GetPoint()->GetNode().GetIndex())
397 pRedln
->MaybeNotifyRedlinePositionModification(getFrameArea().Top());
399 && pRedln
->GetType() == RedlineType::Delete
400 && pRedln
->GetPoint()->GetNode() != pRedln
->GetMark()->GetNode())
402 pTextNode
= pRedln
->End()->GetNode().GetTextNode();
408 void SwTextFrame::AdjustFrame( const SwTwips nChgHght
, bool bHasToFit
)
410 vcl::RenderContext
* pRenderContext
= getRootFrame()->GetCurrShell()->GetOut();
413 if( GetOffset() && !IsFollow() ) // A scrolled paragraph (undersized)
415 SetUndersized( nChgHght
== 0 || bHasToFit
);
418 // AdjustFrame is called with a swapped frame during
419 // formatting but the frame is not swapped during FormatEmpty
420 SwSwapIfSwapped
swap( this );
421 SwRectFnSet
aRectFnSet(this);
423 // The Frame's size variable is incremented by Grow or decremented by Shrink.
424 // If the size cannot change, nothing should happen!
427 SwTwips nChgHeight
= nChgHght
;
428 if( nChgHght
&& !bHasToFit
)
430 if( IsInFootnote() && !IsInSct() )
432 SwTwips nReal
= Grow( nChgHght
, true );
433 if( nReal
< nChgHght
)
435 SwTwips nBot
= aRectFnSet
.YInc( aRectFnSet
.GetBottom(getFrameArea()),
437 SwFrame
* pCont
= FindFootnoteFrame()->GetUpper();
439 if( aRectFnSet
.BottomDist( pCont
->getFrameArea(), nBot
) > 0 )
441 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
442 aRectFnSet
.AddBottom( aFrm
, nChgHght
);
444 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
446 if( aRectFnSet
.IsVert() )
448 aPrt
.AddWidth(nChgHght
);
452 aPrt
.AddHeight(nChgHght
);
464 // If one of the Upper is a Fly, it's very likely that this fly changes its
465 // position by the Grow. Therefore, my position has to be corrected also or
466 // the check further down is not meaningful.
467 // The predecessors need to be calculated, so that the position can be
468 // calculated correctly.
471 SwFrame
*pPre
= GetUpper()->Lower();
473 { pPre
->Calc(pRenderContext
);
474 pPre
= pPre
->GetNext();
475 } while ( pPre
&& pPre
!= this );
477 const Point
aOldPos( getFrameArea().Pos() );
479 if ( aOldPos
!= getFrameArea().Pos() )
481 InvalidateObjs(false);
486 // A Grow() is always accepted by the Layout, even if the
487 // FixSize of the surrounding layout frame should not allow it.
488 // We text for this case and correct the values.
489 // The Frame must NOT be shrunk further than its size permits
490 // even in the case of an emergency.
494 OSL_ENSURE( ! IsSwapped(),"Swapped frame while calculating nRstHeight" );
497 nRstHeight
= GetUpper()->getFrameArea().Left()
498 + GetUpper()->getFramePrintArea().Left()
499 + GetUpper()->getFramePrintArea().Width()
500 - getFrameArea().Left();
502 nRstHeight
= getFrameArea().Left() + getFrameArea().Width() -
503 ( GetUpper()->getFrameArea().Left() + GetUpper()->getFramePrintArea().Left() );
506 nRstHeight
= GetUpper()->getFrameArea().Top()
507 + GetUpper()->getFramePrintArea().Top()
508 + GetUpper()->getFramePrintArea().Height()
509 - getFrameArea().Top();
511 // We can get a bit of space in table cells, because there could be some
512 // left through a vertical alignment to the top.
513 // Assure that first lower in upper is the current one or is valid.
515 ( GetUpper()->Lower() == this ||
516 GetUpper()->Lower()->isFrameAreaDefinitionValid() ) )
518 tools::Long nAdd
= aRectFnSet
.YDiff( aRectFnSet
.GetTop(GetUpper()->Lower()->getFrameArea()),
519 aRectFnSet
.GetPrtTop(*GetUpper()) );
520 OSL_ENSURE( nAdd
>= 0, "Ey" );
524 // nRstHeight < 0 means that the TextFrame is located completely outside of its Upper.
525 // This can happen, if it's located within a FlyAtContentFrame, which changed sides by a
526 // Grow(). In such a case, it's wrong to execute the following Grow().
527 // In the case of a bug, we end up with an infinite loop.
528 SwTwips nFrameHeight
= aRectFnSet
.GetHeight(getFrameArea());
529 SwTwips nPrtHeight
= aRectFnSet
.GetHeight(getFramePrintArea());
531 if( nRstHeight
< nFrameHeight
)
533 // It can be that I have the right size, but the Upper is too small and can get me some room
534 if( ( nRstHeight
>= 0 || ( IsInFootnote() && IsInSct() ) ) && !bHasToFit
)
535 nRstHeight
+= GetUpper()->Grow( nFrameHeight
- nRstHeight
);
536 // In column sections we do not want to get too big or else more areas are created by
537 // GetNextSctLeaf. Instead, we shrink and remember bUndersized, so that FormatWidthCols
538 // can calculate the right column size.
539 if ( nRstHeight
< nFrameHeight
)
541 if( bHasToFit
|| !IsMoveable() ||
542 ( IsInSct() && !FindSctFrame()->MoveAllowed(this) ) )
544 SetUndersized( true );
545 Shrink( std::min( ( nFrameHeight
- nRstHeight
), nPrtHeight
) );
548 SetUndersized( false );
551 else if( nChgHeight
)
553 if( nRstHeight
- nFrameHeight
< nChgHeight
)
554 nChgHeight
= nRstHeight
- nFrameHeight
;
563 css::uno::Sequence
< css::style::TabStop
> SwTextFrame::GetTabStopInfo( SwTwips CurrentPos
)
565 SwTextFormatInfo
aInf( getRootFrame()->GetCurrShell()->GetOut(), this );
566 SwTextFormatter
aLine( this, &aInf
);
567 SwTextCursor
TextCursor( this, &aInf
);
568 const Point
aCharPos( TextCursor
.GetTopLeft() );
570 SwTwips nRight
= aLine
.Right();
571 CurrentPos
-= aCharPos
.X();
573 // get current tab stop information stored in the Frame
574 const SvxTabStop
*pTS
= aLine
.GetLineInfo().GetTabStop( CurrentPos
, nRight
);
581 // copy tab stop information into a Sequence, which only contains one element.
582 css::style::TabStop ts
;
583 ts
.Position
= pTS
->GetTabPos();
584 ts
.DecimalChar
= pTS
->GetDecimal();
585 ts
.FillChar
= pTS
->GetFill();
586 switch( pTS
->GetAdjustment() )
588 case SvxTabAdjust::Left
: ts
.Alignment
= css::style::TabAlign_LEFT
; break;
589 case SvxTabAdjust::Center
: ts
.Alignment
= css::style::TabAlign_CENTER
; break;
590 case SvxTabAdjust::Right
: ts
.Alignment
= css::style::TabAlign_RIGHT
; break;
591 case SvxTabAdjust::Decimal
: ts
.Alignment
= css::style::TabAlign_DECIMAL
; break;
592 case SvxTabAdjust::Default
: ts
.Alignment
= css::style::TabAlign_DEFAULT
; break;
593 default: break; // prevent warning
599 // AdjustFollow expects the following situation:
600 // The SwTextIter points to the lower end of the Master, the Offset is set in the Follow.
601 // nOffset holds the Offset in the text string, from which the Master closes
602 // and the Follow starts.
603 // If it's 0, the FollowFrame is deleted.
604 void SwTextFrame::AdjustFollow_( SwTextFormatter
&rLine
,
605 const TextFrameIndex nOffset
, const TextFrameIndex nEnd
,
606 const sal_uInt8 nMode
)
608 SwFrameSwapper
aSwapper( this, false );
610 // We got the rest of the text mass: Delete all Follows
611 // DummyPortions() are a special case.
612 // Special cases are controlled by parameter <nMode>.
613 bool bDontJoin
= nMode
& 1;
614 if( HasFollow() && !bDontJoin
&& nOffset
== nEnd
)
618 if( GetFollow()->IsLocked() )
620 // this can happen when follow calls pMaster->GetFormatted()
621 SAL_INFO("sw.core", "+SwTextFrame::JoinFrame: Follow is locked." );
624 if (GetFollow()->IsDeleteForbidden())
627 if (HasNonLastSplitFlyDrawObj())
629 // If a fly frame is anchored to us that has a follow, then don't join the anchor.
630 // First those fly frames have to be joined.
640 // Dancing on the volcano: We'll just format the last line quickly
641 // for the QuoVadis stuff.
642 // The Offset can move of course:
643 const TextFrameIndex nNewOfst
= (IsInFootnote() && (!GetIndNext() || HasFollow()))
644 ? rLine
.FormatQuoVadis(nOffset
) : nOffset
;
646 bool bHasNonLastSplitFlyDrawObj
= false;
647 if (GetFollow() && GetOffset() == GetFollow()->GetOffset())
649 bHasNonLastSplitFlyDrawObj
= HasNonLastSplitFlyDrawObj();
654 // We steal text mass from our Follows
655 // It can happen that we have to join some of them
656 while( GetFollow() && GetFollow()->GetFollow() &&
657 nNewOfst
>= GetFollow()->GetFollow()->GetOffset() )
659 if (bHasNonLastSplitFlyDrawObj
)
661 // A non-last split fly is anchored to us, don't move content from the last frame to
662 // this one and don't join.
670 if (IsEmptyMasterWithSplitFly())
672 // A split fly is anchored to us, don't move content from the follow frame to this one.
679 if (!bDontJoin
&& bHasNonLastSplitFlyDrawObj
)
681 // A non-last split fly is anchored to us, our follow is the last one in the text frame
682 // chain. No move of text from that follow to this text frame.
687 GetFollow()->ManipOfst(TextFrameIndex(0));
689 if ( CalcFollow( nNewOfst
) ) // CalcFollow only at the end, we do a SetOffset there
690 rLine
.SetOnceMore( true );
694 SwContentFrame
*SwTextFrame::JoinFrame()
696 OSL_ENSURE( GetFollow(), "+SwTextFrame::JoinFrame: no follow" );
697 SwTextFrame
*pFoll
= GetFollow();
699 SwTextFrame
*pNxt
= pFoll
->GetFollow();
701 // All footnotes of the to-be-destroyed Follow are relocated to us
702 TextFrameIndex nStart
= pFoll
->GetOffset();
703 if ( pFoll
->HasFootnote() )
705 SwFootnoteBossFrame
*pFootnoteBoss
= nullptr;
706 SwFootnoteBossFrame
*pEndBoss
= nullptr;
707 SwTextNode
const* pNode(nullptr);
708 sw::MergedAttrIter
iter(*pFoll
);
709 for (SwTextAttr
const* pHt
= iter
.NextAttr(&pNode
); pHt
; pHt
= iter
.NextAttr(&pNode
))
711 if (RES_TXTATR_FTN
== pHt
->Which()
712 && nStart
<= pFoll
->MapModelToView(pNode
, pHt
->GetStart()))
714 if (pHt
->GetFootnote().IsEndNote())
717 pEndBoss
= pFoll
->FindFootnoteBossFrame();
718 SwFootnoteBossFrame::ChangeFootnoteRef( pFoll
, static_cast<const SwTextFootnote
*>(pHt
), this );
723 pFootnoteBoss
= pFoll
->FindFootnoteBossFrame( true );
724 SwFootnoteBossFrame::ChangeFootnoteRef( pFoll
, static_cast<const SwTextFootnote
*>(pHt
), this );
732 else if ( pFoll
->isFramePrintAreaValid() ||
733 pFoll
->isFrameAreaSizeValid() )
735 pFoll
->CalcFootnoteFlag();
736 OSL_ENSURE( !pFoll
->HasFootnote(), "Missing FootnoteFlag." );
740 pFoll
->MoveFlyInCnt( this, nStart
, TextFrameIndex(COMPLETE_STRING
) );
741 pFoll
->SetFootnote( false );
743 // Notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
744 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
745 // and relation CONTENT_FLOWS_TO for current previous paragraph, which
746 // is <this>, will change.
747 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
749 SwViewShell
* pViewShell( pFoll
->getRootFrame()->GetCurrShell() );
750 if ( pViewShell
&& pViewShell
->GetLayout() &&
751 pViewShell
->GetLayout()->IsAnyShellAccessible() )
753 auto pNext
= pFoll
->FindNextCnt( true );
754 pViewShell
->InvalidateAccessibleParaFlowRelation(
755 pNext
? pNext
->DynCastTextFrame() : nullptr,
763 SwFrame::DestroyFrame(pFoll
);
767 void SwTextFrame::SplitFrame(TextFrameIndex
const nTextPos
)
769 SwSwapIfSwapped
swap( this );
771 // The Paste sends a Modify() to me
772 // I lock myself, so that my data does not disappear
773 TextFrameLockGuard
aLock( this );
774 SwTextFrame
*const pNew
= static_cast<SwTextFrame
*>(GetTextNodeFirst()->MakeFrame(this));
776 pNew
->SetFollow( GetFollow() );
779 pNew
->Paste( GetUpper(), GetNext() );
781 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
782 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
783 // and relation CONTENT_FLOWS_TO for current previous paragraph, which
784 // is <this>, will change.
785 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
787 SwViewShell
* pViewShell( pNew
->getRootFrame()->GetCurrShell() );
788 if ( pViewShell
&& pViewShell
->GetLayout() &&
789 pViewShell
->GetLayout()->IsAnyShellAccessible() )
791 auto pNext
= pNew
->FindNextCnt( true );
792 pViewShell
->InvalidateAccessibleParaFlowRelation(
793 pNext
? pNext
->DynCastTextFrame() : nullptr,
799 // If footnotes end up in pNew bz our actions, we need
800 // to re-register them
803 SwFootnoteBossFrame
*pFootnoteBoss
= nullptr;
804 SwFootnoteBossFrame
*pEndBoss
= nullptr;
805 SwTextNode
const* pNode(nullptr);
806 sw::MergedAttrIter
iter(*this);
807 for (SwTextAttr
const* pHt
= iter
.NextAttr(&pNode
); pHt
; pHt
= iter
.NextAttr(&pNode
))
809 if (RES_TXTATR_FTN
== pHt
->Which()
810 && nTextPos
<= MapModelToView(pNode
, pHt
->GetStart()))
812 if (pHt
->GetFootnote().IsEndNote())
815 pEndBoss
= FindFootnoteBossFrame();
816 SwFootnoteBossFrame::ChangeFootnoteRef( this, static_cast<const SwTextFootnote
*>(pHt
), pNew
);
821 pFootnoteBoss
= FindFootnoteBossFrame( true );
822 SwFootnoteBossFrame::ChangeFootnoteRef( this, static_cast<const SwTextFootnote
*>(pHt
), pNew
);
824 pNew
->SetFootnote( true );
832 CalcFootnoteFlag( nTextPos
- TextFrameIndex(1) );
833 OSL_ENSURE( !HasFootnote(), "Missing FootnoteFlag." );
837 MoveFlyInCnt( pNew
, nTextPos
, TextFrameIndex(COMPLETE_STRING
) );
839 // No SetOffset or CalcFollow, because an AdjustFollow follows immediately anyways
841 pNew
->ManipOfst( nTextPos
);
844 void SwTextFrame::SetOffset_(TextFrameIndex
const nNewOfst
)
846 // We do not need to invalidate our Follow.
847 // We are a Follow, get formatted right away and call
848 // SetOffset() from there
850 SwParaPortion
*pPara
= GetPara();
853 SwCharRange
&rReformat
= pPara
->GetReformat();
854 rReformat
.Start() = TextFrameIndex(0);
855 rReformat
.Len() = TextFrameIndex(GetText().getLength());
856 pPara
->SetDelta(sal_Int32(rReformat
.Len()));
861 bool SwTextFrame::CalcPreps()
863 OSL_ENSURE( ! IsVertical() || ! IsSwapped(), "SwTextFrame::CalcPreps with swapped frame" );
864 SwRectFnSet
aRectFnSet(this);
866 SwParaPortion
*pPara
= GetPara();
869 const bool bPrep
= pPara
->IsPrep();
870 const bool bPrepWidows
= pPara
->IsPrepWidows();
871 const bool bPrepAdjust
= pPara
->IsPrepAdjust();
872 const bool bPrepMustFit
= pPara
->IsPrepMustFit();
876 if( bPrep
&& !pPara
->GetReformat().Len() )
878 // PrepareHint::Widows means that the orphans rule got activated in the Follow.
879 // In unfortunate cases we could also have a PrepAdjust!
884 OSL_ENSURE( GetFollow(), "+SwTextFrame::CalcPreps: no credits" );
888 // We need to prepare for two cases:
889 // We were able to hand over a few lines to the Follow
890 // -> we need to shrink
891 // or we need to go on the next page
892 // -> we let our Frame become too big
894 SwTwips nChgHeight
= GetParHeight();
895 if( nChgHeight
>= aRectFnSet
.GetHeight(getFramePrintArea()) )
899 GetFollow()->SetJustWidow( true );
900 GetFollow()->Prepare();
902 else if ( aRectFnSet
.IsVert() )
905 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
906 aFrm
.Width( aFrm
.Width() + aFrm
.Left() );
911 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
912 aPrt
.Width( aPrt
.Width() + getFrameArea().Left() );
919 // nTmp should be very large, but not so large as to cause overflow later (e.g.,
920 // GetFrameOfModify in sw/source/core/layout/frmtool.cxx calculates nCurrentDist
921 // from, among others, the square of aDiff.getY(), which can be close to nTmp);
922 // the previously used value TWIPS_MAX/2 (i.e., (LONG_MAX - 1)/2) depended on
923 // the range of 'long', while the value (SAL_MAX_INT32 - 1)/2 (which matches the
924 // old value on platforms where 'long' is 'sal_Int32') is empirically shown to
925 // be large enough in practice even on platforms where 'long' is 'sal_Int64':
926 SwTwips
const nTmp
= sw::WIDOW_MAGIC
- (getFrameArea().Top()+10000);
927 SwTwips nDiff
= nTmp
- getFrameArea().Height();
930 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
935 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
936 aPrt
.Height( aPrt
.Height() + nDiff
);
944 OSL_ENSURE( nChgHeight
< aRectFnSet
.GetHeight(getFramePrintArea()),
945 "+SwTextFrame::CalcPrep: want to shrink" );
947 nChgHeight
= aRectFnSet
.GetHeight(getFramePrintArea()) - nChgHeight
;
949 GetFollow()->SetJustWidow( true );
950 GetFollow()->Prepare();
951 Shrink( nChgHeight
);
952 SwRect
&rRepaint
= pPara
->GetRepaint();
954 if ( aRectFnSet
.IsVert() )
956 SwRect
aRepaint( getFrameArea().Pos() + getFramePrintArea().Pos(), getFramePrintArea().SSize() );
957 SwitchVerticalToHorizontal( aRepaint
);
958 rRepaint
.Chg( aRepaint
.Pos(), aRepaint
.SSize() );
961 rRepaint
.Chg( getFrameArea().Pos() + getFramePrintArea().Pos(), getFramePrintArea().SSize() );
963 if( 0 >= rRepaint
.Width() )
968 else if ( bPrepAdjust
)
972 if( !CalcPrepFootnoteAdjust() )
976 SwTextLineAccess
aAccess( this );
977 aAccess
.GetPara()->SetPrepMustFit(true);
984 SwSwapIfNotSwapped
swap( this );
986 SwTextFormatInfo
aInf( getRootFrame()->GetCurrShell()->GetOut(), this );
987 SwTextFormatter
aLine( this, &aInf
);
989 WidowsAndOrphans
aFrameBreak( this );
990 // Whatever the attributes say: we split the paragraph in
991 // MustFit case if necessary
994 aFrameBreak
.SetKeep( false );
995 aFrameBreak
.ClrOrphLines();
997 // Before calling FormatAdjust, we need to make sure
998 // that the lines protruding at the bottom get indeed
1000 bool bBreak
= aFrameBreak
.IsBreakNowWidAndOrp( aLine
);
1002 while( !bBreak
&& aLine
.Next() )
1004 bBreak
= aFrameBreak
.IsBreakNowWidAndOrp( aLine
);
1008 // We run into troubles: when TruncLines is called, the
1009 // conditions in IsInside change immediately such that
1010 // IsBreakNow can return different results.
1011 // For this reason, we tell rFrameBreak that the
1012 // end is reached at the location of rLine.
1013 // Let's see if it works ...
1015 aFrameBreak
.SetRstHeight( aLine
);
1016 FormatAdjust( aLine
, aFrameBreak
, TextFrameIndex(aInf
.GetText().getLength()), aInf
.IsStop() );
1022 FormatAdjust( aLine
, aFrameBreak
,
1023 TextFrameIndex(aInf
.GetText().getLength()), aInf
.IsStop() );
1025 else if ( !aFrameBreak
.IsKeepAlways() )
1027 // We delete a line before the Master, because the Follow
1028 // could hand over a line
1029 const SwCharRange
aFollowRg(GetFollow()->GetOffset(), TextFrameIndex(1));
1030 pPara
->GetReformat() += aFollowRg
;
1031 // We should continue!
1037 // A final check, if FormatAdjust() didn't help we need to
1041 const SwTwips nMust
= aRectFnSet
.GetPrtBottom(*GetUpper());
1042 const SwTwips nIs
= aRectFnSet
.GetBottom(getFrameArea());
1044 if( aRectFnSet
.IsVert() && nIs
< nMust
)
1046 Shrink( nMust
- nIs
);
1048 if( getFramePrintArea().Width() < 0 )
1050 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
1054 SetUndersized( true );
1056 else if ( ! aRectFnSet
.IsVert() && nIs
> nMust
)
1058 Shrink( nIs
- nMust
);
1060 if( getFramePrintArea().Height() < 0 )
1062 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
1066 SetUndersized( true );
1071 pPara
->SetPrepMustFit( bPrepMustFit
);
1075 // Move the as-character objects - footnotes must be moved by RemoveFootnote!
1076 void SwTextFrame::ChangeOffset( SwTextFrame
* pFrame
, TextFrameIndex nNew
)
1078 if( pFrame
->GetOffset() < nNew
)
1079 pFrame
->MoveFlyInCnt( this, TextFrameIndex(0), nNew
);
1080 else if( pFrame
->GetOffset() > nNew
)
1081 MoveFlyInCnt( pFrame
, nNew
, TextFrameIndex(COMPLETE_STRING
) );
1084 void SwTextFrame::FormatAdjust( SwTextFormatter
&rLine
,
1085 WidowsAndOrphans
&rFrameBreak
,
1086 TextFrameIndex
const nStrLen
,
1089 SwSwapIfNotSwapped
swap( this );
1091 SwParaPortion
*pPara
= rLine
.GetInfo().GetParaPortion();
1093 TextFrameIndex nEnd
= rLine
.GetStart();
1095 const bool bHasToFit
= pPara
->IsPrepMustFit();
1097 // The StopFlag is set by footnotes which want to go onto the next page
1098 // Call base class method <SwTextFrameBreak::IsBreakNow(..)>
1099 // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break,
1100 // even if due to widow rule no enough lines exists.
1101 sal_uInt8 nNew
= ( !GetFollow() &&
1105 ? ( rLine
.GetLineNr() > 1 &&
1106 !rFrameBreak
.IsInside( rLine
) )
1107 : rFrameBreak
.IsBreakNow( rLine
) ) ) )
1110 SwTextFormatInfo
& rInf
= rLine
.GetInfo();
1111 if (nNew
== 0 && !nStrLen
&& !rInf
.GetTextFly().IsOn() && IsEmptyWithSplitFly())
1113 // Empty paragraph, so IsBreakNow() is not called, but we should split the fly portion and
1114 // the paragraph marker.
1119 // no split of text frame, which only contains an as-character anchored object
1120 bool bOnlyContainsAsCharAnchoredObj
=
1121 !IsFollow() && nStrLen
== TextFrameIndex(1) &&
1122 GetDrawObjs() && GetDrawObjs()->size() == 1 &&
1123 (*GetDrawObjs())[0]->GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR
;
1125 // Still try split text frame if we have columns.
1127 bOnlyContainsAsCharAnchoredObj
= false;
1129 if ( nNew
&& bOnlyContainsAsCharAnchoredObj
)
1139 const SwFrame
*pBodyFrame
= FindBodyFrame();
1141 const tools::Long nBodyHeight
= pBodyFrame
? ( IsVertical() ?
1142 pBodyFrame
->getFrameArea().Width() :
1143 pBodyFrame
->getFrameArea().Height() ) : 0;
1145 // If the current values have been calculated, show that they
1147 pPara
->GetReformat() = SwCharRange();
1148 bool bDelta
= pPara
->GetDelta() != 0;
1151 if( rLine
.IsStop() )
1153 rLine
.TruncLines( true );
1157 // FindBreak truncates the last line
1158 if( !rFrameBreak
.FindBreak( this, rLine
, bHasToFit
) )
1160 // If we're done formatting, we set nEnd to the end.
1161 // AdjustFollow might execute JoinFrame() because of this.
1162 // Else, nEnd is the end of the last line in the Master.
1163 TextFrameIndex nOld
= nEnd
;
1164 // Make sure content from the last floating table anchor is not shifted to previous anchors.
1165 if (!HasNonLastSplitFlyDrawObj())
1167 nEnd
= rLine
.GetEnd();
1171 if( nNew
&& nOld
< nEnd
)
1172 RemoveFootnote( nOld
, nEnd
- nOld
);
1173 ChangeOffset( GetFollow(), nEnd
);
1175 GetFollow()->ManipOfst( nEnd
);
1179 { // If we pass over lines, we must not call Join in Follows, instead we even
1180 // need to create a Follow.
1181 // We also need to do this if the whole mass of text remains in the Master,
1182 // because a hard line break could necessitate another line (without text mass)!
1183 TextFrameIndex
const nOld(nEnd
);
1184 nEnd
= rLine
.GetEnd();
1187 // Another case for not joining the follow:
1188 // Text frame has no content, but a numbering. Then, do *not* join.
1189 // Example of this case: When an empty, but numbered paragraph
1190 // at the end of page is completely displaced by a fly frame.
1191 // Thus, the text frame introduced a follow by a
1192 // <SwTextFrame::SplitFrame(..)> - see below. The follow then shows
1193 // the numbering and must stay.
1194 if ( GetFollow()->GetOffset() != nEnd
||
1195 GetFollow()->IsFieldFollow() ||
1196 (nStrLen
== TextFrameIndex(0) && GetTextNodeForParaProps()->GetNumRule()))
1200 else if (FindTabFrame() && nEnd
> TextFrameIndex(0) &&
1201 rLine
.GetInfo().GetChar(nEnd
- TextFrameIndex(1)) == CH_BREAK
)
1203 // We are in a table, the paragraph has a follow and the text
1204 // ends with a hard line break. Don't join the follow just
1205 // because the follow would have no content, we may still need it
1206 // for the paragraph mark.
1209 // move footnotes if the follow is kept - if RemoveFootnote() is
1210 // called in next format iteration, it will be with the *new*
1211 // offset so no effect!
1212 if (nNew
&& nOld
< nEnd
)
1214 RemoveFootnote(nOld
, nEnd
- nOld
);
1216 ChangeOffset( GetFollow(), nEnd
);
1218 if (HasNonLastSplitFlyDrawObj())
1220 // Make sure content from the last floating table anchor is not shifted to previous
1222 nEnd
= TextFrameIndex(0);
1225 GetFollow()->ManipOfst( nEnd
);
1229 const SwTextNode
* pTextNode
= GetTextNodeForParaProps();
1230 bool bHasVisibleNumRule
= nStrLen
== TextFrameIndex(0) && pTextNode
->GetNumRule();
1232 if (!pTextNode
->HasVisibleNumberingOrBullet())
1234 bHasVisibleNumRule
= false;
1237 // Only split frame, if the frame contains
1238 // content or contains no content, but has a numbering.
1239 // i#84870 - No split, if text frame only contains one
1240 // as-character anchored object.
1241 if ( !bOnlyContainsAsCharAnchoredObj
&&
1242 (nStrLen
> TextFrameIndex(0) ||
1243 bHasVisibleNumRule
)
1250 // If the remaining height changed e.g by RemoveFootnote() we need to
1251 // fill up in order to avoid oscillation.
1252 if( bDummy
&& pBodyFrame
&&
1253 nBodyHeight
< ( IsVertical() ?
1254 pBodyFrame
->getFrameArea().Width() :
1255 pBodyFrame
->getFrameArea().Height() ) )
1256 rLine
.MakeDummyLine();
1259 // In AdjustFrame() we set ourselves via Grow/Shrink
1260 // In AdjustFollow() we set our FollowFrame
1262 const SwTwips nDocPrtTop
= getFrameArea().Top() + getFramePrintArea().Top();
1263 const SwTwips nOldHeight
= getFramePrintArea().SSize().Height();
1264 SwTwips nChg
= rLine
.CalcBottomLine() - nDocPrtTop
- nOldHeight
;
1266 //#i84870# - no shrink of text frame, if it only contains one as-character anchored object.
1267 if ( nChg
< 0 && !bDelta
&& bOnlyContainsAsCharAnchoredObj
)
1272 // Vertical Formatting:
1273 // The (rotated) repaint rectangle's x coordinate refers to the frame.
1274 // If the frame grows (or shirks) the repaint rectangle cannot simply
1275 // be rotated back after formatting, because we use the upper left point
1276 // of the frame for rotation. This point changes when growing/shrinking.
1278 if ( IsVertical() && !IsVertLR() && nChg
)
1280 SwRect
&rRepaint
= pPara
->GetRepaint();
1281 rRepaint
.Left( rRepaint
.Left() - nChg
);
1282 rRepaint
.Width( rRepaint
.Width() - nChg
);
1285 AdjustFrame( nChg
, bHasToFit
);
1287 if( HasFollow() || IsInFootnote() )
1288 AdjustFollow_( rLine
, nEnd
, nStrLen
, nNew
);
1290 pPara
->SetPrepMustFit( false );
1293 // bPrev is set whether Reformat.Start() was called because of Prev().
1294 // Else, we don't know whether we can limit the repaint or not.
1295 bool SwTextFrame::FormatLine( SwTextFormatter
&rLine
, const bool bPrev
)
1297 OSL_ENSURE( ! IsVertical() || IsSwapped(),
1298 "SwTextFrame::FormatLine( rLine, bPrev) with unswapped frame" );
1299 SwParaPortion
*pPara
= rLine
.GetInfo().GetParaPortion();
1300 const SwLineLayout
*pOldCur
= rLine
.GetCurr();
1301 const TextFrameIndex nOldLen
= pOldCur
->GetLen();
1302 const SwTwips nOldAscent
= pOldCur
->GetAscent();
1303 const SwTwips nOldHeight
= pOldCur
->Height();
1304 const SwTwips nOldWidth
= pOldCur
->Width() + pOldCur
->GetHangingMargin();
1305 const bool bOldHyph
= pOldCur
->IsEndHyph();
1306 SwTwips nOldTop
= 0;
1307 SwTwips nOldBottom
= 0;
1308 if( rLine
.GetCurr()->IsClipping() )
1309 rLine
.CalcUnclipped( nOldTop
, nOldBottom
);
1311 TextFrameIndex
const nNewStart
= rLine
.FormatLine( rLine
.GetStart() );
1313 OSL_ENSURE( getFrameArea().Pos().Y() + getFramePrintArea().Pos().Y() == rLine
.GetFirstPos(),
1314 "SwTextFrame::FormatLine: frame leaves orbit." );
1315 OSL_ENSURE( rLine
.GetCurr()->Height(),
1316 "SwTextFrame::FormatLine: line height is zero" );
1318 // The current line break object
1319 const SwLineLayout
*pNew
= rLine
.GetCurr();
1321 bool bUnChg
= nOldLen
== pNew
->GetLen() &&
1322 bOldHyph
== pNew
->IsEndHyph();
1323 if ( bUnChg
&& !bPrev
)
1325 const tools::Long nWidthDiff
= nOldWidth
> pNew
->Width()
1326 ? nOldWidth
- pNew
->Width()
1327 : pNew
->Width() - nOldWidth
;
1329 // we only declare a line as unchanged, if its main values have not
1330 // changed and it is not the last line (!paragraph end symbol!)
1331 bUnChg
= nOldHeight
== pNew
->Height() &&
1332 nOldAscent
== pNew
->GetAscent() &&
1333 nWidthDiff
<= SLOPPY_TWIPS
&&
1337 // Calculate rRepaint
1338 const SwTwips nBottom
= rLine
.Y() + rLine
.GetLineHeight();
1339 SwRepaint
&rRepaint
= pPara
->GetRepaint();
1340 if( bUnChg
&& rRepaint
.Top() == rLine
.Y()
1341 && (bPrev
|| nNewStart
<= pPara
->GetReformat().Start())
1342 && (nNewStart
< TextFrameIndex(GetText().getLength())))
1344 rRepaint
.Top( nBottom
);
1345 rRepaint
.Height( 0 );
1351 if( nOldTop
< rRepaint
.Top() )
1352 rRepaint
.Top( nOldTop
);
1353 if( !rLine
.IsUnclipped() || nOldBottom
> rRepaint
.Bottom() )
1355 rRepaint
.Bottom( nOldBottom
- 1 );
1356 rLine
.SetUnclipped( true );
1359 if( rLine
.GetCurr()->IsClipping() && rLine
.IsFlyInCntBase() )
1361 SwTwips nTmpTop
, nTmpBottom
;
1362 rLine
.CalcUnclipped( nTmpTop
, nTmpBottom
);
1363 if( nTmpTop
< rRepaint
.Top() )
1364 rRepaint
.Top( nTmpTop
);
1365 if( !rLine
.IsUnclipped() || nTmpBottom
> rRepaint
.Bottom() )
1367 rRepaint
.Bottom( nTmpBottom
- 1 );
1368 rLine
.SetUnclipped( true );
1373 if( !rLine
.IsUnclipped() || nBottom
> rRepaint
.Bottom() )
1375 rRepaint
.Bottom( nBottom
- 1 );
1376 rLine
.SetUnclipped( false );
1379 SwTwips nRght
= std::max( nOldWidth
, pNew
->Width() +
1380 pNew
->GetHangingMargin() );
1381 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
1382 const SwViewOption
*pOpt
= pSh
? pSh
->GetViewOptions() : nullptr;
1383 if( pOpt
&& (pOpt
->IsParagraph() || pOpt
->IsLineBreak()) )
1384 nRght
+= ( std::max( nOldAscent
, pNew
->GetAscent() ) );
1386 nRght
+= ( std::max( nOldAscent
, pNew
->GetAscent() ) / 4);
1387 nRght
+= rLine
.GetLeftMargin();
1388 if( rRepaint
.GetOffset() || rRepaint
.GetRightOfst() < nRght
)
1389 rRepaint
.SetRightOfst( nRght
);
1391 // Finally we enlarge the repaint rectangle if we found an underscore
1392 // within our line. 40 Twips should be enough
1393 const bool bHasUnderscore
=
1394 ( rLine
.GetInfo().GetUnderScorePos() < nNewStart
);
1395 if ( bHasUnderscore
|| rLine
.GetCurr()->HasUnderscore() )
1396 rRepaint
.Bottom( rRepaint
.Bottom() + 40 );
1398 const_cast<SwLineLayout
*>(rLine
.GetCurr())->SetUnderscore( bHasUnderscore
);
1401 // Calculating the good ol' nDelta
1402 const sal_Int32 nDiff
= sal_Int32(pNew
->GetLen()) - sal_Int32(nOldLen
);
1403 pPara
->SetDelta(pPara
->GetDelta() - nDiff
);
1406 if( rLine
.IsStop() )
1409 // Absolutely another line
1410 if( rLine
.IsNewLine() )
1413 // Until the String's end?
1414 if (nNewStart
>= TextFrameIndex(GetText().getLength()))
1417 if( rLine
.GetInfo().IsShift() )
1420 // Reached the Reformat's end?
1421 const TextFrameIndex nEnd
= pPara
->GetReformat().Start() +
1422 pPara
->GetReformat().Len();
1424 if( nNewStart
<= nEnd
)
1427 return 0 != pPara
->GetDelta();
1430 void SwTextFrame::Format_( SwTextFormatter
&rLine
, SwTextFormatInfo
&rInf
,
1431 const bool bAdjust
)
1433 OSL_ENSURE( ! IsVertical() || IsSwapped(),"SwTextFrame::Format_ with unswapped frame" );
1435 SwParaPortion
*pPara
= rLine
.GetInfo().GetParaPortion();
1436 rLine
.SetUnclipped( false );
1438 const OUString
& rString
= GetText();
1439 const TextFrameIndex
nStrLen(rString
.getLength());
1441 SwCharRange
&rReformat
= pPara
->GetReformat();
1442 SwRepaint
&rRepaint
= pPara
->GetRepaint();
1443 std::unique_ptr
<SwRepaint
> pFreeze
;
1445 // Due to performance reasons we set rReformat to COMPLETE_STRING in Init()
1446 // In this case we adjust rReformat
1447 if( rReformat
.Len() > nStrLen
)
1448 rReformat
.Len() = nStrLen
;
1450 if( rReformat
.Start() + rReformat
.Len() > nStrLen
)
1451 rReformat
.Len() = nStrLen
- rReformat
.Start();
1454 if( GetOffset() && !IsFollow() )
1457 nOldBottom
= rLine
.Y();
1462 rLine
.CharToLine( rReformat
.Start() );
1464 // When inserting or removing a Space, words can be moved out of the edited
1465 // line and into the preceding line, hence the preceding line must be
1466 // formatted as well.
1467 // Optimization: If rReformat starts after the first word of the line,
1468 // this line cannot possibly influence the previous one.
1469 // ...Turns out that unfortunately it can: Text size changes + FlyFrames;
1470 // the feedback can affect multiple lines (Frames!)!
1473 // FME: Yes, consider this case: "(word )" has to go to the next line
1474 // because ")" is a forbidden character at the beginning of a line although
1475 // "(word" would still fit on the previous line. Adding text right in front
1476 // of ")" would not trigger a reformatting of the previous line. Adding 1
1477 // to the result of FindBrk() does not solve the problem in all cases,
1478 // nevertheless it should be sufficient.
1479 bool bPrev
= rLine
.GetPrev() &&
1480 (FindBrk(rString
, rLine
.GetStart(), rReformat
.Start() + TextFrameIndex(1))
1483 >= rReformat
.Start() ||
1484 rLine
.GetCurr()->IsRest() );
1487 while( rLine
.Prev() )
1488 if( rLine
.GetCurr()->GetLen() && !rLine
.GetCurr()->IsRest() )
1490 if( !rLine
.GetStart() )
1491 rLine
.Top(); // So that NumDone doesn't get confused
1494 TextFrameIndex nNew
= rLine
.GetStart() + rLine
.GetLength();
1498 if (CH_BREAK
== rString
[sal_Int32(nNew
)])
1505 rReformat
.Len() += rReformat
.Start() - nNew
;
1506 rReformat
.Start() = nNew
;
1509 rRepaint
.SetOffset( 0 );
1510 rRepaint
.SetRightOfst( 0 );
1511 rRepaint
.Chg( getFrameArea().Pos() + getFramePrintArea().Pos(), getFramePrintArea().SSize() );
1512 if( pPara
->IsMargin() )
1513 rRepaint
.Width( rRepaint
.Width() + pPara
->GetHangingMargin() );
1514 rRepaint
.Top( rLine
.Y() );
1515 if( 0 >= rRepaint
.Width() )
1517 WidowsAndOrphans
aFrameBreak( this, rInf
.IsTest() ? 1 : 0 );
1519 // rLine is now set to the first line which needs formatting.
1520 // The bFirst flag makes sure that Next() is not called.
1521 // The whole thing looks weird, but we need to make sure that
1522 // rLine stops at the last non-fitting line when calling IsBreakNow.
1524 bool bFormat
= true;
1526 // The CharToLine() can also get us into the danger zone.
1527 // In that case we need to walk back until rLine is set
1528 // to the non-fitting line. Or else the mass of text is lost,
1529 // because the Ofst was set wrongly in the Follow.
1531 bool bBreak
= ( !pPara
->IsPrepMustFit() || rLine
.GetLineNr() > 1 )
1532 && aFrameBreak
.IsBreakNowWidAndOrp( rLine
);
1535 bool bPrevDone
= nullptr != rLine
.Prev();
1536 while( bPrevDone
&& aFrameBreak
.IsBreakNowWidAndOrp(rLine
) )
1537 bPrevDone
= nullptr != rLine
.Prev();
1540 aFrameBreak
.SetKeep( false );
1546 aFrameBreak
.IsBreakNowWidAndOrp(rLine
);
1549 /* Meaning if the following flags are set:
1551 Watch(End/Mid)Hyph: we need to format if we have a break at
1552 the line end/Fly, as long as MaxHyph is reached
1554 Jump(End/Mid)Flag: the next line which has no break (line end/Fly),
1555 needs to be formatted, because we could wrap now. This might have been
1556 forbidden earlier by MaxHyph
1558 Watch(End/Mid)Hyph: if the last formatted line got a cutoff point, but
1559 didn't have one before
1561 Jump(End/Mid)Hyph: if a cutoff point disappears
1563 bool bJumpEndHyph
= false;
1564 bool bWatchEndHyph
= false;
1565 bool bJumpMidHyph
= false;
1566 bool bWatchMidHyph
= false;
1568 const SwAttrSet
& rAttrSet
= GetTextNodeForParaProps()->GetSwAttrSet();
1569 rInf
.MaxHyph() = rAttrSet
.GetHyphenZone().GetMaxHyphens();
1570 bool bMaxHyph
= 0 != rInf
.MaxHyph();
1572 rLine
.InitCntHyph();
1574 if( IsFollow() && IsFieldFollow() && rLine
.GetStart() == GetOffset() )
1576 SwTextFrame
*pMaster
= FindMaster();
1577 OSL_ENSURE( pMaster
, "SwTextFrame::Format: homeless follow" );
1578 const SwLineLayout
* pLine
=nullptr;
1581 if (!pMaster
->HasPara())
1582 { // master could be locked because it's being formatted upstack
1583 SAL_WARN("sw", "SwTextFrame::Format_: master not formatted!");
1587 SwTextSizeInfo
aInf( pMaster
);
1588 SwTextIter
aMasterLine( pMaster
, &aInf
);
1589 aMasterLine
.Bottom();
1590 pLine
= aMasterLine
.GetCurr();
1591 assert(aMasterLine
.GetEnd() == GetOffset());
1594 SwLinePortion
* pRest
= pLine
?
1595 rLine
.MakeRestPortion(pLine
, GetOffset()) : nullptr;
1597 rInf
.SetRest( pRest
);
1599 SetFieldFollow( false );
1602 /* Ad cancel criterion:
1603 * In order to recognize, whether a line does not fit onto the page
1604 * anymore, we need to format it. This overflow is removed again in
1605 * e.g. AdjustFollow.
1606 * Another complication: if we are the Master, we need to traverse
1607 * the lines, because it could happen that one line can overflow
1608 * from the Follow to the Master.
1618 if ( rLine
.GetCurr()->IsEndHyph() )
1619 rLine
.CntEndHyph()++;
1621 rLine
.CntEndHyph() = 0;
1622 if ( rLine
.GetCurr()->IsMidHyph() )
1623 rLine
.CntMidHyph()++;
1625 rLine
.CntMidHyph() = 0;
1631 SwLinePortion
* pRest
=
1632 rLine
.MakeRestPortion( rLine
.GetCurr(), rLine
.GetEnd() );
1634 rInf
.SetRest( pRest
);
1636 rLine
.Insert( new SwLineLayout() );
1641 if ( !bFormat
&& bMaxHyph
&&
1642 (bWatchEndHyph
|| bJumpEndHyph
|| bWatchMidHyph
|| bJumpMidHyph
) )
1644 if ( rLine
.GetCurr()->IsEndHyph() )
1646 if ( bWatchEndHyph
)
1647 bFormat
= ( rLine
.CntEndHyph() == rInf
.MaxHyph() );
1651 bFormat
= bJumpEndHyph
;
1652 bWatchEndHyph
= false;
1653 bJumpEndHyph
= false;
1655 if ( rLine
.GetCurr()->IsMidHyph() )
1657 if ( bWatchMidHyph
&& !bFormat
)
1658 bFormat
= ( rLine
.CntEndHyph() == rInf
.MaxHyph() );
1662 bFormat
|= bJumpMidHyph
;
1663 bWatchMidHyph
= false;
1664 bJumpMidHyph
= false;
1669 const bool bOldEndHyph
= rLine
.GetCurr()->IsEndHyph();
1670 const bool bOldMidHyph
= rLine
.GetCurr()->IsMidHyph();
1671 bFormat
= FormatLine( rLine
, bPrev
);
1672 // There can only be one bPrev ... (???)
1676 if ( rLine
.GetCurr()->IsEndHyph() != bOldEndHyph
)
1678 bWatchEndHyph
= !bOldEndHyph
;
1679 bJumpEndHyph
= bOldEndHyph
;
1681 if ( rLine
.GetCurr()->IsMidHyph() != bOldMidHyph
)
1683 bWatchMidHyph
= !bOldMidHyph
;
1684 bJumpMidHyph
= bOldMidHyph
;
1689 if( !rInf
.IsNewLine() )
1692 bFormat
= nullptr != rInf
.GetRest();
1693 if( rInf
.IsStop() || rInf
.GetIdx() >= nStrLen
)
1695 if( !bFormat
&& ( !bMaxHyph
|| ( !bWatchEndHyph
&&
1696 !bJumpEndHyph
&& !bWatchMidHyph
&& !bJumpMidHyph
) ) )
1700 while( rLine
.Next() )
1702 pFreeze
.reset(new SwRepaint( rRepaint
)); // to minimize painting
1708 bBreak
= aFrameBreak
.IsBreakNowWidAndOrp(rLine
);
1713 rRepaint
= *pFreeze
;
1717 if( !rLine
.IsStop() )
1719 // If we're finished formatting the text and we still
1720 // have other line objects left, these are superfluous
1721 // now because the text has gotten shorter.
1722 bool bTruncLines
= false;
1723 if( rLine
.GetStart() + rLine
.GetLength() >= nStrLen
&&
1724 rLine
.GetCurr()->GetNext() )
1728 else if (GetMergedPara() && rLine
.GetCurr()->GetNext())
1730 // We can also have superfluous lines with redlining in case the current line is shorter
1731 // than the text length, but the total length of lines is still more than expected.
1732 // Truncate in this case as well.
1733 TextFrameIndex
nLen(0);
1734 for (const SwLineLayout
* pLine
= pPara
; pLine
; pLine
= pLine
->GetNext())
1736 nLen
+= pLine
->GetLen();
1738 bTruncLines
= nLen
> nStrLen
;
1744 rLine
.SetTruncLines( true );
1751 // FormatAdjust does not pay off at OnceMore
1752 if( bAdjust
|| !rLine
.GetDropFormat() || !rLine
.CalcOnceMore() )
1754 FormatAdjust( rLine
, aFrameBreak
, nStrLen
, rInf
.IsStop() );
1756 if( rRepaint
.HasArea() )
1758 rLine
.SetTruncLines( false );
1759 if( nOldBottom
) // We check whether paragraphs that need scrolling can
1760 // be shrunk, so that they don't need scrolling anymore
1763 SwTwips nNewBottom
= rLine
.Y();
1764 if( nNewBottom
< nOldBottom
)
1765 SetOffset_(TextFrameIndex(0));
1769 void SwTextFrame::FormatOnceMore( SwTextFormatter
&rLine
, SwTextFormatInfo
&rInf
)
1771 OSL_ENSURE( ! IsVertical() || IsSwapped(),
1772 "A frame is not swapped in SwTextFrame::FormatOnceMore" );
1774 SwParaPortion
*pPara
= rLine
.GetInfo().GetParaPortion();
1778 // If necessary the pPara
1779 sal_uInt16 nOld
= static_cast<const SwTextMargin
&>(rLine
).GetDropHeight();
1780 bool bShrink
= false;
1782 bool bGoOn
= rLine
.IsOnceMore();
1789 if( !rLine
.GetDropFormat() )
1790 rLine
.SetOnceMore( false );
1791 SwCharRange
aRange(TextFrameIndex(0), TextFrameIndex(rInf
.GetText().getLength()));
1792 pPara
->GetReformat() = aRange
;
1793 Format_( rLine
, rInf
);
1795 bGoOn
= rLine
.IsOnceMore();
1798 const sal_uInt16 nNew
= static_cast<const SwTextMargin
&>(rLine
).GetDropHeight();
1808 if( bShrink
== bGrow
|| 5 < nGo
)
1814 // If something went wrong, we need to reformat again
1817 rInf
.CtorInitTextFormatInfo( getRootFrame()->GetCurrShell()->GetOut(), this );
1818 rLine
.CtorInitTextFormatter( this, &rInf
);
1819 rLine
.SetDropLines( 1 );
1820 rLine
.CalcDropHeight( 1 );
1821 SwCharRange
aTmpRange(TextFrameIndex(0), TextFrameIndex(rInf
.GetText().getLength()));
1822 pPara
->GetReformat() = aTmpRange
;
1823 Format_( rLine
, rInf
, true );
1824 // We paint everything ...
1831 void SwTextFrame::FormatImpl(vcl::RenderContext
* pRenderContext
, SwParaPortion
*pPara
,
1832 std::vector
<SwAnchoredObject
*> & rIntersectingObjs
)
1834 const bool bIsEmpty
= GetText().isEmpty();
1838 // Empty lines do not get tortured for very long:
1839 // pPara is cleared, which is the same as:
1840 // *pPara = SwParaPortion;
1841 const bool bMustFit
= pPara
->IsPrepMustFit();
1843 pPara
->FormatReset();
1845 // delete pSpaceAdd and pKanaComp
1846 pPara
->FinishSpaceAdd();
1847 pPara
->FinishKanaComp();
1848 pPara
->ResetFlags();
1849 pPara
->SetPrepMustFit( bMustFit
);
1852 OSL_ENSURE( ! IsSwapped(), "A frame is swapped before Format_" );
1855 SwapWidthAndHeight();
1857 SwTextFormatInfo
aInf( pRenderContext
, this );
1858 SwTextFormatter
aLine( this, &aInf
);
1860 HideAndShowObjects();
1862 Format_( aLine
, aInf
);
1864 if( aLine
.IsOnceMore() )
1865 FormatOnceMore( aLine
, aInf
);
1867 if (aInf
.GetTextFly().IsOn())
1869 SwRect
const aRect(aInf
.GetTextFly().GetFrameArea());
1870 for (SwAnchoredObject
*const pObj
: *aInf
.GetTextFly().GetAnchoredObjList())
1872 if (!aInf
.GetTextFly().AnchoredObjToRect(pObj
, aRect
).IsEmpty())
1874 rIntersectingObjs
.push_back(pObj
);
1880 SwapWidthAndHeight();
1882 OSL_ENSURE( ! IsSwapped(), "A frame is swapped after Format_" );
1884 if( 1 >= aLine
.GetDropLines() )
1887 if( SvxAdjust::Left
!= aLine
.GetAdjust() &&
1888 SvxAdjust::Block
!= aLine
.GetAdjust() )
1890 aLine
.CalcDropAdjust();
1891 aLine
.SetPaintDrop( true );
1894 if( aLine
.IsPaintDrop() )
1896 aLine
.CalcDropRepaint();
1897 aLine
.SetPaintDrop( false );
1901 // We calculate the text frame's size and send a notification.
1902 // Shrink() or Grow() to adjust the frame's size to the changed required space.
1903 void SwTextFrame::Format( vcl::RenderContext
* pRenderContext
, const SwBorderAttrs
* )
1905 SwRectFnSet
aRectFnSet(this);
1907 CalcAdditionalFirstLineOffset();
1909 // The range autopilot or the BASIC interface pass us TextFrames with
1910 // a width <= 0 from time to time
1911 if( aRectFnSet
.GetWidth(getFramePrintArea()) <= 0 )
1913 // If MustFit is set, we shrink to the Upper's bottom edge if needed.
1914 SwTextLineAccess
aAccess( this );
1916 if( aAccess
.GetPara()->IsPrepMustFit() )
1918 const SwTwips nLimit
= aRectFnSet
.GetPrtBottom(*GetUpper());
1919 const SwTwips nDiff
= - aRectFnSet
.BottomDist( getFrameArea(), nLimit
);
1924 tools::Long nFrameHeight
= aRectFnSet
.GetHeight(getFrameArea());
1925 const tools::Long nTop
= aRectFnSet
.GetTopMargin(*this);
1927 if( nTop
> nFrameHeight
)
1929 aRectFnSet
.SetYMargins( *this, nFrameHeight
, 0 );
1931 else if( aRectFnSet
.GetHeight(getFramePrintArea()) < 0 )
1933 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
1934 aRectFnSet
.SetHeight( aPrt
, 0 );
1940 TextFrameIndex
nStrLen(GetText().getLength());
1942 if (HasNonLastSplitFlyDrawObj())
1944 // Non-last part of split fly anchor: consider this empty.
1945 nStrLen
= TextFrameIndex(0);
1948 if ( nStrLen
|| !FormatEmpty() )
1952 // In order to not get confused by nested Formats
1954 if( 12 == FormatLevel::GetLevel() )
1957 // We could be possibly not allowed to alter the format information
1961 // Attention: Format() could be triggered by GetFormatted()
1964 tools::Long nPrtHeight
= aRectFnSet
.GetHeight(getFramePrintArea());
1968 Shrink( nPrtHeight
);
1972 // Assure that objects anchored
1973 // at paragraph resp. at/as character inside paragraph
1975 HideAndShowObjects();
1981 // We do not want to be interrupted during formatting
1982 TextFrameLockGuard
aLock(this);
1984 // this is to ensure that the similar code in SwTextFrame::Format_
1985 // finds the master formatted in case it's needed
1986 if (IsFollow() && IsFieldFollow())
1988 SwTextFrame
*pMaster
= FindMaster();
1990 if (!pMaster
->HasPara())
1992 pMaster
->GetFormatted();
1994 if (!pMaster
->HasPara())
1995 { // master could be locked because it's being formatted upstack
1996 SAL_WARN("sw", "SwTextFrame::Format: failed to format master!");
2000 SwTextSizeInfo
aInf( pMaster
);
2001 SwTextIter
aMasterLine( pMaster
, &aInf
);
2002 aMasterLine
.Bottom();
2003 SetOffset(aMasterLine
.GetEnd());
2007 SwTextLineAccess
aAccess( this );
2008 const bool bNew
= !aAccess
.IsAvailable();
2009 const bool bSetOffset
=
2010 (GetOffset() && GetOffset() > TextFrameIndex(GetText().getLength()));
2014 // We return if already formatted, but if the TextFrame was just created
2015 // and does not have any format information
2016 else if( !bNew
&& !aAccess
.GetPara()->GetReformat().Len() )
2018 if (GetTextNodeForParaProps()->GetSwAttrSet().GetRegister().GetValue())
2020 aAccess
.GetPara()->SetPrepAdjust();
2021 aAccess
.GetPara()->SetPrep();
2026 else if( bSetOffset
&& IsFollow() )
2028 SwTextFrame
*pMaster
= FindMaster();
2029 OSL_ENSURE( pMaster
, "SwTextFrame::Format: homeless follow" );
2031 pMaster
->Prepare( PrepareHint::FollowFollows
);
2032 SwTwips nMaxY
= aRectFnSet
.GetPrtBottom(*GetUpper());
2034 if( aRectFnSet
.OverStep( getFrameArea(), nMaxY
) )
2036 aRectFnSet
.SetLimit( *this, nMaxY
);
2038 else if( aRectFnSet
.BottomDist( getFrameArea(), nMaxY
) < 0 )
2040 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
2041 aRectFnSet
.AddBottom( aFrm
, -aRectFnSet
.GetHeight(aFrm
) );
2046 // bSetOffset here means that we have the "red arrow situation"
2048 SetOffset_(TextFrameIndex(0));
2050 const bool bOrphan
= IsWidow();
2051 const SwFootnoteBossFrame
* pFootnoteBoss
= HasFootnote() ? FindFootnoteBossFrame() : nullptr;
2052 SwTwips nFootnoteHeight
= 0;
2055 const SwFootnoteContFrame
* pCont
= pFootnoteBoss
->FindFootnoteCont();
2056 nFootnoteHeight
= pCont
? aRectFnSet
.GetHeight(pCont
->getFrameArea()) : 0;
2060 ::std::vector
<SwAnchoredObject
*> intersectingObjs
;
2061 ::std::vector
<SwFrame
const*> nexts
;
2062 for (SwFrame
const* pNext
= GetNext(); pNext
; pNext
= pNext
->GetNext())
2064 nexts
.push_back(pNext
);
2066 FormatImpl(pRenderContext
, aAccess
.GetPara(), intersectingObjs
);
2067 if( pFootnoteBoss
&& nFootnoteHeight
)
2069 const SwFootnoteContFrame
* pCont
= pFootnoteBoss
->FindFootnoteCont();
2070 SwTwips nNewHeight
= pCont
? aRectFnSet
.GetHeight(pCont
->getFrameArea()) : 0;
2071 // If we lost some footnotes, we may have more space
2072 // for our main text, so we have to format again ...
2073 if( nNewHeight
< nFootnoteHeight
)
2075 nFootnoteHeight
= nNewHeight
;
2079 if (!intersectingObjs
.empty())
2081 // assumption is that FormatImpl() only moves frames
2082 // in the next-chain to next page
2083 SwPageFrame
*const pPage(FindPageFrame());
2084 SwTextFrame
* pLastMovedAnchor(nullptr);
2085 auto lastIter(nexts
.end());
2086 for (SwAnchoredObject
*const pObj
: intersectingObjs
)
2088 SwFrame
*const pAnchor(pObj
->AnchorFrame());
2089 SwPageFrame
*const pAnchorPage(pAnchor
->FindPageFrame());
2090 if (pAnchorPage
!= pPage
)
2092 auto const iter(::std::find(nexts
.begin(), nexts
.end(), pAnchor
));
2093 if (iter
!= nexts
.end())
2095 assert(pAnchor
->IsTextFrame());
2096 // (can't check SwOszControl::IsInProgress()?)
2097 // called in loop in FormatAnchorFrameAndItsPrevs()
2098 if (static_cast<SwTextFrame
const*>(pAnchor
)->IsJoinLocked()
2099 // called in loop in SwFrame::PrepareMake()
2100 || pAnchor
->IsDeleteForbidden())
2102 // when called via FormatAnchorFrameAndItsPrevs():
2103 // don't do anything, caller will handle it
2104 pLastMovedAnchor
= nullptr;
2107 assert(pPage
->GetPhyPageNum() < pAnchorPage
->GetPhyPageNum()); // how could it move backward?
2109 if (!pLastMovedAnchor
|| iter
< lastIter
)
2111 pLastMovedAnchor
= static_cast<SwTextFrame
*>(pAnchor
);
2117 SwPageFrame
const*const pPrevPage(static_cast<SwPageFrame
const*>(pPage
->GetPrev()));
2118 if (pLastMovedAnchor
)
2120 for (SwAnchoredObject
*const pObj
: intersectingObjs
)
2122 if (pObj
->AnchorFrame() == pLastMovedAnchor
)
2124 SwPageFrame
*const pAnchorPage(pLastMovedAnchor
->FindPageFrame());
2125 SAL_INFO("sw.layout", "SwTextFrame::Format: move anchored " << pObj
<< " from " << pPage
->GetPhyPageNum() << " to " << pAnchorPage
->GetPhyPageNum());
2126 pObj
->RegisterAtPage(*pAnchorPage
);
2127 // tdf#143239 if the position remains valid, it may not be
2128 // positioned again so would remain on the wrong page!
2129 pObj
->InvalidateObjPos();
2130 ::Notify_Background(pObj
->GetDrawObj(), pPage
,
2131 pObj
->GetObjRect(), PrepareHint::FlyFrameLeave
, false);
2132 pObj
->SetForceNotifyNewBackground(true);
2135 if (GetFollow() // this frame was split
2136 && (!pPrevPage
// prev page is still valid
2137 || (!pPrevPage
->IsInvalid()
2138 && (!pPrevPage
->GetSortedObjs() || !pPrevPage
->IsInvalidFly()))))
2139 { // this seems a bit risky...
2140 SwLayouter::InsertMovedFwdFrame(GetTextNodeFirst()->GetDoc(),
2141 *pLastMovedAnchor
, FindPageFrame()->GetPhyPageNum() + 1);
2143 continue; // try again without the fly
2147 } while ( pFootnoteBoss
);
2154 if( IsEmptyMaster() )
2156 SwFrame
* pPre
= GetPrev();
2158 // i#10826 It's the first, it cannot keep!
2159 pPre
->GetIndPrev() &&
2160 pPre
->GetAttrSet()->GetKeep().GetValue() )
2162 pPre
->InvalidatePos();
2165 if (IsEmptyMasterWithSplitFly())
2167 // A fly is anchored to us, reduce size, so we definitely still fit the current
2169 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
2170 aRectFnSet
.SetHeight(aFrm
, 0);
2172 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
2173 aRectFnSet
.SetTop(aPrt
, 0);
2174 aRectFnSet
.SetHeight(aPrt
, 0);
2181 // the PrepMustFit should not survive a Format operation
2182 SwParaPortion
*pPara
= GetPara();
2184 pPara
->SetPrepMustFit( false );
2186 CalcBaseOfstForFly();
2187 CalcHeightOfLastLine(); // i#11860 - Adjust spacing implementation for
2188 // object positioning - Compatibility to MS Word
2189 // tdf#117982 -- Fix cell spacing hides content
2190 // Check if the cell's content has greater size than the row height
2191 if (IsInTab() && GetUpper() && ((GetUpper()->getFramePrintArea().Height() < getFramePrintArea().Height())
2192 || (getFramePrintArea().Height() <= 0)))
2194 SAL_INFO("sw.core", "Warn: Cell content has greater size than cell height!");
2196 SwTwips aTmpHeight
= getFrameArea().Height();
2197 //...and push it into the text frame
2198 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
2199 //if only bottom margin what we have:
2200 if (GetTopMargin() == 0)
2201 //set the frame to its original location
2202 aPrt
.SetTopAndHeight(0, aTmpHeight
);
2206 // bForceQuickFormat is set if GetFormatted() has been called during the
2207 // painting process. Actually I cannot imagine a situation which requires
2208 // a full formatting of the paragraph during painting, on the other hand
2209 // a full formatting can cause the invalidation of other layout frames,
2210 // e.g., if there are footnotes in this paragraph, and invalid layout
2211 // frames will not calculated during the painting. So I actually want to
2212 // avoid a formatting during painting, but since I'm a coward, I'll only
2213 // force the quick formatting in the situation of issue i29062.
2214 bool SwTextFrame::FormatQuick( bool bForceQuickFormat
)
2216 OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
2217 "SwTextFrame::FormatQuick with swapped frame" );
2219 if( IsEmpty() && FormatEmpty() )
2222 // We're very picky:
2223 if( HasPara() || IsWidow() || IsLocked()
2224 || !isFrameAreaSizeValid() ||
2225 ( ( IsVertical() ? getFramePrintArea().Width() : getFramePrintArea().Height() ) && IsHiddenNow() ) )
2228 SwTextLineAccess
aAccess( this );
2229 SwParaPortion
*pPara
= aAccess
.GetPara();
2233 SwFrameSwapper
aSwapper( this, true );
2235 TextFrameLockGuard
aLock(this);
2236 SwTextFormatInfo
aInf( getRootFrame()->GetCurrShell()->GetOut(), this, false, true );
2237 if( 0 != aInf
.MaxHyph() ) // Respect MaxHyphen!
2240 SwTextFormatter
aLine( this, &aInf
);
2242 // DropCaps are too complicated ...
2243 if( aLine
.GetDropFormat() )
2246 TextFrameIndex nStart
= GetOffset();
2247 const TextFrameIndex nEnd
= GetFollow()
2248 ? GetFollow()->GetOffset()
2249 : TextFrameIndex(aInf
.GetText().getLength());
2251 int nLoopProtection
= 0;
2254 TextFrameIndex nNewStart
= aLine
.FormatLine(nStart
);
2255 if (nNewStart
== nStart
)
2258 nLoopProtection
= 0;
2260 const bool bWillEndlessInsert
= nLoopProtection
> 250;
2261 SAL_WARN_IF(bWillEndlessInsert
, "sw", "loop detection triggered");
2262 if ((!bWillEndlessInsert
) // Check for special case: line is invisible,
2263 // like in too thin table cell: tdf#66141
2264 && (aInf
.IsNewLine() || (!aInf
.IsStop() && nStart
< nEnd
)))
2265 aLine
.Insert( new SwLineLayout() );
2266 } while( aLine
.Next() );
2268 // Last exit: the heights need to match
2269 Point
aTopLeft( getFrameArea().Pos() );
2270 aTopLeft
+= getFramePrintArea().Pos();
2271 const SwTwips nNewHeight
= aLine
.Y() + aLine
.GetLineHeight();
2272 const SwTwips nOldHeight
= aTopLeft
.Y() + getFramePrintArea().Height();
2274 if( !bForceQuickFormat
&& nNewHeight
!= nOldHeight
&& !IsUndersized() )
2276 // Attention: This situation can occur due to FormatLevel==12. Don't panic!
2277 TextFrameIndex
const nStrt
= GetOffset();
2278 InvalidateRange_( SwCharRange( nStrt
, nEnd
- nStrt
) );
2282 if (m_pFollow
&& nStart
!= static_cast<SwTextFrame
*>(m_pFollow
)->GetOffset())
2283 return false; // can be caused by e.g. Orphans
2288 pPara
->GetRepaint().Pos( aTopLeft
);
2289 pPara
->GetRepaint().SSize( getFramePrintArea().SSize() );
2292 pPara
->GetReformat() = SwCharRange();
2298 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */