LibreOffice Module sw (master) 1
objectformattertxtfrm.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
21#include <sortedobjs.hxx>
22#include <rootfrm.hxx>
23#include <anchoredobject.hxx>
24#include <txtfrm.hxx>
25#include <pagefrm.hxx>
26#include <rowfrm.hxx>
27#include <layouter.hxx>
28#include <fmtanchr.hxx>
30#include <fmtfollowtextflow.hxx>
31#include <layact.hxx>
32#include <flyfrm.hxx>
33#include <ftnfrm.hxx>
34#include <osl/diagnose.h>
35
36using namespace ::com::sun::star;
37
38namespace {
39
40// little helper class to forbid follow formatting for the given text frame
41class SwForbidFollowFormat
42{
43private:
44 SwTextFrame& mrTextFrame;
45 const bool bOldFollowFormatAllowed;
46
47public:
48 explicit SwForbidFollowFormat( SwTextFrame& _rTextFrame )
49 : mrTextFrame( _rTextFrame ),
50 bOldFollowFormatAllowed( _rTextFrame.FollowFormatAllowed() )
51 {
52 mrTextFrame.ForbidFollowFormat();
53 }
54
55 ~SwForbidFollowFormat()
56 {
57 if ( bOldFollowFormatAllowed )
58 {
59 mrTextFrame.AllowFollowFormat();
60 }
61 }
62};
63
64}
65
67 const SwPageFrame& _rPageFrame,
68 SwTextFrame* _pMasterAnchorTextFrame,
69 SwLayAction* _pLayAction )
70 : SwObjectFormatter( _rPageFrame, _pLayAction, true ),
71 mrAnchorTextFrame( _rAnchorTextFrame ),
72 mpMasterAnchorTextFrame( _pMasterAnchorTextFrame )
73{
74}
75
77{
78}
79
80std::unique_ptr<SwObjectFormatterTextFrame> SwObjectFormatterTextFrame::CreateObjFormatter(
81 SwTextFrame& _rAnchorTextFrame,
82 const SwPageFrame& _rPageFrame,
83 SwLayAction* _pLayAction )
84{
85 std::unique_ptr<SwObjectFormatterTextFrame> pObjFormatter;
86
87 // determine 'master' of <_rAnchorTextFrame>, if anchor frame is a follow text frame.
88 SwTextFrame* pMasterOfAnchorFrame = nullptr;
89 if ( _rAnchorTextFrame.IsFollow() )
90 {
91 pMasterOfAnchorFrame = _rAnchorTextFrame.FindMaster();
92 while ( pMasterOfAnchorFrame && pMasterOfAnchorFrame->IsFollow() )
93 {
94 pMasterOfAnchorFrame = pMasterOfAnchorFrame->FindMaster();
95 }
96 }
97
98 // create object formatter, if floating screen objects are registered
99 // at anchor frame (or at 'master' anchor frame)
100 if ( _rAnchorTextFrame.GetDrawObjs() ||
101 ( pMasterOfAnchorFrame && pMasterOfAnchorFrame->GetDrawObjs() ) )
102 {
103 pObjFormatter.reset(
104 new SwObjectFormatterTextFrame( _rAnchorTextFrame, _rPageFrame,
105 pMasterOfAnchorFrame, _pLayAction ));
106 }
107
108 return pObjFormatter;
109}
110
112{
113 return mrAnchorTextFrame;
114}
115
116// #i40147# - add parameter <_bCheckForMovedFwd>.
118 const bool _bCheckForMovedFwd )
119{
120 // consider, if the layout action has to be
121 // restarted due to a delete of a page frame.
122 if ( GetLayAction() && GetLayAction()->IsAgain() )
123 {
124 return false;
125 }
126
127 bool bSuccess( true );
128
129 if ( _rAnchoredObj.IsFormatPossible() )
130 {
131 _rAnchoredObj.SetRestartLayoutProcess( false );
132
133 FormatObj_( _rAnchoredObj );
134 // consider, if the layout action has to be
135 // restarted due to a delete of a page frame.
136 if ( GetLayAction() && GetLayAction()->IsAgain() )
137 {
138 return false;
139 }
140
141 // check, if layout process has to be restarted.
142 // if yes, perform needed invalidations.
143
144 // no restart of layout process,
145 // if anchored object is anchored inside a Writer fly frame,
146 // its position is already locked, and it follows the text flow.
147 const bool bRestart =
148 _rAnchoredObj.RestartLayoutProcess() &&
149 !( _rAnchoredObj.PositionLocked() &&
150 _rAnchoredObj.GetAnchorFrame()->IsInFly() &&
151 _rAnchoredObj.GetFrameFormat().GetFollowTextFlow().GetValue() );
152 if ( bRestart )
153 {
154 bSuccess = false;
155 InvalidatePrevObjs( _rAnchoredObj );
156 InvalidateFollowObjs( _rAnchoredObj );
157 }
158
159 // format anchor text frame, if wrapping style influence of the object
160 // has to be considered and it's <NONE_SUCCESSIVE_POSITIONED>
161 // #i3317# - consider also anchored objects, whose
162 // wrapping style influence is temporarily considered.
163 // #i40147# - consider also anchored objects, for
164 // whose the check of a moved forward anchor frame is requested.
165 // revise decision made for i3317:
166 // anchored objects, whose wrapping style influence is temporarily considered,
167 // have to be considered in method <SwObjectFormatterTextFrame::DoFormatObjs()>
168 if ( bSuccess &&
169 _rAnchoredObj.ConsiderObjWrapInfluenceOnObjPos() &&
170 ( _bCheckForMovedFwd ||
172 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
173 GetWrapInfluenceOnObjPos( true ) ==
174 // #i35017# - constant name has changed
175 text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) )
176 {
177 // #i26945# - check conditions for move forward of
178 // anchor text frame
179 // determine, if anchor text frame has previous frame
180 const bool bDoesAnchorHadPrev = ( mrAnchorTextFrame.GetIndPrev() != nullptr );
181
182 // #i40141# - use new method - it also formats the
183 // section the anchor frame is in.
185
186 // #i35911#
187 if ( _rAnchoredObj.HasClearedEnvironment() )
188 {
189 _rAnchoredObj.SetClearedEnvironment( true );
190 // #i44049# - consider, that anchor frame
191 // could already been marked to move forward.
192 SwPageFrame* pAnchorPageFrame( mrAnchorTextFrame.FindPageFrame() );
193 if ( pAnchorPageFrame != _rAnchoredObj.GetPageFrame() )
194 {
195 bool bInsert( true );
196 sal_uInt32 nToPageNum( 0 );
197 const SwDoc& rDoc = *(GetPageFrame().GetFormat()->GetDoc());
199 rDoc, mrAnchorTextFrame, nToPageNum ) )
200 {
201 if ( nToPageNum < pAnchorPageFrame->GetPhyPageNum() )
203 else
204 bInsert = false;
205 }
206 if ( bInsert )
207 {
209 pAnchorPageFrame->GetPhyPageNum() );
211 bSuccess = false;
212 InvalidatePrevObjs( _rAnchoredObj );
213 InvalidateFollowObjs( _rAnchoredObj );
214 }
215 else
216 {
217 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
218 }
219 }
220 }
221 else if ( !mrAnchorTextFrame.IsFollow() && bDoesAnchorHadPrev )
222 {
223 // index of anchored object in collection of page numbers and
224 // anchor types
225 sal_uInt32 nIdx( CountOfCollected() );
226 OSL_ENSURE( nIdx > 0,
227 "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchored object not collected!?" );
228 --nIdx;
229
230 sal_uInt32 nToPageNum( 0 );
231 // #i43913#
232 bool bDummy( false );
233 bool bPageHasFlysAnchoredBelowThis(false);
234 // see how SwObjectFormatter::FormatObjsAtFrame_() checks
235 // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
236 // this subclass
237 assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(nIdx));
239 GetPageFrame(),
241 nToPageNum, bDummy,
242 bPageHasFlysAnchoredBelowThis))
243 {
244 // #i49987# - consider, that anchor frame
245 // could already been marked to move forward.
246 bool bInsert( true );
247 sal_uInt32 nMovedFwdToPageNum( 0 );
248 const SwDoc& rDoc = *(GetPageFrame().GetFormat()->GetDoc());
250 rDoc, mrAnchorTextFrame, nMovedFwdToPageNum ) )
251 {
252 if ( nMovedFwdToPageNum < nToPageNum )
253 {
254 if (!bPageHasFlysAnchoredBelowThis)
255 {
257 }
258 }
259 else
260 bInsert = false;
261 }
262 if ( bInsert )
263 {
264 // Indicate that anchor text frame has to move forward and
265 // invalidate its position to force a re-format.
266 if (!bPageHasFlysAnchoredBelowThis)
267 {
269 mrAnchorTextFrame, nToPageNum);
270 }
272
273 // Indicate restart of the layout process
274 bSuccess = false;
275
276 // If needed, invalidate previous objects anchored at same anchor
277 // text frame.
278 InvalidatePrevObjs( _rAnchoredObj );
279
280 // Invalidate object and following objects for the restart of the
281 // layout process
282 InvalidateFollowObjs( _rAnchoredObj );
283 }
284 else
285 {
286 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
287 }
288 }
289 }
290 // i40155# - mark anchor frame not to wrap around
291 // objects under the condition, that its follow contains all its text.
292 else if ( !mrAnchorTextFrame.IsFollow() &&
295 {
299 }
300 }
301 }
302
303 return bSuccess;
304}
305
307{
309 {
310 if ( GetLayAction() &&
312 {
313 // notify layout action, thus is can restart the layout process on
314 // a previous page.
315 GetLayAction()->SetAgain(true);
316 }
317 else
318 {
319 // the anchor text frame has to be valid, thus assert.
320 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs()> called for invalidate anchor text frame." );
321 }
322
323 return false;
324 }
325
326 bool bSuccess( true );
327
328 if ( mrAnchorTextFrame.IsFollow() )
329 {
330 // Only floating screen objects anchored as-character are directly
331 // registered at a follow text frame. The other floating screen objects
332 // are registered at the 'master' anchor text frame.
333 // Thus, format the other floating screen objects through the 'master'
334 // anchor text frame
335 OSL_ENSURE( mpMasterAnchorTextFrame,
336 "SwObjectFormatterTextFrame::DoFormatObjs() - missing 'master' anchor text frame" );
338
339 if ( bSuccess )
340 {
341 // format of as-character anchored floating screen objects - no failure
342 // expected on the format of these objects.
343 bSuccess = FormatObjsAtFrame_();
344 }
345 }
346 else
347 {
348 bSuccess = FormatObjsAtFrame_();
349 }
350
351 // consider anchored objects, whose wrapping style influence are temporarily
352 // considered.
353 if ( bSuccess &&
355 ( !mrAnchorTextFrame.IsFollow() &&
357 {
358 const bool bDoesAnchorHadPrev = ( mrAnchorTextFrame.GetIndPrev() != nullptr );
359
360 // Format anchor text frame after its objects are formatted.
361 // Note: The format of the anchor frame also formats the invalid
362 // previous frames of the anchor frame. The format of the previous
363 // frames is needed to get a correct result of format of the
364 // anchor frame for the following check for moved forward anchors
365 // #i40141# - use new method - it also formats the
366 // section the anchor frame is in.
368
369 sal_uInt32 nToPageNum( 0 );
370 // #i43913#
371 bool bInFollow( false );
372 bool bPageHasFlysAnchoredBelowThis(false);
373 SwAnchoredObject* pObj = nullptr;
374 if ( !mrAnchorTextFrame.IsFollow() )
375 {
377 // #i35017# - constant name has changed
378 text::WrapInfluenceOnPosition::ONCE_CONCURRENT,
379 nToPageNum, bInFollow, bPageHasFlysAnchoredBelowThis );
380 }
381 // #i35911#
382 if ( pObj && pObj->HasClearedEnvironment() )
383 {
384 pObj->SetClearedEnvironment( true );
385 // #i44049# - consider, that anchor frame
386 // could already been marked to move forward.
387 SwPageFrame* pAnchorPageFrame( mrAnchorTextFrame.FindPageFrame() );
388 // #i43913# - consider, that anchor frame
389 // is a follow or is in a follow row, which will move forward.
390 if ( pAnchorPageFrame != pObj->GetPageFrame() ||
391 bInFollow )
392 {
393 bool bInsert( true );
394 sal_uInt32 nTmpToPageNum( 0 );
395 const SwDoc& rDoc = *(GetPageFrame().GetFormat()->GetDoc());
397 rDoc, mrAnchorTextFrame, nTmpToPageNum ) )
398 {
399 if ( nTmpToPageNum < pAnchorPageFrame->GetPhyPageNum() )
400 {
401 if (!bPageHasFlysAnchoredBelowThis)
402 {
404 }
405 }
406 else
407 bInsert = false;
408 }
409 if ( bInsert )
410 {
411 if (!bPageHasFlysAnchoredBelowThis)
412 {
414 pAnchorPageFrame->GetPhyPageNum());
415 }
417 bSuccess = false;
418 InvalidatePrevObjs( *pObj );
419 InvalidateFollowObjs( *pObj );
420 }
421 else
422 {
423 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
424 }
425 }
426 }
427 else if ( pObj && bDoesAnchorHadPrev )
428 {
429 // Object found, whose anchor is moved forward
430
431 // #i49987# - consider, that anchor frame
432 // could already been marked to move forward.
433 bool bInsert( true );
434 sal_uInt32 nMovedFwdToPageNum( 0 );
435 const SwDoc& rDoc = *(GetPageFrame().GetFormat()->GetDoc());
437 rDoc, mrAnchorTextFrame, nMovedFwdToPageNum ) )
438 {
439 if ( nMovedFwdToPageNum < nToPageNum )
441 else
442 bInsert = false;
443 }
444 if ( bInsert )
445 {
446 // Indicate that anchor text frame has to move forward and
447 // invalidate its position to force a re-format.
450
451 // Indicate restart of the layout process
452 bSuccess = false;
453
454 // If needed, invalidate previous objects anchored at same anchor
455 // text frame.
456 InvalidatePrevObjs( *pObj );
457
458 // Invalidate object and following objects for the restart of the
459 // layout process
460 InvalidateFollowObjs( *pObj );
461 }
462 else
463 {
464 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
465 }
466 }
467 // #i40155# - mark anchor frame not to wrap around
468 // objects under the condition, that its follow contains all its text.
469 else if ( !mrAnchorTextFrame.IsFollow() &&
472 {
476 }
477 }
478
479 return bSuccess;
480}
481
483{
484 // invalidate all previous objects, whose wrapping influence on the object
485 // positioning is <NONE_CONCURRENT_POSITIONED>.
486 // Note: list of objects at anchor frame is sorted by this property.
487 if ( _rAnchoredObj.GetFrameFormat().GetWrapInfluenceOnObjPos().
488 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
489 GetWrapInfluenceOnObjPos( true ) !=
490 // #i35017# - constant name has changed
491 text::WrapInfluenceOnPosition::ONCE_CONCURRENT )
492 return;
493
494 const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
495 if ( !pObjs )
496 return;
497
498 // determine start index
499 size_t i = pObjs->ListPosOf( _rAnchoredObj );
500 while (i > 0)
501 {
502 --i;
503 SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
504 if ( pAnchoredObj->GetFrameFormat().GetWrapInfluenceOnObjPos().
505 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
506 GetWrapInfluenceOnObjPos( true ) ==
507 // #i35017# - constant name has changed
508 text::WrapInfluenceOnPosition::ONCE_CONCURRENT )
509 {
511 }
512 }
513}
514
516{
518
519 const SwSortedObjs* pObjs = GetPageFrame().GetSortedObjs();
520 if ( pObjs )
521 {
522 // determine start index
523 for ( size_t i = pObjs->ListPosOf( _rAnchoredObj ) + 1; i < pObjs->size(); ++i )
524 {
525 SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
527 }
528 }
529}
530
532 const sal_Int16 _nWrapInfluenceOnPosition,
533 sal_uInt32& _noToPageNum,
534 bool& _boInFollow,
535 bool& o_rbPageHasFlysAnchoredBelowThis)
536{
537 // #i35017# - constant names have changed
538 OSL_ENSURE( _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ||
539 _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ONCE_CONCURRENT,
540 "<SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor(..)> - invalid value for parameter <_nWrapInfluenceOnPosition>" );
541
542 SwAnchoredObject* pRetAnchoredObj = nullptr;
543
544 sal_uInt32 i = 0;
545 for ( ; i < CountOfCollected(); ++i )
546 {
547 SwAnchoredObject* pAnchoredObj = GetCollectedObj(i);
548 if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() &&
550 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
551 GetWrapInfluenceOnObjPos( true ) == _nWrapInfluenceOnPosition )
552 {
553 // see how SwObjectFormatter::FormatObjsAtFrame_() checks
554 // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
555 // this subclass
556 assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(i));
557 // #i26945# - use new method <_CheckMovedFwdCondition(..)>
558 // #i43913#
560 GetPageFrame(),
562 _noToPageNum, _boInFollow,
563 o_rbPageHasFlysAnchoredBelowThis) )
564 {
565 pRetAnchoredObj = pAnchoredObj;
566 break;
567 }
568 }
569 }
570
571 return pRetAnchoredObj;
572}
573
574static SwRowFrame const* FindTopLevelRowFrame(SwFrame const*const pFrame)
575{
576 SwRowFrame * pRow = const_cast<SwFrame*>(pFrame)->FindRowFrame();
577 // looks like SwTabFrame has mbInfTab = true so go up 2 levels
578 while (pRow->GetUpper()->GetUpper()->IsInTab())
579 {
580 pRow = pRow->GetUpper()->GetUpper()->FindRowFrame();
581 }
582 return pRow;
583}
584
585static SwContentFrame const* FindFrameInBody(SwAnchoredObject const& rAnchored)
586{
587 SwFrame const*const pAnchor(rAnchored.GetAnchorFrame());
588 assert(pAnchor);
589 if (pAnchor->IsPageFrame() || pAnchor->FindFooterOrHeader())
590 {
591 return nullptr;
592 }
593 if (pAnchor->IsInFly())
594 {
595 return FindFrameInBody(*pAnchor->FindFlyFrame());
596 }
597 if (pAnchor->IsInFootnote())
598 {
599 return pAnchor->FindFootnoteFrame()->GetRef();
600 }
601 assert(pAnchor->IsInDocBody());
602 assert(pAnchor->IsContentFrame());
603 return static_cast<SwContentFrame const*>(pAnchor);
604}
605
606// #i58182#
607// - replace private method by corresponding static public method
609 SwAnchoredObject& _rAnchoredObj,
610 SwPageFrame const& rFromPageFrame,
611 const bool _bAnchoredAtMasterBeforeFormatAnchor,
612 sal_uInt32& _noToPageNum,
613 bool& _boInFollow,
614 bool& o_rbPageHasFlysAnchoredBelowThis)
615{
616 const sal_uInt32 _nFromPageNum(rFromPageFrame.GetPhyPageNum());
617 bool bAnchorIsMovedForward( false );
618
619 SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
620 if ( pPageFrameOfAnchor )
621 {
622 const sal_uInt32 nPageNum = pPageFrameOfAnchor->GetPhyPageNum();
623 if ( nPageNum > _nFromPageNum )
624 {
625 _noToPageNum = nPageNum;
626 // Handling of special case:
627 // If anchor frame is move forward into a follow flow row,
628 // <_noToPageNum> is set to <_nFromPageNum + 1>, because it is
629 // possible that the anchor page frame isn't valid, because the
630 // page distance between master row and follow flow row is greater
631 // than 1.
632 if ( _noToPageNum > (_nFromPageNum + 1) )
633 {
634 SwFrame* pAnchorFrame = _rAnchoredObj.GetAnchorFrameContainingAnchPos();
635 if ( pAnchorFrame->IsInTab() &&
636 pAnchorFrame->IsInFollowFlowRow() )
637 {
638 _noToPageNum = _nFromPageNum + 1;
639 }
640 }
641 bAnchorIsMovedForward = true;
642 }
643 }
644 // #i26945# - check, if an at-paragraph|at-character
645 // anchored object is now anchored at a follow text frame, which will be
646 // on the next page. Also check, if an at-character anchored object
647 // is now anchored at a text frame, which is in a follow flow row,
648 // which will be on the next page.
649 if ( !bAnchorIsMovedForward &&
650 _bAnchoredAtMasterBeforeFormatAnchor &&
651 ((_rAnchoredObj.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR) ||
652 (_rAnchoredObj.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PARA)))
653 {
654 SwFrame* pAnchorFrame = _rAnchoredObj.GetAnchorFrameContainingAnchPos();
655 OSL_ENSURE( pAnchorFrame->IsTextFrame(),
656 "<SwObjectFormatterTextFrame::CheckMovedFwdCondition(..) - wrong type of anchor frame>" );
657 SwTextFrame* pAnchorTextFrame = static_cast<SwTextFrame*>(pAnchorFrame);
658 bool bCheck( false );
659 if ( pAnchorTextFrame->IsFollow() )
660 {
661 bCheck = true;
662 }
663 else if( pAnchorTextFrame->IsInTab() )
664 {
665 const SwRowFrame* pMasterRow = pAnchorTextFrame->IsInFollowFlowRow();
666 if ( pMasterRow &&
667 pMasterRow->FindPageFrame() == pPageFrameOfAnchor )
668 {
669 bCheck = true;
670 }
671 }
672 if ( bCheck )
673 {
674 // check, if found text frame will be on the next page
675 // by checking, if it's in a column, which has no next.
676 SwFrame* pColFrame = pAnchorTextFrame->FindColFrame();
677 while ( pColFrame && !pColFrame->GetNext() )
678 {
679 pColFrame = pColFrame->FindColFrame();
680 }
681 if ( !pColFrame || !pColFrame->GetNext() )
682 {
683 _noToPageNum = _nFromPageNum + 1;
684 bAnchorIsMovedForward = true;
685 // #i43913#
686 _boInFollow = true;
687 }
688 }
689 }
690
691 if (bAnchorIsMovedForward)
692 {
693 // tdf#138518 try to determine if there is a fly on page rFromPageFrame
694 // which is anchored in a frame that is "below" the anchor frame
695 // of _rAnchoredObj, such that it should move to the next page before
696 // _rAnchoredObj does
697 if (auto * pObjs = rFromPageFrame.GetSortedObjs())
698 {
699 for (SwAnchoredObject *const pObj : *pObjs)
700 {
701 SwPageFrame const*const pObjAnchorPage(pObj->FindPageFrameOfAnchor());
702 assert(pObjAnchorPage);
703 if ((pObjAnchorPage == &rFromPageFrame
704 ? _boInFollow // same-page but will move forward
705 : rFromPageFrame.GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum())
706 && pObj->GetFrameFormat().GetAnchor().GetAnchorId()
707 != RndStdIds::FLY_AS_CHAR)
708 {
709 if (pPageFrameOfAnchor->GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum())
710 {
711 SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next page");
712 o_rbPageHasFlysAnchoredBelowThis = true;
713 break;
714 }
715 // on same page: check if it's in next-chain in the document body
716 // (in case both are in the same fly the flag must not be
717 // set because the whole fly moves at once)
718 SwContentFrame const*const pInBodyFrameObj(FindFrameInBody(*pObj));
719 SwContentFrame const*const pInBodyFrameAnchoredObj(FindFrameInBody(_rAnchoredObj));
720 if (pInBodyFrameObj && pInBodyFrameAnchoredObj)
721 {
722 bool isBreakMore(false);
723 // currently this ignores index of at-char flys
724 for (SwContentFrame const* pContentFrame = pInBodyFrameAnchoredObj->FindNextCnt();
725 pContentFrame;
726 pContentFrame = pContentFrame->FindNextCnt())
727 {
728 if (pInBodyFrameObj == pContentFrame)
729 {
730 // subsequent cells in a row are not automatically
731 // "below" and the row could potentially be split
732 // TODO refine check if needed
733 if (!pInBodyFrameAnchoredObj->IsInTab()
734 || FindTopLevelRowFrame(pInBodyFrameAnchoredObj)
735 != FindTopLevelRowFrame(pInBodyFrameAnchoredObj))
736 { // anchored in next chain on same page
737 SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next chain on same page");
738 o_rbPageHasFlysAnchoredBelowThis = true;
739 isBreakMore = true;
740 }
741 break;
742 }
743 }
744 if (isBreakMore)
745 {
746 break;
747 }
748 }
749 }
750 }
751 }
752 }
753
754 return bAnchorIsMovedForward;
755}
756
757static void CleanupEmptyFootnoteFrame(SwFrame* pLowerFrame)
758{
759 // Calc on a SwTextFrame in a footnote can move it to the next page -
760 // deletion of the SwFootnoteFrame was disabled with SwFrameDeleteGuard
761 // but now we have to clean up empty footnote frames to prevent crashes.
762 // Note: check it at this level, not lower: both container and footnote
763 // can be deleted at the same time!
764 if (!pLowerFrame->IsFootnoteContFrame())
765 return;
766
767 for (SwFrame * pFootnote = pLowerFrame->GetLower(); pFootnote; )
768 {
769 assert(pFootnote->IsFootnoteFrame());
770 SwFrame *const pNextNote = pFootnote->GetNext();
771 if (!pFootnote->IsDeleteForbidden() && !pFootnote->GetLower() && !pFootnote->IsColLocked() &&
772 !static_cast<SwFootnoteFrame*>(pFootnote)->IsBackMoveLocked())
773 {
774 pFootnote->Cut();
775 SwFrame::DestroyFrame(pFootnote);
776 }
777 pFootnote = pNextNote;
778 }
779}
780
781// #i40140# - helper method to format layout frames used by
782// method <SwObjectFormatterTextFrame::FormatAnchorFrameForCheckMoveFwd()>
783// #i44049# - format till a certain lower frame, if provided.
785 SwFrame* pLastLowerFrame = nullptr )
786{
787 SwFrame* pLowerFrame = pLayFrame->GetLower();
788 while ( pLowerFrame )
789 {
790 // #i44049#
791 if ( pLastLowerFrame && pLowerFrame == pLastLowerFrame )
792 {
793 break;
794 }
795 if ( pLowerFrame->IsLayoutFrame() )
796 {
797 SwFrameDeleteGuard aCrudeHack(pLowerFrame); // ??? any issue setting this for non-footnote frames?
798 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pLowerFrame),
799 pLastLowerFrame );
800 }
801 else
802 pLowerFrame->Calc(pLowerFrame->getRootFrame()->GetCurrShell()->GetOut());
803
804 // Calc on a SwTextFrame in a footnote can move it to the next page -
805 // deletion of the SwFootnoteFrame was disabled with SwFrameDeleteGuard
806 // but now we have to clean up empty footnote frames to prevent crashes.
807 // Note: check it at this level, not lower: both container and footnote
808 // can be deleted at the same time!
809 SwFrame *const pNext = pLowerFrame->GetNext();
810 CleanupEmptyFootnoteFrame(pLowerFrame);
811 pLowerFrame = pNext;
812 }
813}
814
824{
825 // #i47014# - no format of section and previous columns
826 // for follow text frames.
827 if ( !_rAnchorTextFrame.IsFollow() )
828 {
829 // In case the anchor frame is in a column or section, format its
830 // previous frames first - but don't jump out of the current layout
831 // environment, e.g. from footnotes into the footnote boss.
832 SwFrame * pSectFrame(nullptr);
833 SwFrame * pColFrameOfAnchor(nullptr);
834 for (SwFrame* pUpper = _rAnchorTextFrame.GetUpper();
835 pUpper != nullptr; pUpper = pUpper->GetUpper())
836 {
837 if (pUpper->IsCellFrame())
838 {
839 break; // apparently nothing to be done?
840 }
841 if (pUpper->IsFootnoteFrame())
842 {
843 SAL_INFO_IF(pColFrameOfAnchor == nullptr && pUpper->FindColFrame(),
844 "sw.layout", "tdf#122894 skipping column for footnote in column");
845 break; // stop: prevent crash in case footnotes are being moved
846 }
847 if (pUpper->IsSctFrame())
848 {
849 pColFrameOfAnchor = nullptr;
850 pSectFrame = pUpper;
851 break;
852 }
853 if (pColFrameOfAnchor != nullptr)
854 { // parent of column not a section frame => column not in section
855 break;
856 }
857 if (pUpper->IsColumnFrame())
858 {
859 pColFrameOfAnchor = pUpper;
860 }
861 }
862
863 // if anchor frame is directly inside a section, format this section and
864 // its previous frames.
865 // Note: It's a very simple format without formatting objects.
866 if (pSectFrame)
867 {
868 assert(pSectFrame->IsSctFrame());
869 {
870 SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
871 // #i44049#
872 _rAnchorTextFrame.LockJoin();
873 SwFrame* pFrame = pSectFrame->GetUpper()->GetLower();
874 // #i49605# - section frame could move forward
875 // by the format of its previous frame.
876 // Thus, check for valid <pFrame>.
877 while ( pFrame && pFrame != pSectFrame )
878 {
879 SwFrameDeleteGuard aDeleteFrameGuard(pFrame);
880
881 if ( pFrame->IsLayoutFrame() )
882 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
883 else
884 pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
885
886 pFrame = pFrame->GetNext();
887 }
888 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pSectFrame),
889 &_rAnchorTextFrame );
890 // #i44049#
891 _rAnchorTextFrame.UnlockJoin();
892 }
893 }
894
895 // #i40140# - if anchor frame is inside a column,
896 // format the content of the previous columns.
897 // Note: It's a very simple format without formatting objects.
898 if (pColFrameOfAnchor)
899 {
900 assert(pColFrameOfAnchor->IsColumnFrame());
901 // #i44049#
902 _rAnchorTextFrame.LockJoin();
903 SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
904 SwFrame* pColFrame = pColFrameOfAnchor->GetUpper()->GetLower();
905 while ( pColFrame != pColFrameOfAnchor )
906 {
907 SwFrame* pFrame = pColFrame->GetLower();
908 while ( pFrame )
909 {
910 if ( pFrame->IsLayoutFrame() )
911 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
912 else
913 pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
914
915 pFrame = pFrame->GetNext();
916 }
917
918 pColFrame = pColFrame->GetNext();
919 }
920 // #i44049#
921 _rAnchorTextFrame.UnlockJoin();
922 }
923 }
924
925 // format anchor frame - format of its follow not needed
926 // #i43255# - forbid follow format, only if anchor text
927 // frame is in table
928 if ( _rAnchorTextFrame.IsInTab() )
929 {
930 SwForbidFollowFormat aForbidFollowFormat( _rAnchorTextFrame );
931 _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
932 }
933 else
934 {
935 _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
936 }
937}
938
944{
946}
947
952{
953 bool bRet( false );
954
955 const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
956 if ( pObjs && pObjs->size() > 1 )
957 {
958 for (SwAnchoredObject* pAnchoredObj : *pObjs)
959 {
960 if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() )
961 {
962 bRet = true;
963 break;
964 }
965 }
966 }
967
968 return bRet;
969}
970
971/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool GetValue() const
wrapper class for the positioning of Writer fly frames and drawing objects
const SwFrame * GetAnchorFrame() const
bool PositionLocked() const
void SetClearedEnvironment(const bool _bClearedEnvironment)
SwFrame * GetAnchorFrameContainingAnchPos()
determine anchor frame containing the anchor position
void InvalidateObjPosForConsiderWrapInfluence()
method to perform necessary invalidations for the positioning of objects, for whose the wrapping styl...
bool RestartLayoutProcess() const
bool ConsiderObjWrapInfluenceOnObjPos() const
method to determine, if wrapping style influence of the anchored object has to be considered on the o...
virtual SwFrameFormat & GetFrameFormat()=0
SwPageFrame * GetPageFrame()
SwPageFrame * FindPageFrameOfAnchor()
method to determine the page frame, on which the 'anchor' of the given anchored object is.
bool HasClearedEnvironment() const
method to determine, if due to anchored object size and wrapping style, its layout environment is cle...
virtual bool IsFormatPossible() const
method to determine, if a format on the anchored object is possible
void SetRestartLayoutProcess(const bool _bRestartLayoutProcess)
SwContentFrame is the layout for content nodes: a common base class for text (paragraph) and non-text...
Definition: cntfrm.hxx:59
SwTextFrame * FindMaster() const
Definition: flowfrm.cxx:762
Definition: doc.hxx:197
Represents one footnote or endnote in the layout.
Definition: ftnfrm.hxx:84
const SwContentFrame * GetRef() const
Definition: ftnfrm.cxx:2909
bool IsBackMoveLocked() const
Definition: ftnfrm.hxx:137
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:67
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:139
const SwFormatWrapInfluenceOnObjPos & GetWrapInfluenceOnObjPos(bool=true) const
const SwFormatFollowTextFlow & GetFollowTextFlow(bool=true) const
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:88
bool isFrameAreaDefinitionValid() const
Definition: frame.hxx:171
Base class of the Writer layout elements.
Definition: frame.hxx:315
virtual void Cut()=0
bool IsFootnoteContFrame() const
Definition: frame.hxx:1204
bool IsTextFrame() const
Definition: frame.hxx:1240
SwFrame * GetIndPrev() const
Definition: frame.hxx:730
bool IsInDocBody() const
Definition: frame.hxx:949
SwFlyFrame * FindFlyFrame()
Definition: frame.hxx:1117
SwFrame * GetNext()
Definition: frame.hxx:682
bool IsPageFrame() const
Definition: frame.hxx:1184
bool IsColumnFrame() const
Definition: frame.hxx:1188
bool IsInFootnote() const
Definition: frame.hxx:955
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1799
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:568
bool IsInTab() const
Definition: frame.hxx:961
SwFrame * GetLower()
Definition: findfrm.cxx:196
bool IsInFly() const
Definition: frame.hxx:967
SwRowFrame * FindRowFrame()
Definition: findfrm.cxx:624
const SwRowFrame * IsInFollowFlowRow() const
Definition: findfrm.cxx:1874
void InvalidatePos()
Definition: frame.hxx:1049
SwLayoutFrame * GetUpper()
Definition: frame.hxx:684
SwRootFrame * getRootFrame()
Definition: frame.hxx:685
bool IsContentFrame() const
Definition: frame.hxx:1236
SwFrame * FindColFrame()
Definition: findfrm.cxx:615
bool IsSctFrame() const
Definition: frame.hxx:1220
SwContentFrame * FindNextCnt(const bool _bInSameFootnote=false)
Definition: findfrm.cxx:217
SwPageFrame * FindPageFrame()
Definition: frame.hxx:686
SwFrame * FindFooterOrHeader()
Definition: findfrm.cxx:633
SwFootnoteFrame * FindFootnoteFrame()
Definition: frame.hxx:1113
static void DestroyFrame(SwFrame *const pFrame)
this is the only way to delete a SwFrame instance
Definition: ssfrm.cxx:390
bool IsLayoutFrame() const
Definition: frame.hxx:1176
The usage of LayAction is always the same:
Definition: layact.hxx:59
void SetAgain(bool bAgain)
Definition: layact.cxx:316
A layout frame is a frame that contains other frames (m_pLower), e.g. SwPageFrame or SwTabFrame.
Definition: layfrm.hxx:36
virtual const SwFrameFormat * GetFormat() const
Definition: ssfrm.cxx:401
static void InsertMovedFwdFrame(const SwDoc &_rDoc, const SwTextFrame &_rMovedFwdFrameByObjPos, const sal_uInt32 _nToPageNum)
Definition: layouter.cxx:308
static bool FrameMovedFwdByObjPos(const SwDoc &_rDoc, const SwTextFrame &_rTextFrame, sal_uInt32 &_ornToPageNum)
Definition: layouter.cxx:338
static void RemoveMovedFwdFrame(const SwDoc &_rDoc, const SwTextFrame &_rTextFrame)
Definition: layouter.cxx:328
void InvalidateFollowObjs(SwAnchoredObject &_rAnchoredObj)
method to invalidate objects, anchored after the given object at the page frame
SwObjectFormatterTextFrame(SwTextFrame &_rAnchorTextFrame, const SwPageFrame &_rPageFrame, SwTextFrame *_pMasterAnchorTextFrame, SwLayAction *_pLayAction)
SwAnchoredObject * GetFirstObjWithMovedFwdAnchor(const sal_Int16 _nWrapInfluenceOnPosition, sal_uInt32 &_noToPageNum, bool &_boInFollow, bool &o_rbPageHasFlysAnchoredBelowThis)
method to determine first anchored object, whose 'anchor is moved forward'.
virtual bool DoFormatObjs() override
intrinsic method to format all floating screen objects
void InvalidatePrevObjs(SwAnchoredObject &_rAnchoredObj)
method to invalidate objects, anchored previous to given object at the anchor text frame
bool AtLeastOneObjIsTmpConsiderWrapInfluence()
method to determine if at least one anchored object has state <temporarily consider wrapping style in...
static void FormatAnchorFrameAndItsPrevs(SwTextFrame &_rAnchorTextFrame)
method to format given anchor text frame and its previous frames
virtual ~SwObjectFormatterTextFrame() override
virtual bool DoFormatObj(SwAnchoredObject &_rAnchoredObj, const bool _bCheckForMovedFwd=false) override
intrinsic method to format a certain floating screen object
virtual SwFrame & GetAnchorFrame() override
static std::unique_ptr< SwObjectFormatterTextFrame > CreateObjFormatter(SwTextFrame &_rAnchorTextFrame, const SwPageFrame &_rPageFrame, SwLayAction *_pLayAction)
method to create an instance of <SwObjectFormatterTextFrame> is necessary.
void FormatAnchorFrameForCheckMoveFwd()
method to format the anchor frame for checking of the move forward condition
static bool CheckMovedFwdCondition(SwAnchoredObject &_rAnchoredObj, SwPageFrame const &rFromPageFrame, const bool _bAnchoredAtMasterBeforeFormatAnchor, sal_uInt32 &_noToPageNum, bool &_boInFollow, bool &o_rbPageHasFlysAnchoredBelowThis)
method to check the conditions, if 'anchor is moved forward'
SwLayAction * GetLayAction()
const SwPageFrame & GetPageFrame() const
SwAnchoredObject * GetCollectedObj(const sal_uInt32 _nIndex)
accessor to collected anchored object
void FormatObj_(SwAnchoredObject &_rAnchoredObj)
performs the intrinsic format of a given floating screen object and its content.
bool FormatObjsAtFrame_(SwTextFrame *_pMasterTextFrame=nullptr)
invokes the intrinsic format method for all floating screen objects, anchored at anchor frame on the ...
bool ConsiderWrapOnObjPos() const
sal_uInt32 GetPgNumOfCollected(const sal_uInt32 _nIndex)
accessor to 'anchor' page number of collected anchored object
bool IsCollectedAnchoredAtMaster(const sal_uInt32 _nIndex)
accessor to 'anchor' type of collected anchored object
sal_uInt32 CountOfCollected()
accessor to total number of collected anchored objects
A page of the document layout.
Definition: pagefrm.hxx:60
sal_uInt16 GetPhyPageNum() const
Definition: pagefrm.hxx:209
const SwSortedObjs * GetSortedObjs() const
Definition: pagefrm.hxx:136
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:215
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:29
class for collecting anchored objects
Definition: sortedobjs.hxx:49
size_t size() const
Definition: sortedobjs.cxx:43
size_t ListPosOf(const SwAnchoredObject &_rAnchoredObj) const
Position of object <_rAnchoredObj> in sorted list.
Definition: sortedobjs.cxx:277
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:168
SwTextFrame * GetFollow()
Definition: txtfrm.hxx:889
TextFrameIndex GetOffset() const
Definition: txtfrm.hxx:453
void AllowFollowFormat()
Definition: txtfrm.hxx:766
void ForbidFollowFormat()
Definition: txtfrm.hxx:771
vcl::RenderContext * GetOut() const
Definition: viewsh.hxx:365
#define SAL_INFO_IF(condition, area, stream)
#define SAL_INFO(area, stream)
size
int i
static void CleanupEmptyFootnoteFrame(SwFrame *pLowerFrame)
static SwRowFrame const * FindTopLevelRowFrame(SwFrame const *const pFrame)
static SwContentFrame const * FindFrameInBody(SwAnchoredObject const &rAnchored)
static void lcl_FormatContentOfLayoutFrame(SwLayoutFrame *pLayFrame, SwFrame *pLastLowerFrame=nullptr)