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