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