Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / layout / objectformatter.cxx
blobb99da6a0fe4b72ab589863da62e740fe111f2302
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 )
172 bool bSuccess( true );
174 OSL_ENSURE( _pAnchorFrame || _rAnchoredObj.GetAnchorFrame(),
175 "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
176 SwFrame& rAnchorFrame = _pAnchorFrame ? *_pAnchorFrame : *(_rAnchoredObj.AnchorFrame());
178 OSL_ENSURE( _pPageFrame || rAnchorFrame.FindPageFrame(),
179 "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
180 const SwPageFrame& rPageFrame = _pPageFrame ? *_pPageFrame : *(rAnchorFrame.FindPageFrame());
182 // create corresponding object formatter
183 std::unique_ptr<SwObjectFormatter> pObjFormatter =
184 SwObjectFormatter::CreateObjFormatter( rAnchorFrame, rPageFrame, nullptr/*_pLayAction*/ );
186 if ( pObjFormatter )
188 // format given floating screen object
189 // --> #i40147# - check for moved forward anchor frame
190 bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
193 return bSuccess;
196 /** helper method for method <FormatObj_(..)> - performs the intrinsic format
197 of the layout of the given layout frame and all its lower layout frames.
199 #i28701#
200 IMPORTANT NOTE:
201 Method corresponds to methods <SwLayAction::FormatLayoutFly(..)> and
202 <SwLayAction::FormatLayout(..)>. Thus, its code for the formatting have
203 to be synchronised.
205 void SwObjectFormatter::FormatLayout_( SwLayoutFrame& _rLayoutFrame )
207 _rLayoutFrame.Calc(_rLayoutFrame.getRootFrame()->GetCurrShell()->GetOut());
209 SwFrame* pLowerFrame = _rLayoutFrame.Lower();
210 while ( pLowerFrame )
212 if ( pLowerFrame->IsLayoutFrame() )
214 FormatLayout_( *static_cast<SwLayoutFrame*>(pLowerFrame) );
216 pLowerFrame = pLowerFrame->GetNext();
220 /** helper method for method <FormatObj_(..)> - performs the intrinsic
221 format of the content of the given floating screen object.
223 #i28701#
225 void SwObjectFormatter::FormatObjContent( SwAnchoredObject& _rAnchoredObj )
227 if ( !_rAnchoredObj.DynCastFlyFrame() )
229 // only Writer fly frames have content
230 return;
233 SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
234 SwContentFrame* pContent = rFlyFrame.ContainsContent();
236 while ( pContent )
238 // format content
239 pContent->OptCalc();
241 // format floating screen objects at content text frame
242 // #i23129#, #i36347# - pass correct page frame to
243 // the object formatter
244 if ( pContent->IsTextFrame() &&
245 !SwObjectFormatter::FormatObjsAtFrame( *pContent,
246 *(pContent->FindPageFrame()),
247 GetLayAction() ) )
249 // restart format with first content
250 pContent = rFlyFrame.ContainsContent();
251 continue;
254 // continue with next content
255 pContent = pContent->GetNextContentFrame();
259 /** performs the intrinsic format of a given floating screen object and its content.
261 #i28701#
263 void SwObjectFormatter::FormatObj_( SwAnchoredObject& _rAnchoredObj )
265 // collect anchor object and its 'anchor' page number, if requested
266 if ( mpPgNumAndTypeOfAnchors )
268 mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj );
271 if ( auto pFlyFrame = _rAnchoredObj.DynCastFlyFrame() )
273 // --> #i34753# - reset flag, which prevents a positioning
274 if ( pFlyFrame->IsFlyLayFrame() )
276 static_cast<SwFlyLayFrame*>(pFlyFrame)->SetNoMakePos( false );
279 // #i81146# new loop control
280 int nLoopControlRuns = 0;
281 const int nLoopControlMax = 15;
283 do {
284 if ( mpLayAction )
286 mpLayAction->FormatLayoutFly( pFlyFrame );
287 // --> consider, if the layout action
288 // has to be restarted due to a delete of a page frame.
289 if ( mpLayAction->IsAgain() )
291 break;
294 else
296 FormatLayout_( *pFlyFrame );
298 // --> #i34753# - prevent further positioning, if
299 // to-page|to-fly anchored Writer fly frame is already clipped.
300 if ( pFlyFrame->IsFlyLayFrame() && pFlyFrame->IsClipped() )
302 static_cast<SwFlyLayFrame*>(pFlyFrame)->SetNoMakePos( true );
304 // #i23129#, #i36347# - pass correct page frame
305 // to the object formatter
306 SwObjectFormatter::FormatObjsAtFrame( *pFlyFrame,
307 *(pFlyFrame->FindPageFrame()),
308 mpLayAction );
309 if ( mpLayAction )
311 mpLayAction->FormatFlyContent( pFlyFrame );
312 // --> consider, if the layout action
313 // has to be restarted due to a delete of a page frame.
314 if ( mpLayAction->IsAgain() )
316 break;
319 else
321 FormatObjContent( *pFlyFrame );
324 if ( ++nLoopControlRuns >= nLoopControlMax )
326 OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
327 pFlyFrame->ValidateThisAndAllLowers( 2 );
328 nLoopControlRuns = 0;
331 // --> #i57917#
332 // stop formatting of anchored object, if restart of layout process is requested.
333 } while ( !pFlyFrame->isFrameAreaDefinitionValid() &&
334 !_rAnchoredObj.RestartLayoutProcess() &&
335 pFlyFrame->GetAnchorFrame() == &GetAnchorFrame() );
337 else if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rAnchoredObj) != nullptr )
339 _rAnchoredObj.MakeObjPos();
343 /** invokes the intrinsic format method for all floating screen objects,
344 anchored at anchor frame on the given page frame
346 #i28701#
347 #i26945# - for format of floating screen objects for
348 follow text frames, the 'master' text frame is passed to the method.
349 Thus, the objects, whose anchor character is inside the follow text
350 frame can be formatted.
352 bool SwObjectFormatter::FormatObjsAtFrame_( SwTextFrame* _pMasterTextFrame )
354 // --> #i26945#
355 SwFrame* pAnchorFrame( nullptr );
356 if ( GetAnchorFrame().IsTextFrame() &&
357 static_cast<SwTextFrame&>(GetAnchorFrame()).IsFollow() &&
358 _pMasterTextFrame )
360 pAnchorFrame = _pMasterTextFrame;
362 else
364 pAnchorFrame = &GetAnchorFrame();
366 if ( !pAnchorFrame->GetDrawObjs() )
368 // nothing to do, if no floating screen object is registered at the anchor frame.
369 return true;
372 bool bSuccess( true );
374 for ( size_t i = 0; i < pAnchorFrame->GetDrawObjs()->size(); ++i )
376 SwAnchoredObject* pAnchoredObj = (*pAnchorFrame->GetDrawObjs())[i];
378 // check, if object's anchor is on the given page frame or
379 // object is registered at the given page frame.
380 // --> #i26945# - check, if the anchor character of the
381 // anchored object is located in a follow text frame. If this anchor
382 // follow text frame differs from the given anchor frame, the given
383 // anchor frame is a 'master' text frame of the anchor follow text frame.
384 // If the anchor follow text frame is in the same body as its 'master'
385 // text frame, do not format the anchored object.
386 // E.g., this situation can occur during the table row splitting algorithm.
387 SwTextFrame* pAnchorCharFrame = pAnchoredObj->FindAnchorCharFrame();
388 const bool bAnchoredAtFollowInSameBodyAsMaster =
389 pAnchorCharFrame && pAnchorCharFrame->IsFollow() &&
390 pAnchorCharFrame != pAnchoredObj->GetAnchorFrame() &&
391 pAnchorCharFrame->FindBodyFrame() ==
392 static_cast<SwTextFrame*>(pAnchoredObj->AnchorFrame())->FindBodyFrame();
393 // Make sure that in case nested split flys are moved "out of range" in
394 // lcl_InvalidateLowerObjs(), then we moved them back here.
395 SwFlyFrame* pFly = pAnchoredObj->DynCastFlyFrame();
396 bool bSplitFly = pFly && pFly->IsFlySplitAllowed();
397 bool bNestedSplitFly = bSplitFly && pAnchorCharFrame && pAnchorCharFrame->IsInFly();
398 if (bAnchoredAtFollowInSameBodyAsMaster && !bNestedSplitFly)
400 continue;
402 // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
403 // is replaced by method <FindPageFrameOfAnchor()>. It's return value
404 // have to be checked.
405 SwPageFrame* pPageFrameOfAnchor = pAnchoredObj->FindPageFrameOfAnchor();
406 OSL_ENSURE( pPageFrameOfAnchor,
407 "<SwObjectFormatter::FormatObjsAtFrame_()> - missing page frame." );
408 // --> #i26945#
409 if ( pPageFrameOfAnchor && pPageFrameOfAnchor == &mrPageFrame )
411 // if format of object fails, stop formatting and pass fail to
412 // calling method via the return value.
413 if ( !DoFormatObj( *pAnchoredObj ) )
415 bSuccess = false;
416 break;
419 // considering changes at <pAnchorFrame->GetDrawObjs()> during
420 // format of the object.
421 if ( !pAnchorFrame->GetDrawObjs() ||
422 i > pAnchorFrame->GetDrawObjs()->size() )
424 break;
426 else
428 const size_t nActPosOfObj =
429 pAnchorFrame->GetDrawObjs()->ListPosOf( *pAnchoredObj );
430 if ( nActPosOfObj == pAnchorFrame->GetDrawObjs()->size() ||
431 nActPosOfObj > i )
433 --i;
435 else if ( nActPosOfObj < i )
437 i = nActPosOfObj;
441 } // end of loop on <pAnchorFrame->.GetDrawObjs()>
443 return bSuccess;
446 /** accessor to collected anchored object
448 #i28701#
450 SwAnchoredObject* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex )
452 return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : nullptr;
455 /** accessor to 'anchor' page number of collected anchored object
457 #i28701#
459 sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex )
461 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0;
464 /** accessor to 'anchor' type of collected anchored object
466 #i26945#
468 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex )
470 return mpPgNumAndTypeOfAnchors == nullptr
471 || mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex);
474 /** accessor to total number of collected anchored objects
476 #i28701#
478 sal_uInt32 SwObjectFormatter::CountOfCollected()
480 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0;
483 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */