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 "layouter.hxx"
21 : #include "doc.hxx"
22 : #include "sectfrm.hxx"
23 : #include "pagefrm.hxx"
24 : #include "ftnfrm.hxx"
25 : #include "txtfrm.hxx"
26 : #include <IDocumentLayoutAccess.hxx>
27 :
28 : #include <movedfwdfrmsbyobjpos.hxx>
29 : #include <objstmpconsiderwrapinfl.hxx>
30 :
31 : #define LOOP_DETECT 250
32 :
33 : class SwLooping
34 : {
35 : sal_uInt16 nMinPage;
36 : sal_uInt16 nMaxPage;
37 : sal_uInt16 nCount;
38 : sal_uInt16 mnLoopControlStage;
39 : public:
40 : explicit SwLooping( SwPageFrm* pPage );
41 : void Control( SwPageFrm* pPage );
42 : void Drastic( SwFrm* pFrm );
43 2 : bool IsLoopingLouieLight() const { return nCount > LOOP_DETECT - 30; };
44 : };
45 :
46 : class SwEndnoter
47 : {
48 : SwLayouter* pMaster;
49 : SwSectionFrm* pSect;
50 : SwFootnoteFrms* pEndArr;
51 : public:
52 1 : explicit SwEndnoter( SwLayouter* pLay )
53 1 : : pMaster( pLay ), pSect( NULL ), pEndArr( NULL ) {}
54 1 : ~SwEndnoter() { delete pEndArr; }
55 : void CollectEndnotes( SwSectionFrm* pSct );
56 : void CollectEndnote( SwFootnoteFrm* pFootnote );
57 17 : const SwSectionFrm* GetSect() const { return pSect; }
58 : void InsertEndnotes();
59 15 : bool HasEndnotes() const { return pEndArr && !pEndArr->empty(); }
60 : };
61 :
62 15 : void SwEndnoter::CollectEndnotes( SwSectionFrm* pSct )
63 : {
64 : OSL_ENSURE( pSct, "CollectEndnotes: Which section?" );
65 15 : if( !pSect )
66 15 : pSect = pSct;
67 0 : else if( pSct != pSect )
68 15 : return;
69 15 : pSect->CollectEndnotes( pMaster );
70 : }
71 :
72 15 : void SwEndnoter::CollectEndnote( SwFootnoteFrm* pFootnote )
73 : {
74 15 : if( pEndArr && pEndArr->end() != std::find( pEndArr->begin(), pEndArr->end(), pFootnote ) )
75 0 : return;
76 :
77 15 : if( pFootnote->GetUpper() )
78 : {
79 : // pFootnote is the master, he incorporates its follows
80 14 : SwFootnoteFrm *pNxt = pFootnote->GetFollow();
81 33 : while ( pNxt )
82 : {
83 5 : SwFrm *pCnt = pNxt->ContainsAny();
84 5 : if ( pCnt )
85 : {
86 5 : do
87 5 : { SwFrm *pNxtCnt = pCnt->GetNext();
88 5 : pCnt->Cut();
89 5 : pCnt->Paste( pFootnote );
90 5 : pCnt = pNxtCnt;
91 : } while ( pCnt );
92 : }
93 : else
94 : { OSL_ENSURE( pNxt->Lower() && pNxt->Lower()->IsSctFrm(),
95 : "Endnote without content?" );
96 0 : pNxt->Cut();
97 0 : SwFrm::DestroyFrm(pNxt);
98 : }
99 5 : pNxt = pFootnote->GetFollow();
100 : }
101 14 : if( pFootnote->GetMaster() )
102 0 : return;
103 14 : pFootnote->Cut();
104 : }
105 1 : else if( pEndArr )
106 : {
107 0 : for ( size_t i = 0; i < pEndArr->size(); ++i )
108 : {
109 0 : SwFootnoteFrm *pEndFootnote = (*pEndArr)[i];
110 0 : if( pEndFootnote->GetAttr() == pFootnote->GetAttr() )
111 : {
112 0 : SwFrm::DestroyFrm(pFootnote);
113 0 : return;
114 : }
115 : }
116 : }
117 15 : if( !pEndArr )
118 15 : pEndArr = new SwFootnoteFrms; // deleted from the SwLayouter
119 15 : pEndArr->push_back( pFootnote );
120 : }
121 :
122 15 : void SwEndnoter::InsertEndnotes()
123 : {
124 15 : if( !pSect )
125 0 : return;
126 15 : if( !pEndArr || pEndArr->empty() )
127 : {
128 0 : pSect = NULL;
129 0 : return;
130 : }
131 : OSL_ENSURE( pSect->Lower() && pSect->Lower()->IsFootnoteBossFrm(),
132 : "InsertEndnotes: Where's my column?" );
133 15 : SwFrm* pRef = pSect->FindLastContent( FINDMODE_MYLAST );
134 : SwFootnoteBossFrm *pBoss = pRef ? pRef->FindFootnoteBossFrm()
135 15 : : static_cast<SwFootnoteBossFrm*>(pSect->Lower());
136 15 : pBoss->_MoveFootnotes( *pEndArr );
137 15 : delete pEndArr;
138 15 : pEndArr = NULL;
139 15 : pSect = NULL;
140 : }
141 :
142 10009 : SwLooping::SwLooping( SwPageFrm* pPage )
143 : {
144 : OSL_ENSURE( pPage, "Where's my page?" );
145 10009 : nMinPage = pPage->GetPhyPageNum();
146 10009 : nMaxPage = nMinPage;
147 10009 : nCount = 0;
148 10009 : mnLoopControlStage = 0;
149 10009 : }
150 :
151 0 : void SwLooping::Drastic( SwFrm* pFrm )
152 : {
153 0 : while( pFrm )
154 : {
155 0 : pFrm->ValidateThisAndAllLowers( mnLoopControlStage );
156 0 : pFrm = pFrm->GetNext();
157 : }
158 0 : }
159 :
160 18433 : void SwLooping::Control( SwPageFrm* pPage )
161 : {
162 18433 : if( !pPage )
163 22773 : return;
164 14093 : const sal_uInt16 nNew = pPage->GetPhyPageNum();
165 14093 : if( nNew > nMaxPage )
166 1975 : nMaxPage = nNew;
167 14093 : if( nNew < nMinPage )
168 : {
169 169 : nMinPage = nNew;
170 169 : nMaxPage = nNew;
171 169 : nCount = 0;
172 169 : mnLoopControlStage = 0;
173 : }
174 13924 : else if( nNew > nMinPage + 2 )
175 : {
176 705 : nMinPage = nNew - 2;
177 705 : nMaxPage = nNew;
178 705 : nCount = 0;
179 705 : mnLoopControlStage = 0;
180 : }
181 13219 : else if( ++nCount > LOOP_DETECT )
182 : {
183 : #if OSL_DEBUG_LEVEL > 1
184 : static bool bNoLouie = false;
185 : if( bNoLouie )
186 : return;
187 :
188 : // FME 2007-08-30 #i81146# new loop control
189 : OSL_ENSURE( 0 != mnLoopControlStage, "Looping Louie: Stage 1!" );
190 : OSL_ENSURE( 1 != mnLoopControlStage, "Looping Louie: Stage 2!!" );
191 : OSL_ENSURE( 2 > mnLoopControlStage, "Looping Louie: Stage 3!!!" );
192 : #endif
193 :
194 0 : Drastic( pPage->Lower() );
195 0 : if( nNew > nMinPage && pPage->GetPrev() )
196 0 : Drastic( static_cast<SwPageFrm*>(pPage->GetPrev())->Lower() );
197 0 : if( nNew < nMaxPage && pPage->GetNext() )
198 0 : Drastic( static_cast<SwPageFrm*>(pPage->GetNext())->Lower() );
199 :
200 0 : ++mnLoopControlStage;
201 0 : nCount = 0;
202 : }
203 : }
204 :
205 2764 : SwLayouter::SwLayouter()
206 : : mpEndnoter( NULL ),
207 : mpLooping( NULL ),
208 : // #i28701#
209 : mpMovedFwdFrms( 0L ),
210 : // #i35911#
211 2764 : mpObjsTmpConsiderWrapInfl( 0L )
212 : {
213 2764 : }
214 :
215 5518 : SwLayouter::~SwLayouter()
216 : {
217 2759 : delete mpEndnoter;
218 2759 : delete mpLooping;
219 : // #i28701#
220 2759 : delete mpMovedFwdFrms;
221 2759 : mpMovedFwdFrms = 0L;
222 : // #i35911#
223 2759 : delete mpObjsTmpConsiderWrapInfl;
224 2759 : mpObjsTmpConsiderWrapInfl = 0L;
225 2759 : }
226 :
227 15 : void SwLayouter::_CollectEndnotes( SwSectionFrm* pSect )
228 : {
229 15 : if( !mpEndnoter )
230 1 : mpEndnoter = new SwEndnoter( this );
231 15 : mpEndnoter->CollectEndnotes( pSect );
232 15 : }
233 :
234 15 : bool SwLayouter::HasEndnotes() const
235 : {
236 15 : return mpEndnoter->HasEndnotes();
237 : }
238 :
239 15 : void SwLayouter::CollectEndnote( SwFootnoteFrm* pFootnote )
240 : {
241 15 : mpEndnoter->CollectEndnote( pFootnote );
242 15 : }
243 :
244 15 : void SwLayouter::InsertEndnotes( SwSectionFrm* pSect )
245 : {
246 15 : if( !mpEndnoter || mpEndnoter->GetSect() != pSect )
247 15 : return;
248 15 : mpEndnoter->InsertEndnotes();
249 : }
250 :
251 18433 : void SwLayouter::LoopControl( SwPageFrm* pPage, sal_uInt8 )
252 : {
253 : OSL_ENSURE( mpLooping, "Looping: Lost control" );
254 18433 : mpLooping->Control( pPage );
255 18433 : }
256 :
257 2 : void SwLayouter::LoopingLouieLight( const SwDoc& rDoc, const SwTextFrm& rFrm )
258 : {
259 2 : if ( mpLooping && mpLooping->IsLoopingLouieLight() )
260 : {
261 : #if OSL_DEBUG_LEVEL > 1
262 : OSL_FAIL( "Looping Louie (Light): Fixating fractious frame" );
263 : #endif
264 0 : SwLayouter::InsertMovedFwdFrm( rDoc, rFrm, rFrm.FindPageFrm()->GetPhyPageNum() );
265 : }
266 2 : }
267 :
268 10009 : bool SwLayouter::StartLooping( SwPageFrm* pPage )
269 : {
270 10009 : if( mpLooping )
271 0 : return false;
272 10009 : mpLooping = new SwLooping( pPage );
273 10009 : return true;
274 : }
275 :
276 10009 : void SwLayouter::EndLoopControl()
277 : {
278 10009 : delete mpLooping;
279 10009 : mpLooping = NULL;
280 10009 : }
281 :
282 15 : void SwLayouter::CollectEndnotes( SwDoc* pDoc, SwSectionFrm* pSect )
283 : {
284 : assert(pDoc && "No doc, no fun");
285 15 : if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
286 0 : pDoc->getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
287 15 : pDoc->getIDocumentLayoutAccess().GetLayouter()->_CollectEndnotes( pSect );
288 15 : }
289 :
290 1 : bool SwLayouter::Collecting( SwDoc* pDoc, SwSectionFrm* pSect, SwFootnoteFrm* pFootnote )
291 : {
292 1 : if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
293 0 : return false;
294 1 : SwLayouter *pLayouter = pDoc->getIDocumentLayoutAccess().GetLayouter();
295 3 : if( pLayouter->mpEndnoter && pLayouter->mpEndnoter->GetSect() && pSect &&
296 1 : ( pLayouter->mpEndnoter->GetSect()->IsAnFollow( pSect ) ||
297 0 : pSect->IsAnFollow( pLayouter->mpEndnoter->GetSect() ) ) )
298 : {
299 1 : if( pFootnote )
300 0 : pLayouter->CollectEndnote( pFootnote );
301 1 : return true;
302 : }
303 0 : return false;
304 : }
305 :
306 10009 : bool SwLayouter::StartLoopControl( SwDoc* pDoc, SwPageFrm *pPage )
307 : {
308 : OSL_ENSURE( pDoc, "No doc, no fun" );
309 10009 : if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
310 2764 : pDoc->getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
311 20018 : return !pDoc->getIDocumentLayoutAccess().GetLayouter()->mpLooping &&
312 20018 : pDoc->getIDocumentLayoutAccess().GetLayouter()->StartLooping( pPage );
313 : }
314 :
315 : // #i28701#
316 : // methods to manage text frames, which are moved forward by the positioning
317 : // of its anchored objects
318 1004792 : void SwLayouter::ClearMovedFwdFrms( const SwDoc& _rDoc )
319 : {
320 1050407 : if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() &&
321 45615 : _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms )
322 : {
323 63 : _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms->Clear();
324 : }
325 1004792 : }
326 :
327 4 : void SwLayouter::InsertMovedFwdFrm( const SwDoc& _rDoc,
328 : const SwTextFrm& _rMovedFwdFrmByObjPos,
329 : const sal_uInt32 _nToPageNum )
330 : {
331 4 : if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
332 : {
333 0 : const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
334 : }
335 :
336 4 : if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms )
337 : {
338 4 : const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms =
339 8 : new SwMovedFwdFrmsByObjPos();
340 : }
341 :
342 4 : _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms->Insert( _rMovedFwdFrmByObjPos,
343 4 : _nToPageNum );
344 4 : }
345 :
346 : // #i40155#
347 10 : void SwLayouter::RemoveMovedFwdFrm( const SwDoc& _rDoc,
348 : const SwTextFrm& _rTextFrm )
349 : {
350 : sal_uInt32 nDummy;
351 10 : if ( SwLayouter::FrmMovedFwdByObjPos( _rDoc, _rTextFrm, nDummy ) )
352 : {
353 0 : _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms->Remove( _rTextFrm );
354 : }
355 10 : }
356 :
357 73856 : bool SwLayouter::FrmMovedFwdByObjPos( const SwDoc& _rDoc,
358 : const SwTextFrm& _rTextFrm,
359 : sal_uInt32& _ornToPageNum )
360 : {
361 73856 : if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
362 : {
363 10084 : _ornToPageNum = 0;
364 10084 : return false;
365 : }
366 63772 : else if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms )
367 : {
368 63406 : _ornToPageNum = 0;
369 63406 : return false;
370 : }
371 : else
372 : {
373 366 : return _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms->
374 366 : FrmMovedFwdByObjPos( _rTextFrm, _ornToPageNum );
375 : }
376 : }
377 :
378 : // #i26945#
379 10 : bool SwLayouter::DoesRowContainMovedFwdFrm( const SwDoc& _rDoc,
380 : const SwRowFrm& _rRowFrm )
381 : {
382 10 : if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
383 : {
384 0 : return false;
385 : }
386 10 : else if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrms )
387 : {
388 10 : return false;
389 : }
390 : else
391 : {
392 0 : return _rDoc.getIDocumentLayoutAccess().GetLayouter()->
393 0 : mpMovedFwdFrms->DoesRowContainMovedFwdFrm( _rRowFrm );
394 : }
395 : }
396 :
397 : // #i35911#
398 1004792 : void SwLayouter::ClearObjsTmpConsiderWrapInfluence( const SwDoc& _rDoc )
399 : {
400 1050407 : if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() &&
401 45615 : _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl )
402 : {
403 32 : _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Clear();
404 : }
405 1004792 : }
406 1 : void SwLayouter::InsertObjForTmpConsiderWrapInfluence(
407 : const SwDoc& _rDoc,
408 : SwAnchoredObject& _rAnchoredObj )
409 : {
410 1 : if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
411 : {
412 0 : const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
413 : }
414 :
415 1 : if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl )
416 : {
417 1 : const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl =
418 2 : new SwObjsMarkedAsTmpConsiderWrapInfluence();
419 : }
420 :
421 1 : _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Insert( _rAnchoredObj );
422 1 : }
423 :
424 68948 : void LOOPING_LOUIE_LIGHT( bool bCondition, const SwTextFrm& rTextFrm )
425 : {
426 68948 : if ( bCondition )
427 : {
428 2 : const SwDoc& rDoc = *rTextFrm.GetAttrSet()->GetDoc();
429 2 : if ( rDoc.getIDocumentLayoutAccess().GetLayouter() )
430 : {
431 2 : const_cast<SwDoc&>(rDoc).getIDocumentLayoutAccess().GetLayouter()->LoopingLouieLight( rDoc, rTextFrm );
432 : }
433 : }
434 68948 : }
435 :
436 : // #i65250#
437 6797 : bool SwLayouter::MoveBwdSuppressed( const SwDoc& p_rDoc,
438 : const SwFlowFrm& p_rFlowFrm,
439 : const SwLayoutFrm& p_rNewUpperFrm )
440 : {
441 6797 : bool bMoveBwdSuppressed( false );
442 :
443 6797 : if ( !p_rDoc.getIDocumentLayoutAccess().GetLayouter() )
444 : {
445 0 : const_cast<SwDoc&>(p_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
446 : }
447 :
448 : // create hash map key
449 : tMoveBwdLayoutInfoKey aMoveBwdLayoutInfo;
450 6797 : aMoveBwdLayoutInfo.mnFrmId = p_rFlowFrm.GetFrm().GetFrmId();
451 6797 : aMoveBwdLayoutInfo.mnNewUpperPosX = p_rNewUpperFrm.Frm().Pos().X();
452 6797 : aMoveBwdLayoutInfo.mnNewUpperPosY = p_rNewUpperFrm.Frm().Pos().Y();
453 6797 : aMoveBwdLayoutInfo.mnNewUpperWidth = p_rNewUpperFrm.Frm().Width();
454 6797 : aMoveBwdLayoutInfo.mnNewUpperHeight = p_rNewUpperFrm.Frm().Height();
455 6797 : SWRECTFN( (&p_rNewUpperFrm) )
456 6797 : const SwFrm* pLastLower( p_rNewUpperFrm.Lower() );
457 85951 : while ( pLastLower && pLastLower->GetNext() )
458 : {
459 72357 : pLastLower = pLastLower->GetNext();
460 : }
461 : aMoveBwdLayoutInfo.mnFreeSpaceInNewUpper =
462 : pLastLower
463 6526 : ? (pLastLower->Frm().*fnRect->fnBottomDist)( (p_rNewUpperFrm.*fnRect->fnGetPrtBottom)() )
464 13323 : : (p_rNewUpperFrm.Frm().*fnRect->fnGetHeight)();
465 :
466 : // check for moving backward suppress threshold
467 6797 : const sal_uInt16 cMoveBwdCountSuppressThreshold = 20;
468 6797 : if ( ++const_cast<SwDoc&>(p_rDoc).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo[ aMoveBwdLayoutInfo ] >
469 : cMoveBwdCountSuppressThreshold )
470 : {
471 0 : bMoveBwdSuppressed = true;
472 : }
473 :
474 6797 : return bMoveBwdSuppressed;
475 : }
476 :
477 1004792 : void SwLayouter::ClearMoveBwdLayoutInfo( const SwDoc& _rDoc )
478 : {
479 1004792 : if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() )
480 45615 : const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo.clear();
481 1004969 : }
482 :
483 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|