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 "objectformattertxtfrm.hxx"
21 #include "objectformatterlayfrm.hxx"
22 #include <anchoreddrawobject.hxx>
23 #include <sortedobjs.hxx>
24 #include <rootfrm.hxx>
25 #include <pagefrm.hxx>
26 #include <flyfrms.hxx>
29 #include <IDocumentSettingAccess.hxx>
30 #include <osl/diagnose.h>
34 // --> #i26945# - Additionally the type of the anchor text frame
35 // is collected - by type is meant 'master' or 'follow'.
36 class SwPageNumAndTypeOfAnchors
41 SwAnchoredObject
* mpAnchoredObj
;
42 sal_uInt32 mnPageNumOfAnchor
;
43 bool mbAnchoredAtMaster
;
46 std::vector
< tEntry
> maObjList
;
49 SwPageNumAndTypeOfAnchors()
53 void Collect( SwAnchoredObject
& _rAnchoredObj
)
56 aNewEntry
.mpAnchoredObj
= &_rAnchoredObj
;
57 // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
58 // is replaced by method <FindPageFrameOfAnchor()>. It's return value
59 // have to be checked.
60 SwPageFrame
* pPageFrameOfAnchor
= _rAnchoredObj
.FindPageFrameOfAnchor();
61 if ( pPageFrameOfAnchor
)
63 aNewEntry
.mnPageNumOfAnchor
= pPageFrameOfAnchor
->GetPhyPageNum();
67 aNewEntry
.mnPageNumOfAnchor
= 0;
69 // --> #i26945# - collect type of anchor
70 SwTextFrame
* pAnchorCharFrame
= _rAnchoredObj
.FindAnchorCharFrame();
71 if ( pAnchorCharFrame
)
73 aNewEntry
.mbAnchoredAtMaster
= !pAnchorCharFrame
->IsFollow();
77 aNewEntry
.mbAnchoredAtMaster
= true;
79 maObjList
.push_back( aNewEntry
);
82 SwAnchoredObject
* operator[]( sal_uInt32 _nIndex
)
84 return maObjList
[_nIndex
].mpAnchoredObj
;
87 sal_uInt32
GetPageNum( sal_uInt32 _nIndex
) const
89 return maObjList
[_nIndex
].mnPageNumOfAnchor
;
93 bool AnchoredAtMaster( sal_uInt32 _nIndex
)
95 return maObjList
[_nIndex
].mbAnchoredAtMaster
;
98 sal_uInt32
Count() const
100 return maObjList
.size();
104 SwObjectFormatter::SwObjectFormatter( const SwPageFrame
& _rPageFrame
,
105 SwLayAction
* _pLayAction
,
106 const bool _bCollectPgNumOfAnchors
)
107 : mrPageFrame( _rPageFrame
),
108 mbConsiderWrapOnObjPos( _rPageFrame
.GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION
) ),
109 mpLayAction( _pLayAction
),
111 mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors
? new SwPageNumAndTypeOfAnchors() : nullptr )
115 SwObjectFormatter::~SwObjectFormatter()
119 std::unique_ptr
<SwObjectFormatter
> SwObjectFormatter::CreateObjFormatter(
120 SwFrame
& _rAnchorFrame
,
121 const SwPageFrame
& _rPageFrame
,
122 SwLayAction
* _pLayAction
)
124 std::unique_ptr
<SwObjectFormatter
> pObjFormatter
;
125 if ( _rAnchorFrame
.IsTextFrame() )
127 pObjFormatter
= SwObjectFormatterTextFrame::CreateObjFormatter(
128 static_cast<SwTextFrame
&>(_rAnchorFrame
),
129 _rPageFrame
, _pLayAction
);
131 else if ( _rAnchorFrame
.IsLayoutFrame() )
133 pObjFormatter
= SwObjectFormatterLayFrame::CreateObjFormatter(
134 static_cast<SwLayoutFrame
&>(_rAnchorFrame
),
135 _rPageFrame
, _pLayAction
);
139 OSL_FAIL( "<SwObjectFormatter::CreateObjFormatter(..)> - unexpected type of anchor frame" );
142 return pObjFormatter
;
145 /** method to format all floating screen objects at the given anchor frame
147 bool SwObjectFormatter::FormatObjsAtFrame( SwFrame
& _rAnchorFrame
,
148 const SwPageFrame
& _rPageFrame
,
149 SwLayAction
* _pLayAction
)
151 bool bSuccess( true );
153 // create corresponding object formatter
154 std::unique_ptr
<SwObjectFormatter
> pObjFormatter
=
155 SwObjectFormatter::CreateObjFormatter( _rAnchorFrame
, _rPageFrame
, _pLayAction
);
159 // format anchored floating screen objects
160 bSuccess
= pObjFormatter
->DoFormatObjs();
166 /** method to format a given floating screen object
168 bool SwObjectFormatter::FormatObj( SwAnchoredObject
& _rAnchoredObj
,
169 SwFrame
* _pAnchorFrame
,
170 const SwPageFrame
* _pPageFrame
,
171 SwLayAction
* pLayAction
)
173 bool bSuccess( true );
175 OSL_ENSURE( _pAnchorFrame
|| _rAnchoredObj
.GetAnchorFrame(),
176 "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
177 SwFrame
& rAnchorFrame
= _pAnchorFrame
? *_pAnchorFrame
: *(_rAnchoredObj
.AnchorFrame());
179 OSL_ENSURE( _pPageFrame
|| rAnchorFrame
.FindPageFrame(),
180 "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
181 const SwPageFrame
& rPageFrame
= _pPageFrame
? *_pPageFrame
: *(rAnchorFrame
.FindPageFrame());
183 // create corresponding object formatter
184 std::unique_ptr
<SwObjectFormatter
> pObjFormatter
=
185 SwObjectFormatter::CreateObjFormatter(rAnchorFrame
, rPageFrame
, pLayAction
);
189 // format given floating screen object
190 // --> #i40147# - check for moved forward anchor frame
191 bSuccess
= pObjFormatter
->DoFormatObj( _rAnchoredObj
, true );
197 /** helper method for method <FormatObj_(..)> - performs the intrinsic format
198 of the layout of the given layout frame and all its lower layout frames.
202 Method corresponds to methods <SwLayAction::FormatLayoutFly(..)> and
203 <SwLayAction::FormatLayout(..)>. Thus, its code for the formatting have
206 void SwObjectFormatter::FormatLayout_( SwLayoutFrame
& _rLayoutFrame
)
208 _rLayoutFrame
.Calc(_rLayoutFrame
.getRootFrame()->GetCurrShell()->GetOut());
210 SwFrame
* pLowerFrame
= _rLayoutFrame
.Lower();
211 while ( pLowerFrame
)
213 if ( pLowerFrame
->IsLayoutFrame() )
215 FormatLayout_( *static_cast<SwLayoutFrame
*>(pLowerFrame
) );
217 pLowerFrame
= pLowerFrame
->GetNext();
221 /** helper method for method <FormatObj_(..)> - performs the intrinsic
222 format of the content of the given floating screen object.
226 void SwObjectFormatter::FormatObjContent( SwAnchoredObject
& _rAnchoredObj
)
228 if ( !_rAnchoredObj
.DynCastFlyFrame() )
230 // only Writer fly frames have content
234 SwFlyFrame
& rFlyFrame
= static_cast<SwFlyFrame
&>(_rAnchoredObj
);
235 SwContentFrame
* pContent
= rFlyFrame
.ContainsContent();
242 // format floating screen objects at content text frame
243 // #i23129#, #i36347# - pass correct page frame to
244 // the object formatter
245 if ( pContent
->IsTextFrame() &&
246 !SwObjectFormatter::FormatObjsAtFrame( *pContent
,
247 *(pContent
->FindPageFrame()),
250 // restart format with first content
251 pContent
= rFlyFrame
.ContainsContent();
255 // continue with next content
256 pContent
= pContent
->GetNextContentFrame();
260 /** performs the intrinsic format of a given floating screen object and its content.
264 void SwObjectFormatter::FormatObj_( SwAnchoredObject
& _rAnchoredObj
)
266 // collect anchor object and its 'anchor' page number, if requested
267 if ( mpPgNumAndTypeOfAnchors
)
269 mpPgNumAndTypeOfAnchors
->Collect( _rAnchoredObj
);
272 if ( auto pFlyFrame
= _rAnchoredObj
.DynCastFlyFrame() )
274 // --> #i34753# - reset flag, which prevents a positioning
275 if ( pFlyFrame
->IsFlyLayFrame() )
277 static_cast<SwFlyLayFrame
*>(pFlyFrame
)->SetNoMakePos( false );
280 // #i81146# new loop control
281 int nLoopControlRuns
= 0;
282 const int nLoopControlMax
= 15;
287 mpLayAction
->FormatLayoutFly( pFlyFrame
);
288 // --> consider, if the layout action
289 // has to be restarted due to a delete of a page frame.
290 if ( mpLayAction
->IsAgain() )
297 FormatLayout_( *pFlyFrame
);
299 // --> #i34753# - prevent further positioning, if
300 // to-page|to-fly anchored Writer fly frame is already clipped.
301 if ( pFlyFrame
->IsFlyLayFrame() && pFlyFrame
->IsClipped() )
303 static_cast<SwFlyLayFrame
*>(pFlyFrame
)->SetNoMakePos( true );
305 // #i23129#, #i36347# - pass correct page frame
306 // to the object formatter
307 SwObjectFormatter::FormatObjsAtFrame( *pFlyFrame
,
308 *(pFlyFrame
->FindPageFrame()),
312 mpLayAction
->FormatFlyContent( pFlyFrame
);
313 // --> consider, if the layout action
314 // has to be restarted due to a delete of a page frame.
315 if ( mpLayAction
->IsAgain() )
322 FormatObjContent( *pFlyFrame
);
325 if ( ++nLoopControlRuns
>= nLoopControlMax
)
327 OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
328 pFlyFrame
->ValidateThisAndAllLowers( 2 );
329 nLoopControlRuns
= 0;
333 // stop formatting of anchored object, if restart of layout process is requested.
334 } while ( !pFlyFrame
->isFrameAreaDefinitionValid() &&
335 !_rAnchoredObj
.RestartLayoutProcess() &&
336 pFlyFrame
->GetAnchorFrame() == &GetAnchorFrame() );
338 else if ( dynamic_cast<const SwAnchoredDrawObject
*>( &_rAnchoredObj
) != nullptr )
340 _rAnchoredObj
.MakeObjPos();
344 /** invokes the intrinsic format method for all floating screen objects,
345 anchored at anchor frame on the given page frame
348 #i26945# - for format of floating screen objects for
349 follow text frames, the 'master' text frame is passed to the method.
350 Thus, the objects, whose anchor character is inside the follow text
351 frame can be formatted.
353 bool SwObjectFormatter::FormatObjsAtFrame_( SwTextFrame
* _pMasterTextFrame
)
356 SwFrame
* pAnchorFrame( nullptr );
357 if ( GetAnchorFrame().IsTextFrame() &&
358 static_cast<SwTextFrame
&>(GetAnchorFrame()).IsFollow() &&
361 pAnchorFrame
= _pMasterTextFrame
;
365 pAnchorFrame
= &GetAnchorFrame();
367 if ( !pAnchorFrame
->GetDrawObjs() || pAnchorFrame
->IsInDtor() )
369 // nothing to do, if no floating screen object is registered at the anchor frame.
373 bool bSuccess( true );
375 for ( size_t i
= 0; i
< pAnchorFrame
->GetDrawObjs()->size(); ++i
)
377 SwAnchoredObject
* pAnchoredObj
= (*pAnchorFrame
->GetDrawObjs())[i
];
379 // check, if object's anchor is on the given page frame or
380 // object is registered at the given page frame.
381 // --> #i26945# - check, if the anchor character of the
382 // anchored object is located in a follow text frame. If this anchor
383 // follow text frame differs from the given anchor frame, the given
384 // anchor frame is a 'master' text frame of the anchor follow text frame.
385 // If the anchor follow text frame is in the same body as its 'master'
386 // text frame, do not format the anchored object.
387 // E.g., this situation can occur during the table row splitting algorithm.
388 SwTextFrame
* pAnchorCharFrame
= pAnchoredObj
->FindAnchorCharFrame();
389 const bool bAnchoredAtFollowInSameBodyAsMaster
=
390 pAnchorCharFrame
&& pAnchorCharFrame
->IsFollow() &&
391 pAnchorCharFrame
!= pAnchoredObj
->GetAnchorFrame() &&
392 pAnchorCharFrame
->FindBodyFrame() ==
393 static_cast<SwTextFrame
*>(pAnchoredObj
->AnchorFrame())->FindBodyFrame();
394 // Make sure that in case nested split flys are moved "out of range" in
395 // lcl_InvalidateLowerObjs(), then we moved them back here.
396 SwFlyFrame
* pFly
= pAnchoredObj
->DynCastFlyFrame();
397 bool bSplitFly
= pFly
&& pFly
->IsFlySplitAllowed();
398 bool bNestedSplitFly
= bSplitFly
&& pAnchorCharFrame
&& pAnchorCharFrame
->IsInFly();
399 if (bAnchoredAtFollowInSameBodyAsMaster
&& !bNestedSplitFly
)
403 // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
404 // is replaced by method <FindPageFrameOfAnchor()>. It's return value
405 // have to be checked.
406 SwPageFrame
* pPageFrameOfAnchor
= pAnchoredObj
->FindPageFrameOfAnchor();
407 OSL_ENSURE( pPageFrameOfAnchor
,
408 "<SwObjectFormatter::FormatObjsAtFrame_()> - missing page frame." );
410 if ( pPageFrameOfAnchor
&& pPageFrameOfAnchor
== &mrPageFrame
)
412 // if format of object fails, stop formatting and pass fail to
413 // calling method via the return value.
414 if ( !DoFormatObj( *pAnchoredObj
) )
420 // considering changes at <pAnchorFrame->GetDrawObjs()> during
421 // format of the object.
422 if ( !pAnchorFrame
->GetDrawObjs() ||
423 i
> pAnchorFrame
->GetDrawObjs()->size() )
429 const size_t nActPosOfObj
=
430 pAnchorFrame
->GetDrawObjs()->ListPosOf( *pAnchoredObj
);
431 if ( nActPosOfObj
== pAnchorFrame
->GetDrawObjs()->size() ||
436 else if ( nActPosOfObj
< i
)
442 } // end of loop on <pAnchorFrame->.GetDrawObjs()>
447 /** accessor to collected anchored object
451 SwAnchoredObject
* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex
)
453 return mpPgNumAndTypeOfAnchors
? (*mpPgNumAndTypeOfAnchors
)[_nIndex
] : nullptr;
456 /** accessor to 'anchor' page number of collected anchored object
460 sal_uInt32
SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex
)
462 return mpPgNumAndTypeOfAnchors
? mpPgNumAndTypeOfAnchors
->GetPageNum(_nIndex
) : 0;
465 /** accessor to 'anchor' type of collected anchored object
469 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex
)
471 return mpPgNumAndTypeOfAnchors
== nullptr
472 || mpPgNumAndTypeOfAnchors
->AnchoredAtMaster(_nIndex
);
475 /** accessor to total number of collected anchored objects
479 sal_uInt32
SwObjectFormatter::CountOfCollected()
481 return mpPgNumAndTypeOfAnchors
? mpPgNumAndTypeOfAnchors
->Count() : 0;
484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */