1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include <objectformatter.hxx>
27 #include <objectformattertxtfrm.hxx>
28 #include <objectformatterlayfrm.hxx>
29 #include <anchoredobject.hxx>
30 #include <anchoreddrawobject.hxx>
31 #include <sortedobjs.hxx>
32 #include <pagefrm.hxx>
33 #include <flyfrms.hxx>
34 #include <txtfrm.hxx>
35 #include <layact.hxx>
36 #include <frmfmt.hxx>
37 #include <fmtanchr.hxx>
38 #include <doc.hxx>
39
40 #include <vector>
41
42 // =============================================================================
43 // helper class <SwPageNumAndTypeOfAnchors>
44 // --> OD 2004-10-04 #i26945# - Additionally the type of the anchor text frame
45 // is collected - by type is meant 'master' or 'follow'.
46 // =============================================================================
47 class SwPageNumAndTypeOfAnchors
48 {
49 private:
50 struct tEntry
51 {
52 SwAnchoredObject* mpAnchoredObj;
53 sal_uInt32 mnPageNumOfAnchor;
54 bool mbAnchoredAtMaster;
55 };
56
57 std::vector< tEntry* > maObjList;
58
59 public:
SwPageNumAndTypeOfAnchors()60 inline SwPageNumAndTypeOfAnchors()
61 {
62 }
~SwPageNumAndTypeOfAnchors()63 inline ~SwPageNumAndTypeOfAnchors()
64 {
65 for ( std::vector< tEntry* >::iterator aIter = maObjList.begin();
66 aIter != maObjList.end(); ++aIter )
67 {
68 delete (*aIter);
69 }
70 maObjList.clear();
71 }
72
Collect(SwAnchoredObject & _rAnchoredObj)73 inline void Collect( SwAnchoredObject& _rAnchoredObj )
74 {
75 tEntry* pNewEntry = new tEntry();
76 pNewEntry->mpAnchoredObj = &_rAnchoredObj;
77 // --> OD 2004-09-23 #i33751#, #i34060# - method <GetPageFrmOfAnchor()>
78 // is replaced by method <FindPageFrmOfAnchor()>. It's return value
79 // have to be checked.
80 SwPageFrm* pPageFrmOfAnchor = _rAnchoredObj.FindPageFrmOfAnchor();
81 if ( pPageFrmOfAnchor )
82 {
83 pNewEntry->mnPageNumOfAnchor = pPageFrmOfAnchor->GetPhyPageNum();
84 }
85 else
86 {
87 pNewEntry->mnPageNumOfAnchor = 0;
88 }
89 // <--
90 // --> OD 2004-10-04 #i26945# - collect type of anchor
91 SwTxtFrm* pAnchorCharFrm = _rAnchoredObj.FindAnchorCharFrm();
92 if ( pAnchorCharFrm )
93 {
94 pNewEntry->mbAnchoredAtMaster = !pAnchorCharFrm->IsFollow();
95 }
96 else
97 {
98 pNewEntry->mbAnchoredAtMaster = true;
99 }
100 // <--
101 maObjList.push_back( pNewEntry );
102 }
103
operator [](sal_uInt32 _nIndex)104 inline SwAnchoredObject* operator[]( sal_uInt32 _nIndex )
105 {
106 SwAnchoredObject* bRetObj = 0L;
107
108 if ( _nIndex < Count())
109 {
110 bRetObj = maObjList[_nIndex]->mpAnchoredObj;
111 }
112
113 return bRetObj;
114 }
115
GetPageNum(sal_uInt32 _nIndex)116 inline sal_uInt32 GetPageNum( sal_uInt32 _nIndex )
117 {
118 sal_uInt32 nRetPgNum = 0L;
119
120 if ( _nIndex < Count())
121 {
122 nRetPgNum = maObjList[_nIndex]->mnPageNumOfAnchor;
123 }
124
125 return nRetPgNum;
126 }
127
128 // --> OD 2004-10-04 #i26945#
AnchoredAtMaster(sal_uInt32 _nIndex)129 inline bool AnchoredAtMaster( sal_uInt32 _nIndex )
130 {
131 bool bAnchoredAtMaster( true );
132
133 if ( _nIndex < Count())
134 {
135 bAnchoredAtMaster = maObjList[_nIndex]->mbAnchoredAtMaster;
136 }
137
138 return bAnchoredAtMaster;
139 }
140 // <--
141
Count() const142 inline sal_uInt32 Count() const
143 {
144 return maObjList.size();
145 }
146 };
147
148 // =============================================================================
149 // implementation of class <SwObjectFormatter>
150 // =============================================================================
SwObjectFormatter(const SwPageFrm & _rPageFrm,SwLayAction * _pLayAction,const bool _bCollectPgNumOfAnchors)151 SwObjectFormatter::SwObjectFormatter( const SwPageFrm& _rPageFrm,
152 SwLayAction* _pLayAction,
153 const bool _bCollectPgNumOfAnchors )
154 : mrPageFrm( _rPageFrm ),
155 mbFormatOnlyAsCharAnchored( false ),
156 mbConsiderWrapOnObjPos( _rPageFrm.GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ),
157 mpLayAction( _pLayAction ),
158 // --> OD 2004-10-04 #i26945#
159 mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors ? new SwPageNumAndTypeOfAnchors() : 0L )
160 // <--
161 {
162 }
163
~SwObjectFormatter()164 SwObjectFormatter::~SwObjectFormatter()
165 {
166 delete mpPgNumAndTypeOfAnchors;
167 }
168
CreateObjFormatter(SwFrm & _rAnchorFrm,const SwPageFrm & _rPageFrm,SwLayAction * _pLayAction)169 SwObjectFormatter* SwObjectFormatter::CreateObjFormatter(
170 SwFrm& _rAnchorFrm,
171 const SwPageFrm& _rPageFrm,
172 SwLayAction* _pLayAction )
173 {
174 SwObjectFormatter* pObjFormatter = 0L;
175 if ( _rAnchorFrm.IsTxtFrm() )
176 {
177 pObjFormatter = SwObjectFormatterTxtFrm::CreateObjFormatter(
178 static_cast<SwTxtFrm&>(_rAnchorFrm),
179 _rPageFrm, _pLayAction );
180 }
181 else if ( _rAnchorFrm.IsLayoutFrm() )
182 {
183 pObjFormatter = SwObjectFormatterLayFrm::CreateObjFormatter(
184 static_cast<SwLayoutFrm&>(_rAnchorFrm),
185 _rPageFrm, _pLayAction );
186 }
187 else
188 {
189 ASSERT( false,
190 "<SwObjectFormatter::CreateObjFormatter(..)> - unexcepted type of anchor frame" );
191 }
192
193 return pObjFormatter;
194 }
195
196 /** method to format all floating screen objects at the given anchor frame
197
198 @author OD
199 */
FormatObjsAtFrm(SwFrm & _rAnchorFrm,const SwPageFrm & _rPageFrm,SwLayAction * _pLayAction)200 bool SwObjectFormatter::FormatObjsAtFrm( SwFrm& _rAnchorFrm,
201 const SwPageFrm& _rPageFrm,
202 SwLayAction* _pLayAction )
203 {
204 bool bSuccess( true );
205
206 // create corresponding object formatter
207 SwObjectFormatter* pObjFormatter =
208 SwObjectFormatter::CreateObjFormatter( _rAnchorFrm, _rPageFrm, _pLayAction );
209
210 if ( pObjFormatter )
211 {
212 // format anchored floating screen objects
213 bSuccess = pObjFormatter->DoFormatObjs();
214 }
215 delete pObjFormatter;
216
217 return bSuccess;
218 }
219
220 /** method to format a given floating screen object
221
222 @author OD
223 */
FormatObj(SwAnchoredObject & _rAnchoredObj,SwFrm * _pAnchorFrm,const SwPageFrm * _pPageFrm,SwLayAction * _pLayAction)224 bool SwObjectFormatter::FormatObj( SwAnchoredObject& _rAnchoredObj,
225 SwFrm* _pAnchorFrm,
226 const SwPageFrm* _pPageFrm,
227 SwLayAction* _pLayAction )
228 {
229 bool bSuccess( true );
230
231 ASSERT( _pAnchorFrm || _rAnchoredObj.GetAnchorFrm(),
232 "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
233 SwFrm& rAnchorFrm = _pAnchorFrm ? *(_pAnchorFrm) : *(_rAnchoredObj.AnchorFrm());
234
235 ASSERT( _pPageFrm || rAnchorFrm.FindPageFrm(),
236 "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
237 const SwPageFrm& rPageFrm = _pPageFrm ? *(_pPageFrm) : *(rAnchorFrm.FindPageFrm());
238
239 // create corresponding object formatter
240 SwObjectFormatter* pObjFormatter =
241 SwObjectFormatter::CreateObjFormatter( rAnchorFrm, rPageFrm, _pLayAction );
242
243 if ( pObjFormatter )
244 {
245 // format given floating screen object
246 // --> OD 2005-01-10 #i40147# - check for moved forward anchor frame
247 bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
248 // <--
249 }
250 delete pObjFormatter;
251
252 return bSuccess;
253 }
254
255 /** helper method for method <_FormatObj(..)> - performs the intrinsic format
256 of the layout of the given layout frame and all its lower layout frames.
257
258 OD 2004-06-28 #i28701#
259 IMPORTANT NOTE:
260 Method corresponds to methods <SwLayAction::FormatLayoutFly(..)> and
261 <SwLayAction::FormatLayout(..)>. Thus, its code for the formatting have
262 to be synchronised.
263
264 @author OD
265 */
_FormatLayout(SwLayoutFrm & _rLayoutFrm)266 void SwObjectFormatter::_FormatLayout( SwLayoutFrm& _rLayoutFrm )
267 {
268 _rLayoutFrm.Calc();
269
270 SwFrm* pLowerFrm = _rLayoutFrm.Lower();
271 while ( pLowerFrm )
272 {
273 if ( pLowerFrm->IsLayoutFrm() )
274 {
275 _FormatLayout( *(static_cast<SwLayoutFrm*>(pLowerFrm)) );
276 }
277 pLowerFrm = pLowerFrm->GetNext();
278 }
279 }
280
281 /** helper method for method <_FormatObj(..)> - performs the intrinsic
282 format of the content of the given floating screen object.
283
284 OD 2004-06-28 #i28701#
285
286 @author OD
287 */
_FormatObjCntnt(SwAnchoredObject & _rAnchoredObj)288 void SwObjectFormatter::_FormatObjCntnt( SwAnchoredObject& _rAnchoredObj )
289 {
290 if ( !_rAnchoredObj.ISA(SwFlyFrm) )
291 {
292 // only Writer fly frames have content
293 return;
294 }
295
296 SwFlyFrm& rFlyFrm = static_cast<SwFlyFrm&>(_rAnchoredObj);
297 SwCntntFrm* pCntnt = rFlyFrm.ContainsCntnt();
298
299 while ( pCntnt )
300 {
301 // format content
302 pCntnt->OptCalc();
303
304 // format floating screen objects at content text frame
305 // --> OD 2004-11-01 #i23129#, #i36347# - pass correct page frame to
306 // the object formatter
307 if ( pCntnt->IsTxtFrm() &&
308 !SwObjectFormatter::FormatObjsAtFrm( *pCntnt,
309 *(pCntnt->FindPageFrm()),
310 GetLayAction() ) )
311 // <--
312 {
313 // restart format with first content
314 pCntnt = rFlyFrm.ContainsCntnt();
315 continue;
316 }
317
318 // continue with next content
319 pCntnt = pCntnt->GetNextCntntFrm();
320 }
321 }
322
323 /** performs the intrinsic format of a given floating screen object and its content.
324
325 OD 2004-06-28 #i28701#
326
327 @author OD
328 */
_FormatObj(SwAnchoredObject & _rAnchoredObj)329 void SwObjectFormatter::_FormatObj( SwAnchoredObject& _rAnchoredObj )
330 {
331 // check, if only as-character anchored object have to be formatted, and
332 // check the anchor type
333 if ( FormatOnlyAsCharAnchored() &&
334 !(_rAnchoredObj.GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR) )
335 {
336 return;
337 }
338
339 // collect anchor object and its 'anchor' page number, if requested
340 if ( mpPgNumAndTypeOfAnchors )
341 {
342 mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj );
343 }
344
345 if ( _rAnchoredObj.ISA(SwFlyFrm) )
346 {
347 SwFlyFrm& rFlyFrm = static_cast<SwFlyFrm&>(_rAnchoredObj);
348 // --> OD 2004-11-15 #i34753# - reset flag, which prevents a positioning
349 if ( rFlyFrm.IsFlyLayFrm() )
350 {
351 static_cast<SwFlyLayFrm&>(rFlyFrm).SetNoMakePos( false );
352 }
353 // <--
354
355 // FME 2007-08-30 #i81146# new loop control
356 sal_uInt16 nLoopControlRuns = 0;
357 const sal_uInt16 nLoopControlMax = 15;
358
359 do {
360 if ( mpLayAction )
361 {
362 mpLayAction->FormatLayoutFly( &rFlyFrm );
363 // --> OD 2005-07-13 #124218# - consider, if the layout action
364 // has to be restarted due to a delete of a page frame.
365 if ( mpLayAction->IsAgain() )
366 {
367 break;
368 }
369 // <--
370 }
371 else
372 {
373 _FormatLayout( rFlyFrm );
374 }
375 // --> OD 2004-11-15 #i34753# - prevent further positioning, if
376 // to-page|to-fly anchored Writer fly frame is already clipped.
377 if ( rFlyFrm.IsFlyLayFrm() && rFlyFrm.IsClipped() )
378 {
379 static_cast<SwFlyLayFrm&>(rFlyFrm).SetNoMakePos( true );
380 }
381 // <--
382 // --> OD 2004-11-02 #i23129#, #i36347# - pass correct page frame
383 // to the object formatter
384 SwObjectFormatter::FormatObjsAtFrm( rFlyFrm,
385 *(rFlyFrm.FindPageFrm()),
386 mpLayAction );
387 // <--
388 if ( mpLayAction )
389 {
390 mpLayAction->_FormatFlyCntnt( &rFlyFrm );
391 // --> OD 2005-07-13 #124218# - consider, if the layout action
392 // has to be restarted due to a delete of a page frame.
393 if ( mpLayAction->IsAgain() )
394 {
395 break;
396 }
397 // <--
398 }
399 else
400 {
401 _FormatObjCntnt( rFlyFrm );
402 }
403
404 if ( ++nLoopControlRuns >= nLoopControlMax )
405 {
406 #if OSL_DEBUG_LEVEL > 1
407 ASSERT( false, "LoopControl in SwObjectFormatter::_FormatObj: Stage 3!!!" );
408 #endif
409 rFlyFrm.ValidateThisAndAllLowers( 2 );
410 nLoopControlRuns = 0;
411 }
412
413 // --> OD 2006-02-02 #i57917#
414 // stop formatting of anchored object, if restart of layout process is requested.
415 } while ( !rFlyFrm.IsValid() &&
416 !_rAnchoredObj.RestartLayoutProcess() &&
417 rFlyFrm.GetAnchorFrm() == &GetAnchorFrm() );
418 // <--
419 }
420 else if ( _rAnchoredObj.ISA(SwAnchoredDrawObject) )
421 {
422 _rAnchoredObj.MakeObjPos();
423 }
424 }
425
426 /** invokes the intrinsic format method for all floating screen objects,
427 anchored at anchor frame on the given page frame
428
429 OD 2004-06-28 #i28701#
430 OD 2004-10-08 #i26945# - for format of floating screen objects for
431 follow text frames, the 'master' text frame is passed to the method.
432 Thus, the objects, whose anchor character is inside the follow text
433 frame can be formatted.
434
435 @author OD
436 */
_FormatObjsAtFrm(SwTxtFrm * _pMasterTxtFrm)437 bool SwObjectFormatter::_FormatObjsAtFrm( SwTxtFrm* _pMasterTxtFrm )
438 {
439 // --> OD 2004-10-08 #i26945#
440 SwFrm* pAnchorFrm( 0L );
441 if ( GetAnchorFrm().IsTxtFrm() &&
442 static_cast<SwTxtFrm&>(GetAnchorFrm()).IsFollow() &&
443 _pMasterTxtFrm )
444 {
445 pAnchorFrm = _pMasterTxtFrm;
446 }
447 else
448 {
449 pAnchorFrm = &GetAnchorFrm();
450 }
451 // <--
452 if ( !pAnchorFrm->GetDrawObjs() )
453 {
454 // nothing to do, if no floating screen object is registered at the anchor frame.
455 return true;
456 }
457
458 bool bSuccess( true );
459
460 sal_uInt32 i = 0;
461 for ( ; i < pAnchorFrm->GetDrawObjs()->Count(); ++i )
462 {
463 SwAnchoredObject* pAnchoredObj = (*pAnchorFrm->GetDrawObjs())[i];
464
465 // check, if object's anchor is on the given page frame or
466 // object is registered at the given page frame.
467 // --> OD 2004-10-05 #i26945# - check, if the anchor character of the
468 // anchored object is located in a follow text frame. If this anchor
469 // follow text frame differs from the given anchor frame, the given
470 // anchor frame is a 'master' text frame of the anchor follow text frame.
471 // If the anchor follow text frame is in the same body as its 'master'
472 // text frame, do not format the anchored object.
473 // E.g., this situation can occur during the table row splitting algorithm.
474 SwTxtFrm* pAnchorCharFrm = pAnchoredObj->FindAnchorCharFrm();
475 const bool bAnchoredAtFollowInSameBodyAsMaster =
476 pAnchorCharFrm && pAnchorCharFrm->IsFollow() &&
477 pAnchorCharFrm != pAnchoredObj->GetAnchorFrm() &&
478 pAnchorCharFrm->FindBodyFrm() ==
479 static_cast<SwTxtFrm*>(pAnchoredObj->AnchorFrm())->FindBodyFrm();
480 if ( bAnchoredAtFollowInSameBodyAsMaster )
481 {
482 continue;
483 }
484 // <--
485 // --> OD 2004-09-23 #i33751#, #i34060# - method <GetPageFrmOfAnchor()>
486 // is replaced by method <FindPageFrmOfAnchor()>. It's return value
487 // have to be checked.
488 SwPageFrm* pPageFrmOfAnchor = pAnchoredObj->FindPageFrmOfAnchor();
489 ASSERT( pPageFrmOfAnchor,
490 "<SwObjectFormatter::_FormatObjsAtFrm()> - missing page frame." );
491 // --> OD 2004-10-08 #i26945#
492 if ( pPageFrmOfAnchor && pPageFrmOfAnchor == &mrPageFrm )
493 // <--
494 {
495 // if format of object fails, stop formatting and pass fail to
496 // calling method via the return value.
497 if ( !DoFormatObj( *pAnchoredObj ) )
498 {
499 bSuccess = false;
500 break;
501 }
502
503 // considering changes at <pAnchorFrm->GetDrawObjs()> during
504 // format of the object.
505 if ( !pAnchorFrm->GetDrawObjs() ||
506 i > pAnchorFrm->GetDrawObjs()->Count() )
507 {
508 break;
509 }
510 else
511 {
512 sal_uInt32 nActPosOfObj =
513 pAnchorFrm->GetDrawObjs()->ListPosOf( *pAnchoredObj );
514 if ( nActPosOfObj == pAnchorFrm->GetDrawObjs()->Count() ||
515 nActPosOfObj > i )
516 {
517 --i;
518 }
519 else if ( nActPosOfObj < i )
520 {
521 i = nActPosOfObj;
522 }
523 }
524 }
525 } // end of loop on <pAnchorFrm->.GetDrawObjs()>
526
527 return bSuccess;
528 }
529
530 /** accessor to collected anchored object
531
532 OD 2004-07-05 #i28701#
533
534 @author OD
535 */
GetCollectedObj(const sal_uInt32 _nIndex)536 SwAnchoredObject* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex )
537 {
538 return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : 0L;
539 }
540
541 /** accessor to 'anchor' page number of collected anchored object
542
543 OD 2004-07-05 #i28701#
544
545 @author OD
546 */
GetPgNumOfCollected(const sal_uInt32 _nIndex)547 sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex )
548 {
549 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0L;
550 }
551
552 /** accessor to 'anchor' type of collected anchored object
553
554 OD 2004-10-04 #i26945#
555
556 @author OD
557 */
IsCollectedAnchoredAtMaster(const sal_uInt32 _nIndex)558 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex )
559 {
560 return mpPgNumAndTypeOfAnchors
561 ? mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex)
562 : true;
563 }
564
565 /** accessor to total number of collected anchored objects
566
567 OD 2004-07-05 #i28701#
568
569 @author OD
570 */
CountOfCollected()571 sal_uInt32 SwObjectFormatter::CountOfCollected()
572 {
573 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0L;
574 }
575