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