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 8430 : inline SwPageNumAndTypeOfAnchors()
50 8430 : {
51 8430 : }
52 8430 : inline ~SwPageNumAndTypeOfAnchors()
53 8430 : {
54 66753 : for ( std::vector< tEntry* >::iterator aIter = maObjList.begin();
55 44502 : aIter != maObjList.end(); ++aIter )
56 : {
57 13821 : delete (*aIter);
58 : }
59 8430 : maObjList.clear();
60 8430 : }
61 :
62 13821 : inline void Collect( SwAnchoredObject& _rAnchoredObj )
63 : {
64 13821 : tEntry* pNewEntry = new tEntry();
65 13821 : pNewEntry->mpAnchoredObj = &_rAnchoredObj;
66 : // #i33751#, #i34060# - method <GetPageFrmOfAnchor()>
67 : // is replaced by method <FindPageFrmOfAnchor()>. It's return value
68 : // have to be checked.
69 13821 : SwPageFrm* pPageFrmOfAnchor = _rAnchoredObj.FindPageFrmOfAnchor();
70 13821 : if ( pPageFrmOfAnchor )
71 : {
72 13821 : pNewEntry->mnPageNumOfAnchor = pPageFrmOfAnchor->GetPhyPageNum();
73 : }
74 : else
75 : {
76 0 : pNewEntry->mnPageNumOfAnchor = 0;
77 : }
78 : // --> #i26945# - collect type of anchor
79 13821 : SwTextFrm* pAnchorCharFrm = _rAnchoredObj.FindAnchorCharFrm();
80 13821 : if ( pAnchorCharFrm )
81 : {
82 5819 : pNewEntry->mbAnchoredAtMaster = !pAnchorCharFrm->IsFollow();
83 : }
84 : else
85 : {
86 8002 : pNewEntry->mbAnchoredAtMaster = true;
87 : }
88 13821 : maObjList.push_back( pNewEntry );
89 13821 : }
90 :
91 12264 : inline SwAnchoredObject* operator[]( sal_uInt32 _nIndex )
92 : {
93 12264 : SwAnchoredObject* bRetObj = 0L;
94 :
95 12264 : if ( _nIndex < Count())
96 : {
97 12264 : bRetObj = maObjList[_nIndex]->mpAnchoredObj;
98 : }
99 :
100 12264 : return bRetObj;
101 : }
102 :
103 1361 : inline sal_uInt32 GetPageNum( sal_uInt32 _nIndex ) const
104 : {
105 1361 : sal_uInt32 nRetPgNum = 0L;
106 :
107 1361 : if ( _nIndex < Count())
108 : {
109 1361 : nRetPgNum = maObjList[_nIndex]->mnPageNumOfAnchor;
110 : }
111 :
112 1361 : return nRetPgNum;
113 : }
114 :
115 : // --> #i26945#
116 1361 : inline bool AnchoredAtMaster( sal_uInt32 _nIndex )
117 : {
118 1361 : bool bAnchoredAtMaster( true );
119 :
120 1361 : if ( _nIndex < Count())
121 : {
122 1361 : bAnchoredAtMaster = maObjList[_nIndex]->mbAnchoredAtMaster;
123 : }
124 :
125 1361 : return bAnchoredAtMaster;
126 : }
127 :
128 31974 : inline sal_uInt32 Count() const
129 : {
130 31974 : return maObjList.size();
131 : }
132 : };
133 :
134 9965 : SwObjectFormatter::SwObjectFormatter( const SwPageFrm& _rPageFrm,
135 : SwLayAction* _pLayAction,
136 : const bool _bCollectPgNumOfAnchors )
137 : : mrPageFrm( _rPageFrm ),
138 : mbFormatOnlyAsCharAnchored( false ),
139 9965 : mbConsiderWrapOnObjPos( _rPageFrm.GetFormat()->getIDocumentSettingAccess()->get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ),
140 : mpLayAction( _pLayAction ),
141 : // --> #i26945#
142 19930 : mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors ? new SwPageNumAndTypeOfAnchors() : 0L )
143 : {
144 9965 : }
145 :
146 9965 : SwObjectFormatter::~SwObjectFormatter()
147 : {
148 9965 : delete mpPgNumAndTypeOfAnchors;
149 9965 : }
150 :
151 147943 : SwObjectFormatter* SwObjectFormatter::CreateObjFormatter(
152 : SwFrm& _rAnchorFrm,
153 : const SwPageFrm& _rPageFrm,
154 : SwLayAction* _pLayAction )
155 : {
156 147943 : SwObjectFormatter* pObjFormatter = 0L;
157 147943 : if ( _rAnchorFrm.IsTextFrm() )
158 : {
159 : pObjFormatter = SwObjectFormatterTextFrm::CreateObjFormatter(
160 : static_cast<SwTextFrm&>(_rAnchorFrm),
161 131655 : _rPageFrm, _pLayAction );
162 : }
163 16288 : else if ( _rAnchorFrm.IsLayoutFrm() )
164 : {
165 : pObjFormatter = SwObjectFormatterLayFrm::CreateObjFormatter(
166 : static_cast<SwLayoutFrm&>(_rAnchorFrm),
167 16288 : _rPageFrm, _pLayAction );
168 : }
169 : else
170 : {
171 : OSL_FAIL( "<SwObjectFormatter::CreateObjFormatter(..)> - unexpected type of anchor frame" );
172 : }
173 :
174 147943 : return pObjFormatter;
175 : }
176 :
177 : /** method to format all floating screen objects at the given anchor frame
178 : */
179 147191 : bool SwObjectFormatter::FormatObjsAtFrm( SwFrm& _rAnchorFrm,
180 : const SwPageFrm& _rPageFrm,
181 : SwLayAction* _pLayAction )
182 : {
183 147191 : bool bSuccess( true );
184 :
185 : // create corresponding object formatter
186 : SwObjectFormatter* pObjFormatter =
187 147191 : SwObjectFormatter::CreateObjFormatter( _rAnchorFrm, _rPageFrm, _pLayAction );
188 :
189 147191 : if ( pObjFormatter )
190 : {
191 : // format anchored floating screen objects
192 9213 : bSuccess = pObjFormatter->DoFormatObjs();
193 : }
194 147191 : delete pObjFormatter;
195 :
196 147191 : return bSuccess;
197 : }
198 :
199 : /** method to format a given floating screen object
200 : */
201 752 : bool SwObjectFormatter::FormatObj( SwAnchoredObject& _rAnchoredObj,
202 : SwFrm* _pAnchorFrm,
203 : const SwPageFrm* _pPageFrm,
204 : SwLayAction* _pLayAction )
205 : {
206 752 : bool bSuccess( true );
207 :
208 : OSL_ENSURE( _pAnchorFrm || _rAnchoredObj.GetAnchorFrm(),
209 : "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
210 752 : SwFrm& rAnchorFrm = _pAnchorFrm ? *(_pAnchorFrm) : *(_rAnchoredObj.AnchorFrm());
211 :
212 : OSL_ENSURE( _pPageFrm || rAnchorFrm.FindPageFrm(),
213 : "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
214 752 : const SwPageFrm& rPageFrm = _pPageFrm ? *(_pPageFrm) : *(rAnchorFrm.FindPageFrm());
215 :
216 : // create corresponding object formatter
217 : SwObjectFormatter* pObjFormatter =
218 752 : SwObjectFormatter::CreateObjFormatter( rAnchorFrm, rPageFrm, _pLayAction );
219 :
220 752 : if ( pObjFormatter )
221 : {
222 : // format given floating screen object
223 : // --> #i40147# - check for moved forward anchor frame
224 752 : bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
225 : }
226 752 : delete pObjFormatter;
227 :
228 752 : 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 2261 : void SwObjectFormatter::_FormatLayout( SwLayoutFrm& _rLayoutFrm )
241 : {
242 2261 : _rLayoutFrm.Calc();
243 :
244 2261 : SwFrm* pLowerFrm = _rLayoutFrm.Lower();
245 7063 : while ( pLowerFrm )
246 : {
247 2541 : if ( pLowerFrm->IsLayoutFrm() )
248 : {
249 192 : _FormatLayout( *(static_cast<SwLayoutFrm*>(pLowerFrm)) );
250 : }
251 2541 : pLowerFrm = pLowerFrm->GetNext();
252 : }
253 2261 : }
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 2069 : void SwObjectFormatter::_FormatObjContent( SwAnchoredObject& _rAnchoredObj )
261 : {
262 2069 : if ( !_rAnchoredObj.ISA(SwFlyFrm) )
263 : {
264 : // only Writer fly frames have content
265 2069 : return;
266 : }
267 :
268 2069 : SwFlyFrm& rFlyFrm = static_cast<SwFlyFrm&>(_rAnchoredObj);
269 2069 : SwContentFrm* pContent = rFlyFrm.ContainsContent();
270 :
271 6487 : while ( pContent )
272 : {
273 : // format content
274 2349 : pContent->OptCalc();
275 :
276 : // format floating screen objects at content text frame
277 : // #i23129#, #i36347# - pass correct page frame to
278 : // the object formatter
279 3510 : if ( pContent->IsTextFrm() &&
280 : !SwObjectFormatter::FormatObjsAtFrm( *pContent,
281 1161 : *(pContent->FindPageFrm()),
282 2322 : GetLayAction() ) )
283 : {
284 : // restart format with first content
285 0 : pContent = rFlyFrm.ContainsContent();
286 0 : continue;
287 : }
288 :
289 : // continue with next content
290 2349 : pContent = pContent->GetNextContentFrm();
291 : }
292 : }
293 :
294 : /** performs the intrinsic format of a given floating screen object and its content.
295 :
296 : #i28701#
297 : */
298 14423 : 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 14423 : if ( FormatOnlyAsCharAnchored() &&
303 0 : !(_rAnchoredObj.GetFrameFormat().GetAnchor().GetAnchorId() == FLY_AS_CHAR) )
304 : {
305 14423 : return;
306 : }
307 :
308 : // collect anchor object and its 'anchor' page number, if requested
309 14423 : if ( mpPgNumAndTypeOfAnchors )
310 : {
311 13821 : mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj );
312 : }
313 :
314 14423 : if ( _rAnchoredObj.ISA(SwFlyFrm) )
315 : {
316 7686 : SwFlyFrm& rFlyFrm = static_cast<SwFlyFrm&>(_rAnchoredObj);
317 : // --> #i34753# - reset flag, which prevents a positioning
318 7686 : if ( rFlyFrm.IsFlyLayFrm() )
319 : {
320 75 : static_cast<SwFlyLayFrm&>(rFlyFrm).SetNoMakePos( false );
321 : }
322 :
323 : // #i81146# new loop control
324 7686 : int nLoopControlRuns = 0;
325 7686 : const int nLoopControlMax = 15;
326 :
327 7815 : do {
328 7815 : if ( mpLayAction )
329 : {
330 5746 : mpLayAction->FormatLayoutFly( &rFlyFrm );
331 : // --> consider, if the layout action
332 : // has to be restarted due to a delete of a page frame.
333 5746 : if ( mpLayAction->IsAgain() )
334 : {
335 0 : break;
336 : }
337 : }
338 : else
339 : {
340 2069 : _FormatLayout( rFlyFrm );
341 : }
342 : // --> #i34753# - prevent further positioning, if
343 : // to-page|to-fly anchored Writer fly frame is already clipped.
344 7815 : if ( rFlyFrm.IsFlyLayFrm() && rFlyFrm.IsClipped() )
345 : {
346 0 : static_cast<SwFlyLayFrm&>(rFlyFrm).SetNoMakePos( true );
347 : }
348 : // #i23129#, #i36347# - pass correct page frame
349 : // to the object formatter
350 : SwObjectFormatter::FormatObjsAtFrm( rFlyFrm,
351 7815 : *(rFlyFrm.FindPageFrm()),
352 15630 : mpLayAction );
353 7815 : if ( mpLayAction )
354 : {
355 5746 : mpLayAction->_FormatFlyContent( &rFlyFrm );
356 : // --> consider, if the layout action
357 : // has to be restarted due to a delete of a page frame.
358 5746 : if ( mpLayAction->IsAgain() )
359 : {
360 0 : break;
361 : }
362 : }
363 : else
364 : {
365 2069 : _FormatObjContent( rFlyFrm );
366 : }
367 :
368 7815 : 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 8156 : } while ( !rFlyFrm.IsValid() &&
378 7944 : !_rAnchoredObj.RestartLayoutProcess() &&
379 129 : rFlyFrm.GetAnchorFrm() == &GetAnchorFrm() );
380 : }
381 6737 : else if ( _rAnchoredObj.ISA(SwAnchoredDrawObject) )
382 : {
383 6737 : _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 9231 : bool SwObjectFormatter::_FormatObjsAtFrm( SwTextFrm* _pMasterTextFrm )
397 : {
398 : // --> #i26945#
399 9231 : SwFrm* pAnchorFrm( 0L );
400 26158 : if ( GetAnchorFrm().IsTextFrm() &&
401 9267 : static_cast<SwTextFrm&>(GetAnchorFrm()).IsFollow() &&
402 : _pMasterTextFrm )
403 : {
404 18 : pAnchorFrm = _pMasterTextFrm;
405 : }
406 : else
407 : {
408 9213 : pAnchorFrm = &GetAnchorFrm();
409 : }
410 9231 : if ( !pAnchorFrm->GetDrawObjs() )
411 : {
412 : // nothing to do, if no floating screen object is registered at the anchor frame.
413 1364 : return true;
414 : }
415 :
416 7867 : bool bSuccess( true );
417 :
418 21071 : for ( size_t i = 0; i < pAnchorFrm->GetDrawObjs()->size(); ++i )
419 : {
420 13691 : 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 13691 : SwTextFrm* pAnchorCharFrm = pAnchoredObj->FindAnchorCharFrm();
432 : const bool bAnchoredAtFollowInSameBodyAsMaster =
433 5113 : pAnchorCharFrm && pAnchorCharFrm->IsFollow() &&
434 13728 : pAnchorCharFrm != pAnchoredObj->GetAnchorFrm() &&
435 12 : pAnchorCharFrm->FindBodyFrm() ==
436 13703 : static_cast<SwTextFrm*>(pAnchoredObj->AnchorFrm())->FindBodyFrm();
437 13691 : 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 13691 : SwPageFrm* pPageFrmOfAnchor = pAnchoredObj->FindPageFrmOfAnchor();
445 : OSL_ENSURE( pPageFrmOfAnchor,
446 : "<SwObjectFormatter::_FormatObjsAtFrm()> - missing page frame." );
447 : // --> #i26945#
448 13691 : 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 13671 : if ( !DoFormatObj( *pAnchoredObj ) )
453 : {
454 487 : bSuccess = false;
455 487 : break;
456 : }
457 :
458 : // considering changes at <pAnchorFrm->GetDrawObjs()> during
459 : // format of the object.
460 26368 : if ( !pAnchorFrm->GetDrawObjs() ||
461 13184 : i > pAnchorFrm->GetDrawObjs()->size() )
462 : {
463 0 : break;
464 : }
465 : else
466 : {
467 : const size_t nActPosOfObj =
468 13184 : pAnchorFrm->GetDrawObjs()->ListPosOf( *pAnchoredObj );
469 13184 : if ( nActPosOfObj == pAnchorFrm->GetDrawObjs()->size() ||
470 : nActPosOfObj > i )
471 : {
472 0 : --i;
473 : }
474 13184 : else if ( nActPosOfObj < i )
475 : {
476 0 : i = nActPosOfObj;
477 : }
478 : }
479 : }
480 : } // end of loop on <pAnchorFrm->.GetDrawObjs()>
481 :
482 7867 : return bSuccess;
483 : }
484 :
485 : /** accessor to collected anchored object
486 :
487 : #i28701#
488 : */
489 12264 : SwAnchoredObject* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex )
490 : {
491 12264 : return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : 0L;
492 : }
493 :
494 : /** accessor to 'anchor' page number of collected anchored object
495 :
496 : #i28701#
497 : */
498 1361 : sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex )
499 : {
500 1361 : return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0L;
501 : }
502 :
503 : /** accessor to 'anchor' type of collected anchored object
504 :
505 : #i26945#
506 : */
507 1361 : bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex )
508 : {
509 1361 : return mpPgNumAndTypeOfAnchors == nullptr
510 1361 : || mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex);
511 : }
512 :
513 : /** accessor to total number of collected anchored objects
514 :
515 : #i28701#
516 : */
517 16988 : sal_uInt32 SwObjectFormatter::CountOfCollected()
518 : {
519 16988 : return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0L;
520 177 : }
521 :
522 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|