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