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