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 <fmtanchr.hxx>
31 #include <IDocumentSettingAccess.hxx>
35 // --> #i26945# - Additionally the type of the anchor text frame
36 // is collected - by type is meant 'master' or 'follow'.
37 class SwPageNumAndTypeOfAnchors
42 SwAnchoredObject
* mpAnchoredObj
;
43 sal_uInt32 mnPageNumOfAnchor
;
44 bool mbAnchoredAtMaster
;
47 std::vector
< tEntry
* > maObjList
;
50 SwPageNumAndTypeOfAnchors()
53 ~SwPageNumAndTypeOfAnchors()
55 for ( std::vector
< tEntry
* >::iterator aIter
= maObjList
.begin();
56 aIter
!= maObjList
.end(); ++aIter
)
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();
77 pNewEntry
->mnPageNumOfAnchor
= 0;
79 // --> #i26945# - collect type of anchor
80 SwTextFrame
* pAnchorCharFrame
= _rAnchoredObj
.FindAnchorCharFrame();
81 if ( pAnchorCharFrame
)
83 pNewEntry
->mbAnchoredAtMaster
= !pAnchorCharFrame
->IsFollow();
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
;
104 sal_uInt32
GetPageNum( sal_uInt32 _nIndex
) const
106 sal_uInt32 nRetPgNum
= 0;
108 if ( _nIndex
< Count())
110 nRetPgNum
= maObjList
[_nIndex
]->mnPageNumOfAnchor
;
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
),
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
);
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
);
190 // format anchored floating screen objects
191 bSuccess
= pObjFormatter
->DoFormatObjs();
193 delete pObjFormatter
;
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*/ );
220 // format given floating screen object
221 // --> #i40147# - check for moved forward anchor frame
222 bSuccess
= pObjFormatter
->DoFormatObj( _rAnchoredObj
, true );
224 delete pObjFormatter
;
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.
234 Method corresponds to methods <SwLayAction::FormatLayoutFly(..)> and
235 <SwLayAction::FormatLayout(..)>. Thus, its code for the formatting have
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.
258 void SwObjectFormatter::FormatObjContent( SwAnchoredObject
& _rAnchoredObj
)
260 if ( dynamic_cast<const SwFlyFrame
*>( &_rAnchoredObj
) == nullptr )
262 // only Writer fly frames have content
266 SwFlyFrame
& rFlyFrame
= static_cast<SwFlyFrame
&>(_rAnchoredObj
);
267 SwContentFrame
* pContent
= rFlyFrame
.ContainsContent();
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()),
282 // restart format with first content
283 pContent
= rFlyFrame
.ContainsContent();
287 // continue with next content
288 pContent
= pContent
->GetNextContentFrame();
292 /** performs the intrinsic format of a given floating screen object and its content.
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;
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() )
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()),
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() )
355 FormatObjContent( rFlyFrame
);
358 if ( ++nLoopControlRuns
>= nLoopControlMax
)
360 OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
361 rFlyFrame
.ValidateThisAndAllLowers( 2 );
362 nLoopControlRuns
= 0;
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
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
)
389 SwFrame
* pAnchorFrame( nullptr );
390 if ( GetAnchorFrame().IsTextFrame() &&
391 static_cast<SwTextFrame
&>(GetAnchorFrame()).IsFollow() &&
394 pAnchorFrame
= _pMasterTextFrame
;
398 pAnchorFrame
= &GetAnchorFrame();
400 if ( !pAnchorFrame
->GetDrawObjs() )
402 // nothing to do, if no floating screen object is registered at the anchor frame.
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
)
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." );
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
) )
448 // considering changes at <pAnchorFrame->GetDrawObjs()> during
449 // format of the object.
450 if ( !pAnchorFrame
->GetDrawObjs() ||
451 i
> pAnchorFrame
->GetDrawObjs()->size() )
457 const size_t nActPosOfObj
=
458 pAnchorFrame
->GetDrawObjs()->ListPosOf( *pAnchoredObj
);
459 if ( nActPosOfObj
== pAnchorFrame
->GetDrawObjs()->size() ||
464 else if ( nActPosOfObj
< i
)
470 } // end of loop on <pAnchorFrame->.GetDrawObjs()>
475 /** accessor to collected anchored object
479 SwAnchoredObject
* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex
)
481 return mpPgNumAndTypeOfAnchors
? (*mpPgNumAndTypeOfAnchors
)[_nIndex
] : nullptr;
484 /** accessor to 'anchor' page number of collected anchored object
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
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
507 sal_uInt32
SwObjectFormatter::CountOfCollected()
509 return mpPgNumAndTypeOfAnchors
? mpPgNumAndTypeOfAnchors
->Count() : 0;
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */