Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / sw / source / core / layout / objectformatter.cxx
bloba0621956e730ff019610d4bebaf9dccc4da1c49e
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 <fmtanchr.hxx>
30 #include <doc.hxx>
31 #include <IDocumentSettingAccess.hxx>
33 #include <vector>
35 // --> #i26945# - Additionally the type of the anchor text frame
36 // is collected - by type is meant 'master' or 'follow'.
37 class SwPageNumAndTypeOfAnchors
39 private:
40 struct tEntry
42 SwAnchoredObject* mpAnchoredObj;
43 sal_uInt32 mnPageNumOfAnchor;
44 bool mbAnchoredAtMaster;
47 std::vector< tEntry* > maObjList;
49 public:
50 SwPageNumAndTypeOfAnchors()
53 ~SwPageNumAndTypeOfAnchors()
55 for ( std::vector< tEntry* >::iterator aIter = maObjList.begin();
56 aIter != maObjList.end(); ++aIter )
58 delete *aIter;
60 maObjList.clear();
63 void Collect( SwAnchoredObject& _rAnchoredObj )
65 tEntry* pNewEntry = new tEntry;
66 pNewEntry->mpAnchoredObj = &_rAnchoredObj;
67 // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
68 // is replaced by method <FindPageFrameOfAnchor()>. It's return value
69 // have to be checked.
70 SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
71 if ( pPageFrameOfAnchor )
73 pNewEntry->mnPageNumOfAnchor = pPageFrameOfAnchor->GetPhyPageNum();
75 else
77 pNewEntry->mnPageNumOfAnchor = 0;
79 // --> #i26945# - collect type of anchor
80 SwTextFrame* pAnchorCharFrame = _rAnchoredObj.FindAnchorCharFrame();
81 if ( pAnchorCharFrame )
83 pNewEntry->mbAnchoredAtMaster = !pAnchorCharFrame->IsFollow();
85 else
87 pNewEntry->mbAnchoredAtMaster = true;
89 maObjList.push_back( pNewEntry );
92 SwAnchoredObject* operator[]( sal_uInt32 _nIndex )
94 SwAnchoredObject* bRetObj = nullptr;
96 if ( _nIndex < Count())
98 bRetObj = maObjList[_nIndex]->mpAnchoredObj;
101 return bRetObj;
104 sal_uInt32 GetPageNum( sal_uInt32 _nIndex ) const
106 sal_uInt32 nRetPgNum = 0;
108 if ( _nIndex < Count())
110 nRetPgNum = maObjList[_nIndex]->mnPageNumOfAnchor;
113 return nRetPgNum;
116 // --> #i26945#
117 bool AnchoredAtMaster( sal_uInt32 _nIndex )
119 bool bAnchoredAtMaster( true );
121 if ( _nIndex < Count())
123 bAnchoredAtMaster = maObjList[_nIndex]->mbAnchoredAtMaster;
126 return bAnchoredAtMaster;
129 sal_uInt32 Count() const
131 return maObjList.size();
135 SwObjectFormatter::SwObjectFormatter( const SwPageFrame& _rPageFrame,
136 SwLayAction* _pLayAction,
137 const bool _bCollectPgNumOfAnchors )
138 : mrPageFrame( _rPageFrame ),
139 mbConsiderWrapOnObjPos( _rPageFrame.GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ),
140 mpLayAction( _pLayAction ),
141 // --> #i26945#
142 mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors ? new SwPageNumAndTypeOfAnchors() : nullptr )
146 SwObjectFormatter::~SwObjectFormatter()
150 SwObjectFormatter* SwObjectFormatter::CreateObjFormatter(
151 SwFrame& _rAnchorFrame,
152 const SwPageFrame& _rPageFrame,
153 SwLayAction* _pLayAction )
155 SwObjectFormatter* pObjFormatter = nullptr;
156 if ( _rAnchorFrame.IsTextFrame() )
158 pObjFormatter = SwObjectFormatterTextFrame::CreateObjFormatter(
159 static_cast<SwTextFrame&>(_rAnchorFrame),
160 _rPageFrame, _pLayAction );
162 else if ( _rAnchorFrame.IsLayoutFrame() )
164 pObjFormatter = SwObjectFormatterLayFrame::CreateObjFormatter(
165 static_cast<SwLayoutFrame&>(_rAnchorFrame),
166 _rPageFrame, _pLayAction );
168 else
170 OSL_FAIL( "<SwObjectFormatter::CreateObjFormatter(..)> - unexpected type of anchor frame" );
173 return pObjFormatter;
176 /** method to format all floating screen objects at the given anchor frame
178 bool SwObjectFormatter::FormatObjsAtFrame( SwFrame& _rAnchorFrame,
179 const SwPageFrame& _rPageFrame,
180 SwLayAction* _pLayAction )
182 bool bSuccess( true );
184 // create corresponding object formatter
185 SwObjectFormatter* pObjFormatter =
186 SwObjectFormatter::CreateObjFormatter( _rAnchorFrame, _rPageFrame, _pLayAction );
188 if ( pObjFormatter )
190 // format anchored floating screen objects
191 bSuccess = pObjFormatter->DoFormatObjs();
193 delete pObjFormatter;
195 return bSuccess;
198 /** method to format a given floating screen object
200 bool SwObjectFormatter::FormatObj( SwAnchoredObject& _rAnchoredObj,
201 SwFrame* _pAnchorFrame,
202 const SwPageFrame* _pPageFrame )
204 bool bSuccess( true );
206 OSL_ENSURE( _pAnchorFrame || _rAnchoredObj.GetAnchorFrame(),
207 "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
208 SwFrame& rAnchorFrame = _pAnchorFrame ? *_pAnchorFrame : *(_rAnchoredObj.AnchorFrame());
210 OSL_ENSURE( _pPageFrame || rAnchorFrame.FindPageFrame(),
211 "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
212 const SwPageFrame& rPageFrame = _pPageFrame ? *_pPageFrame : *(rAnchorFrame.FindPageFrame());
214 // create corresponding object formatter
215 SwObjectFormatter* pObjFormatter =
216 SwObjectFormatter::CreateObjFormatter( rAnchorFrame, rPageFrame, nullptr/*_pLayAction*/ );
218 if ( pObjFormatter )
220 // format given floating screen object
221 // --> #i40147# - check for moved forward anchor frame
222 bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
224 delete pObjFormatter;
226 return bSuccess;
229 /** helper method for method <FormatObj_(..)> - performs the intrinsic format
230 of the layout of the given layout frame and all its lower layout frames.
232 #i28701#
233 IMPORTANT NOTE:
234 Method corresponds to methods <SwLayAction::FormatLayoutFly(..)> and
235 <SwLayAction::FormatLayout(..)>. Thus, its code for the formatting have
236 to be synchronised.
238 void SwObjectFormatter::FormatLayout_( SwLayoutFrame& _rLayoutFrame )
240 _rLayoutFrame.Calc(_rLayoutFrame.getRootFrame()->GetCurrShell()->GetOut());
242 SwFrame* pLowerFrame = _rLayoutFrame.Lower();
243 while ( pLowerFrame )
245 if ( pLowerFrame->IsLayoutFrame() )
247 FormatLayout_( *static_cast<SwLayoutFrame*>(pLowerFrame) );
249 pLowerFrame = pLowerFrame->GetNext();
253 /** helper method for method <FormatObj_(..)> - performs the intrinsic
254 format of the content of the given floating screen object.
256 #i28701#
258 void SwObjectFormatter::FormatObjContent( SwAnchoredObject& _rAnchoredObj )
260 if ( dynamic_cast<const SwFlyFrame*>( &_rAnchoredObj) == nullptr )
262 // only Writer fly frames have content
263 return;
266 SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
267 SwContentFrame* pContent = rFlyFrame.ContainsContent();
269 while ( pContent )
271 // format content
272 pContent->OptCalc();
274 // format floating screen objects at content text frame
275 // #i23129#, #i36347# - pass correct page frame to
276 // the object formatter
277 if ( pContent->IsTextFrame() &&
278 !SwObjectFormatter::FormatObjsAtFrame( *pContent,
279 *(pContent->FindPageFrame()),
280 GetLayAction() ) )
282 // restart format with first content
283 pContent = rFlyFrame.ContainsContent();
284 continue;
287 // continue with next content
288 pContent = pContent->GetNextContentFrame();
292 /** performs the intrinsic format of a given floating screen object and its content.
294 #i28701#
296 void SwObjectFormatter::FormatObj_( SwAnchoredObject& _rAnchoredObj )
298 // collect anchor object and its 'anchor' page number, if requested
299 if ( mpPgNumAndTypeOfAnchors )
301 mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj );
304 if ( dynamic_cast<const SwFlyFrame*>( &_rAnchoredObj) != nullptr )
306 SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
307 // --> #i34753# - reset flag, which prevents a positioning
308 if ( rFlyFrame.IsFlyLayFrame() )
310 static_cast<SwFlyLayFrame&>(rFlyFrame).SetNoMakePos( false );
313 // #i81146# new loop control
314 int nLoopControlRuns = 0;
315 const int nLoopControlMax = 15;
317 do {
318 if ( mpLayAction )
320 mpLayAction->FormatLayoutFly( &rFlyFrame );
321 // --> consider, if the layout action
322 // has to be restarted due to a delete of a page frame.
323 if ( mpLayAction->IsAgain() )
325 break;
328 else
330 FormatLayout_( rFlyFrame );
332 // --> #i34753# - prevent further positioning, if
333 // to-page|to-fly anchored Writer fly frame is already clipped.
334 if ( rFlyFrame.IsFlyLayFrame() && rFlyFrame.IsClipped() )
336 static_cast<SwFlyLayFrame&>(rFlyFrame).SetNoMakePos( true );
338 // #i23129#, #i36347# - pass correct page frame
339 // to the object formatter
340 SwObjectFormatter::FormatObjsAtFrame( rFlyFrame,
341 *(rFlyFrame.FindPageFrame()),
342 mpLayAction );
343 if ( mpLayAction )
345 mpLayAction->FormatFlyContent( &rFlyFrame );
346 // --> consider, if the layout action
347 // has to be restarted due to a delete of a page frame.
348 if ( mpLayAction->IsAgain() )
350 break;
353 else
355 FormatObjContent( rFlyFrame );
358 if ( ++nLoopControlRuns >= nLoopControlMax )
360 OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
361 rFlyFrame.ValidateThisAndAllLowers( 2 );
362 nLoopControlRuns = 0;
365 // --> #i57917#
366 // stop formatting of anchored object, if restart of layout process is requested.
367 } while ( !rFlyFrame.isFrameAreaDefinitionValid() &&
368 !_rAnchoredObj.RestartLayoutProcess() &&
369 rFlyFrame.GetAnchorFrame() == &GetAnchorFrame() );
371 else if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rAnchoredObj) != nullptr )
373 _rAnchoredObj.MakeObjPos();
377 /** invokes the intrinsic format method for all floating screen objects,
378 anchored at anchor frame on the given page frame
380 #i28701#
381 #i26945# - for format of floating screen objects for
382 follow text frames, the 'master' text frame is passed to the method.
383 Thus, the objects, whose anchor character is inside the follow text
384 frame can be formatted.
386 bool SwObjectFormatter::FormatObjsAtFrame_( SwTextFrame* _pMasterTextFrame )
388 // --> #i26945#
389 SwFrame* pAnchorFrame( nullptr );
390 if ( GetAnchorFrame().IsTextFrame() &&
391 static_cast<SwTextFrame&>(GetAnchorFrame()).IsFollow() &&
392 _pMasterTextFrame )
394 pAnchorFrame = _pMasterTextFrame;
396 else
398 pAnchorFrame = &GetAnchorFrame();
400 if ( !pAnchorFrame->GetDrawObjs() )
402 // nothing to do, if no floating screen object is registered at the anchor frame.
403 return true;
406 bool bSuccess( true );
408 for ( size_t i = 0; i < pAnchorFrame->GetDrawObjs()->size(); ++i )
410 SwAnchoredObject* pAnchoredObj = (*pAnchorFrame->GetDrawObjs())[i];
412 // check, if object's anchor is on the given page frame or
413 // object is registered at the given page frame.
414 // --> #i26945# - check, if the anchor character of the
415 // anchored object is located in a follow text frame. If this anchor
416 // follow text frame differs from the given anchor frame, the given
417 // anchor frame is a 'master' text frame of the anchor follow text frame.
418 // If the anchor follow text frame is in the same body as its 'master'
419 // text frame, do not format the anchored object.
420 // E.g., this situation can occur during the table row splitting algorithm.
421 SwTextFrame* pAnchorCharFrame = pAnchoredObj->FindAnchorCharFrame();
422 const bool bAnchoredAtFollowInSameBodyAsMaster =
423 pAnchorCharFrame && pAnchorCharFrame->IsFollow() &&
424 pAnchorCharFrame != pAnchoredObj->GetAnchorFrame() &&
425 pAnchorCharFrame->FindBodyFrame() ==
426 static_cast<SwTextFrame*>(pAnchoredObj->AnchorFrame())->FindBodyFrame();
427 if ( bAnchoredAtFollowInSameBodyAsMaster )
429 continue;
431 // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
432 // is replaced by method <FindPageFrameOfAnchor()>. It's return value
433 // have to be checked.
434 SwPageFrame* pPageFrameOfAnchor = pAnchoredObj->FindPageFrameOfAnchor();
435 OSL_ENSURE( pPageFrameOfAnchor,
436 "<SwObjectFormatter::FormatObjsAtFrame_()> - missing page frame." );
437 // --> #i26945#
438 if ( pPageFrameOfAnchor && pPageFrameOfAnchor == &mrPageFrame )
440 // if format of object fails, stop formatting and pass fail to
441 // calling method via the return value.
442 if ( !DoFormatObj( *pAnchoredObj ) )
444 bSuccess = false;
445 break;
448 // considering changes at <pAnchorFrame->GetDrawObjs()> during
449 // format of the object.
450 if ( !pAnchorFrame->GetDrawObjs() ||
451 i > pAnchorFrame->GetDrawObjs()->size() )
453 break;
455 else
457 const size_t nActPosOfObj =
458 pAnchorFrame->GetDrawObjs()->ListPosOf( *pAnchoredObj );
459 if ( nActPosOfObj == pAnchorFrame->GetDrawObjs()->size() ||
460 nActPosOfObj > i )
462 --i;
464 else if ( nActPosOfObj < i )
466 i = nActPosOfObj;
470 } // end of loop on <pAnchorFrame->.GetDrawObjs()>
472 return bSuccess;
475 /** accessor to collected anchored object
477 #i28701#
479 SwAnchoredObject* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex )
481 return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : nullptr;
484 /** accessor to 'anchor' page number of collected anchored object
486 #i28701#
488 sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex )
490 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0;
493 /** accessor to 'anchor' type of collected anchored object
495 #i26945#
497 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex )
499 return mpPgNumAndTypeOfAnchors == nullptr
500 || mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex);
503 /** accessor to total number of collected anchored objects
505 #i28701#
507 sal_uInt32 SwObjectFormatter::CountOfCollected()
509 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0;
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */