1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
31
32 #include <vector>
33
34 // --> #i26945# - Additionally the type of the anchor text frame
35 // is collected - by type is meant 'master' or 'follow'.
36 class SwPageNumAndTypeOfAnchors
37 {
38 private:
39 struct tEntry
40 {
41 SwAnchoredObject* mpAnchoredObj;
42 sal_uInt32 mnPageNumOfAnchor;
43 bool mbAnchoredAtMaster;
44 };
45
46 std::vector< tEntry > maObjList;
47
48 public:
SwPageNumAndTypeOfAnchors()49 SwPageNumAndTypeOfAnchors()
50 {
51 }
52
Collect(SwAnchoredObject & _rAnchoredObj)53 void Collect( SwAnchoredObject& _rAnchoredObj )
54 {
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 )
62 {
63 aNewEntry.mnPageNumOfAnchor = pPageFrameOfAnchor->GetPhyPageNum();
64 }
65 else
66 {
67 aNewEntry.mnPageNumOfAnchor = 0;
68 }
69 // --> #i26945# - collect type of anchor
70 SwTextFrame* pAnchorCharFrame = _rAnchoredObj.FindAnchorCharFrame();
71 if ( pAnchorCharFrame )
72 {
73 aNewEntry.mbAnchoredAtMaster = !pAnchorCharFrame->IsFollow();
74 }
75 else
76 {
77 aNewEntry.mbAnchoredAtMaster = true;
78 }
79 maObjList.push_back( aNewEntry );
80 }
81
operator [](sal_uInt32 _nIndex)82 SwAnchoredObject* operator[]( sal_uInt32 _nIndex )
83 {
84 return maObjList[_nIndex].mpAnchoredObj;
85 }
86
GetPageNum(sal_uInt32 _nIndex) const87 sal_uInt32 GetPageNum( sal_uInt32 _nIndex ) const
88 {
89 return maObjList[_nIndex].mnPageNumOfAnchor;
90 }
91
92 // --> #i26945#
AnchoredAtMaster(sal_uInt32 _nIndex)93 bool AnchoredAtMaster( sal_uInt32 _nIndex )
94 {
95 return maObjList[_nIndex].mbAnchoredAtMaster;
96 }
97
Count() const98 sal_uInt32 Count() const
99 {
100 return maObjList.size();
101 }
102 };
103
SwObjectFormatter(const SwPageFrame & _rPageFrame,SwLayAction * _pLayAction,const bool _bCollectPgNumOfAnchors)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 )
112 {
113 }
114
~SwObjectFormatter()115 SwObjectFormatter::~SwObjectFormatter()
116 {
117 }
118
CreateObjFormatter(SwFrame & _rAnchorFrame,const SwPageFrame & _rPageFrame,SwLayAction * _pLayAction)119 std::unique_ptr<SwObjectFormatter> SwObjectFormatter::CreateObjFormatter(
120 SwFrame& _rAnchorFrame,
121 const SwPageFrame& _rPageFrame,
122 SwLayAction* _pLayAction )
123 {
124 std::unique_ptr<SwObjectFormatter> pObjFormatter;
125 if ( _rAnchorFrame.IsTextFrame() )
126 {
127 pObjFormatter = SwObjectFormatterTextFrame::CreateObjFormatter(
128 static_cast<SwTextFrame&>(_rAnchorFrame),
129 _rPageFrame, _pLayAction );
130 }
131 else if ( _rAnchorFrame.IsLayoutFrame() )
132 {
133 pObjFormatter = SwObjectFormatterLayFrame::CreateObjFormatter(
134 static_cast<SwLayoutFrame&>(_rAnchorFrame),
135 _rPageFrame, _pLayAction );
136 }
137 else
138 {
139 OSL_FAIL( "<SwObjectFormatter::CreateObjFormatter(..)> - unexpected type of anchor frame" );
140 }
141
142 return pObjFormatter;
143 }
144
145 /** method to format all floating screen objects at the given anchor frame
146 */
FormatObjsAtFrame(SwFrame & _rAnchorFrame,const SwPageFrame & _rPageFrame,SwLayAction * _pLayAction)147 bool SwObjectFormatter::FormatObjsAtFrame( SwFrame& _rAnchorFrame,
148 const SwPageFrame& _rPageFrame,
149 SwLayAction* _pLayAction )
150 {
151 bool bSuccess( true );
152
153 // create corresponding object formatter
154 std::unique_ptr<SwObjectFormatter> pObjFormatter =
155 SwObjectFormatter::CreateObjFormatter( _rAnchorFrame, _rPageFrame, _pLayAction );
156
157 if ( pObjFormatter )
158 {
159 // format anchored floating screen objects
160 bSuccess = pObjFormatter->DoFormatObjs();
161 }
162
163 return bSuccess;
164 }
165
166 /** method to format a given floating screen object
167 */
FormatObj(SwAnchoredObject & _rAnchoredObj,SwFrame * _pAnchorFrame,const SwPageFrame * _pPageFrame)168 bool SwObjectFormatter::FormatObj( SwAnchoredObject& _rAnchoredObj,
169 SwFrame* _pAnchorFrame,
170 const SwPageFrame* _pPageFrame )
171 {
172 bool bSuccess( true );
173
174 OSL_ENSURE( _pAnchorFrame || _rAnchoredObj.GetAnchorFrame(),
175 "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
176 SwFrame& rAnchorFrame = _pAnchorFrame ? *_pAnchorFrame : *(_rAnchoredObj.AnchorFrame());
177
178 OSL_ENSURE( _pPageFrame || rAnchorFrame.FindPageFrame(),
179 "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
180 const SwPageFrame& rPageFrame = _pPageFrame ? *_pPageFrame : *(rAnchorFrame.FindPageFrame());
181
182 // create corresponding object formatter
183 std::unique_ptr<SwObjectFormatter> pObjFormatter =
184 SwObjectFormatter::CreateObjFormatter( rAnchorFrame, rPageFrame, nullptr/*_pLayAction*/ );
185
186 if ( pObjFormatter )
187 {
188 // format given floating screen object
189 // --> #i40147# - check for moved forward anchor frame
190 bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
191 }
192
193 return bSuccess;
194 }
195
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.
198
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.
204 */
FormatLayout_(SwLayoutFrame & _rLayoutFrame)205 void SwObjectFormatter::FormatLayout_( SwLayoutFrame& _rLayoutFrame )
206 {
207 _rLayoutFrame.Calc(_rLayoutFrame.getRootFrame()->GetCurrShell()->GetOut());
208
209 SwFrame* pLowerFrame = _rLayoutFrame.Lower();
210 while ( pLowerFrame )
211 {
212 if ( pLowerFrame->IsLayoutFrame() )
213 {
214 FormatLayout_( *static_cast<SwLayoutFrame*>(pLowerFrame) );
215 }
216 pLowerFrame = pLowerFrame->GetNext();
217 }
218 }
219
220 /** helper method for method <FormatObj_(..)> - performs the intrinsic
221 format of the content of the given floating screen object.
222
223 #i28701#
224 */
FormatObjContent(SwAnchoredObject & _rAnchoredObj)225 void SwObjectFormatter::FormatObjContent( SwAnchoredObject& _rAnchoredObj )
226 {
227 if ( dynamic_cast<const SwFlyFrame*>( &_rAnchoredObj) == nullptr )
228 {
229 // only Writer fly frames have content
230 return;
231 }
232
233 SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
234 SwContentFrame* pContent = rFlyFrame.ContainsContent();
235
236 while ( pContent )
237 {
238 // format content
239 pContent->OptCalc();
240
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() ) )
248 {
249 // restart format with first content
250 pContent = rFlyFrame.ContainsContent();
251 continue;
252 }
253
254 // continue with next content
255 pContent = pContent->GetNextContentFrame();
256 }
257 }
258
259 /** performs the intrinsic format of a given floating screen object and its content.
260
261 #i28701#
262 */
FormatObj_(SwAnchoredObject & _rAnchoredObj)263 void SwObjectFormatter::FormatObj_( SwAnchoredObject& _rAnchoredObj )
264 {
265 // collect anchor object and its 'anchor' page number, if requested
266 if ( mpPgNumAndTypeOfAnchors )
267 {
268 mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj );
269 }
270
271 if ( auto pFlyFrame = dynamic_cast<SwFlyFrame*>( &_rAnchoredObj) )
272 {
273 // --> #i34753# - reset flag, which prevents a positioning
274 if ( pFlyFrame->IsFlyLayFrame() )
275 {
276 static_cast<SwFlyLayFrame*>(pFlyFrame)->SetNoMakePos( false );
277 }
278
279 // #i81146# new loop control
280 int nLoopControlRuns = 0;
281 const int nLoopControlMax = 15;
282
283 do {
284 if ( mpLayAction )
285 {
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() )
290 {
291 break;
292 }
293 }
294 else
295 {
296 FormatLayout_( *pFlyFrame );
297 }
298 // --> #i34753# - prevent further positioning, if
299 // to-page|to-fly anchored Writer fly frame is already clipped.
300 if ( pFlyFrame->IsFlyLayFrame() && pFlyFrame->IsClipped() )
301 {
302 static_cast<SwFlyLayFrame*>(pFlyFrame)->SetNoMakePos( true );
303 }
304 // #i23129#, #i36347# - pass correct page frame
305 // to the object formatter
306 SwObjectFormatter::FormatObjsAtFrame( *pFlyFrame,
307 *(pFlyFrame->FindPageFrame()),
308 mpLayAction );
309 if ( mpLayAction )
310 {
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() )
315 {
316 break;
317 }
318 }
319 else
320 {
321 FormatObjContent( *pFlyFrame );
322 }
323
324 if ( ++nLoopControlRuns >= nLoopControlMax )
325 {
326 OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
327 pFlyFrame->ValidateThisAndAllLowers( 2 );
328 nLoopControlRuns = 0;
329 }
330
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() );
336 }
337 else if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rAnchoredObj) != nullptr )
338 {
339 _rAnchoredObj.MakeObjPos();
340 }
341 }
342
343 /** invokes the intrinsic format method for all floating screen objects,
344 anchored at anchor frame on the given page frame
345
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.
351 */
FormatObjsAtFrame_(SwTextFrame * _pMasterTextFrame)352 bool SwObjectFormatter::FormatObjsAtFrame_( SwTextFrame* _pMasterTextFrame )
353 {
354 // --> #i26945#
355 SwFrame* pAnchorFrame( nullptr );
356 if ( GetAnchorFrame().IsTextFrame() &&
357 static_cast<SwTextFrame&>(GetAnchorFrame()).IsFollow() &&
358 _pMasterTextFrame )
359 {
360 pAnchorFrame = _pMasterTextFrame;
361 }
362 else
363 {
364 pAnchorFrame = &GetAnchorFrame();
365 }
366 if ( !pAnchorFrame->GetDrawObjs() )
367 {
368 // nothing to do, if no floating screen object is registered at the anchor frame.
369 return true;
370 }
371
372 bool bSuccess( true );
373
374 for ( size_t i = 0; i < pAnchorFrame->GetDrawObjs()->size(); ++i )
375 {
376 SwAnchoredObject* pAnchoredObj = (*pAnchorFrame->GetDrawObjs())[i];
377
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 if ( bAnchoredAtFollowInSameBodyAsMaster )
394 {
395 continue;
396 }
397 // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
398 // is replaced by method <FindPageFrameOfAnchor()>. It's return value
399 // have to be checked.
400 SwPageFrame* pPageFrameOfAnchor = pAnchoredObj->FindPageFrameOfAnchor();
401 OSL_ENSURE( pPageFrameOfAnchor,
402 "<SwObjectFormatter::FormatObjsAtFrame_()> - missing page frame." );
403 // --> #i26945#
404 if ( pPageFrameOfAnchor && pPageFrameOfAnchor == &mrPageFrame )
405 {
406 // if format of object fails, stop formatting and pass fail to
407 // calling method via the return value.
408 if ( !DoFormatObj( *pAnchoredObj ) )
409 {
410 bSuccess = false;
411 break;
412 }
413
414 // considering changes at <pAnchorFrame->GetDrawObjs()> during
415 // format of the object.
416 if ( !pAnchorFrame->GetDrawObjs() ||
417 i > pAnchorFrame->GetDrawObjs()->size() )
418 {
419 break;
420 }
421 else
422 {
423 const size_t nActPosOfObj =
424 pAnchorFrame->GetDrawObjs()->ListPosOf( *pAnchoredObj );
425 if ( nActPosOfObj == pAnchorFrame->GetDrawObjs()->size() ||
426 nActPosOfObj > i )
427 {
428 --i;
429 }
430 else if ( nActPosOfObj < i )
431 {
432 i = nActPosOfObj;
433 }
434 }
435 }
436 } // end of loop on <pAnchorFrame->.GetDrawObjs()>
437
438 return bSuccess;
439 }
440
441 /** accessor to collected anchored object
442
443 #i28701#
444 */
GetCollectedObj(const sal_uInt32 _nIndex)445 SwAnchoredObject* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex )
446 {
447 return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : nullptr;
448 }
449
450 /** accessor to 'anchor' page number of collected anchored object
451
452 #i28701#
453 */
GetPgNumOfCollected(const sal_uInt32 _nIndex)454 sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex )
455 {
456 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0;
457 }
458
459 /** accessor to 'anchor' type of collected anchored object
460
461 #i26945#
462 */
IsCollectedAnchoredAtMaster(const sal_uInt32 _nIndex)463 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex )
464 {
465 return mpPgNumAndTypeOfAnchors == nullptr
466 || mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex);
467 }
468
469 /** accessor to total number of collected anchored objects
470
471 #i28701#
472 */
CountOfCollected()473 sal_uInt32 SwObjectFormatter::CountOfCollected()
474 {
475 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0;
476 }
477
478 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
479