Add a comment to clarify what kind of inputs the class handles
[LibreOffice.git] / sw / source / core / layout / objectformatter.cxx
blob547aa3c550d5e6027e0b6cb61573d8968445e2ab
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
27 #include <txtfrm.hxx>
28 #include <layact.hxx>
29 #include <IDocumentSettingAccess.hxx>
30 #include <osl/diagnose.h>
32 #include <vector>
34 // --> #i26945# - Additionally the type of the anchor text frame
35 // is collected - by type is meant 'master' or 'follow'.
36 class SwPageNumAndTypeOfAnchors
38 private:
39 struct tEntry
41 SwAnchoredObject* mpAnchoredObj;
42 sal_uInt32 mnPageNumOfAnchor;
43 bool mbAnchoredAtMaster;
46 std::vector< tEntry > maObjList;
48 public:
49 SwPageNumAndTypeOfAnchors()
53 void Collect( SwAnchoredObject& _rAnchoredObj )
55 tEntry aNewEntry;
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();
65 else
67 aNewEntry.mnPageNumOfAnchor = 0;
69 // --> #i26945# - collect type of anchor
70 SwTextFrame* pAnchorCharFrame = _rAnchoredObj.FindAnchorCharFrame();
71 if ( pAnchorCharFrame )
73 aNewEntry.mbAnchoredAtMaster = !pAnchorCharFrame->IsFollow();
75 else
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;
92 // --> #i26945#
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 ),
110 // --> #i26945#
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 );
137 else
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 );
157 if ( pObjFormatter )
159 // format anchored floating screen objects
160 bSuccess = pObjFormatter->DoFormatObjs();
163 return bSuccess;
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);
187 if ( pObjFormatter )
189 // format given floating screen object
190 // --> #i40147# - check for moved forward anchor frame
191 bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
194 return bSuccess;
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.
200 #i28701#
201 IMPORTANT NOTE:
202 Method corresponds to methods <SwLayAction::FormatLayoutFly(..)> and
203 <SwLayAction::FormatLayout(..)>. Thus, its code for the formatting have
204 to be synchronised.
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.
224 #i28701#
226 void SwObjectFormatter::FormatObjContent( SwAnchoredObject& _rAnchoredObj )
228 if ( !_rAnchoredObj.DynCastFlyFrame() )
230 // only Writer fly frames have content
231 return;
234 SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
235 SwContentFrame* pContent = rFlyFrame.ContainsContent();
237 while ( pContent )
239 // format content
240 pContent->OptCalc();
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()),
248 GetLayAction() ) )
250 // restart format with first content
251 pContent = rFlyFrame.ContainsContent();
252 continue;
255 // continue with next content
256 pContent = pContent->GetNextContentFrame();
260 /** performs the intrinsic format of a given floating screen object and its content.
262 #i28701#
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;
284 do {
285 if ( mpLayAction )
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() )
292 break;
295 else
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()),
309 mpLayAction );
310 if ( mpLayAction )
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() )
317 break;
320 else
322 FormatObjContent( *pFlyFrame );
325 if ( ++nLoopControlRuns >= nLoopControlMax )
327 OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
328 pFlyFrame->ValidateThisAndAllLowers( 2 );
329 nLoopControlRuns = 0;
332 // --> #i57917#
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
347 #i28701#
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 )
355 // --> #i26945#
356 SwFrame* pAnchorFrame( nullptr );
357 if ( GetAnchorFrame().IsTextFrame() &&
358 static_cast<SwTextFrame&>(GetAnchorFrame()).IsFollow() &&
359 _pMasterTextFrame )
361 pAnchorFrame = _pMasterTextFrame;
363 else
365 pAnchorFrame = &GetAnchorFrame();
367 if ( !pAnchorFrame->GetDrawObjs() || pAnchorFrame->IsInDtor() )
369 // nothing to do, if no floating screen object is registered at the anchor frame.
370 return true;
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)
401 continue;
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." );
409 // --> #i26945#
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 ) )
416 bSuccess = false;
417 break;
420 // considering changes at <pAnchorFrame->GetDrawObjs()> during
421 // format of the object.
422 if ( !pAnchorFrame->GetDrawObjs() ||
423 i > pAnchorFrame->GetDrawObjs()->size() )
425 break;
427 else
429 const size_t nActPosOfObj =
430 pAnchorFrame->GetDrawObjs()->ListPosOf( *pAnchoredObj );
431 if ( nActPosOfObj == pAnchorFrame->GetDrawObjs()->size() ||
432 nActPosOfObj > i )
434 --i;
436 else if ( nActPosOfObj < i )
438 i = nActPosOfObj;
442 } // end of loop on <pAnchorFrame->.GetDrawObjs()>
444 return bSuccess;
447 /** accessor to collected anchored object
449 #i28701#
451 SwAnchoredObject* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex )
453 return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : nullptr;
456 /** accessor to 'anchor' page number of collected anchored object
458 #i28701#
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
467 #i26945#
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
477 #i28701#
479 sal_uInt32 SwObjectFormatter::CountOfCollected()
481 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0;
484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */