xref: /AOO41X/main/sw/source/core/layout/laycache.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <hintids.hxx>
33 #include <editeng/brkitem.hxx>
34 #include <tools/stream.hxx>
35 #include <doc.hxx>
36 #include <docstat.hxx>
37 #include <docary.hxx>
38 #include <fmtpdsc.hxx>
39 #include <laycache.hxx>
40 #include <layhelp.hxx>
41 #include <pagefrm.hxx>
42 #include <rootfrm.hxx>
43 #include <txtfrm.hxx>
44 #include <ndtxt.hxx>
45 #include <swtable.hxx>
46 #include <tabfrm.hxx>
47 #include <rowfrm.hxx>
48 #include <colfrm.hxx>
49 #include <bodyfrm.hxx>
50 #include <ndindex.hxx>
51 #include <sectfrm.hxx>
52 #include <frmfmt.hxx>
53 #include <fmtcntnt.hxx>
54 #include <pagedesc.hxx>
55 #include <frmtool.hxx>
56 #include <dflyobj.hxx>
57 #include <dcontact.hxx>
58 #include "viewopt.hxx"
59 #include "viewsh.hxx"
60 #include <flyfrm.hxx>
61 // OD 2004-05-24 #i28701#
62 #include <sortedobjs.hxx>
63 // --> OD 2006-03-22 #b6375613#
64 #include <pam.hxx>
65 #include <docsh.hxx>
66 #include <com/sun/star/document/XDocumentInfoSupplier.hpp>
67 #include <com/sun/star/beans/XPropertySet.hpp>
68 
69 #include <set>
70 
71 
72 using namespace ::com::sun::star;
73 // <--
74 
75 SV_IMPL_PTRARR( SwPageFlyCache, SwFlyCachePtr )
76 
77 /*-----------------28.5.2001 10:06------------------
78  *  Reading and writing of the layout cache.
79  *  The layout cache is not necessary, but it improves
80  *  the performance and reduces the text flow during
81  *  the formatting.
82  *  The layout cache contains the index of the paragraphs/tables
83  *  at the top of every page, so it's possible to create
84  *  the right count of pages and to distribute the document content
85  *  to this pages before the formatting starts.
86  *--------------------------------------------------*/
87 
88 void SwLayoutCache::Read( SvStream &rStream )
89 {
90     if( !pImpl )
91 	{
92         pImpl = new SwLayCacheImpl;
93 		if( !pImpl->Read( rStream ) )
94 		{
95 			delete pImpl;
96 			pImpl = 0;
97 		}
98 	}
99 }
100 
101 //-----------------------------------------------------------------------------
102 
103 void SwLayCacheImpl::Insert( sal_uInt16 nType, sal_uLong nIndex, xub_StrLen nOffset )
104 {
105 	aType.Insert( nType, aType.Count() );
106 	SvULongs::Insert( nIndex, SvULongs::Count() );
107 	aOffset.push_back( nOffset );
108 }
109 
110 sal_Bool SwLayCacheImpl::Read( SvStream& rStream )
111 {
112 	SwLayCacheIoImpl aIo( rStream, sal_False );
113 	if( aIo.GetMajorVersion() > SW_LAYCACHE_IO_VERSION_MAJOR )
114 		return sal_False;
115 
116     // Due to an evil bug in the layout cache (#102759#), we cannot trust the
117     // sizes of fly frames which have been written using the "old" layout cache.
118     // This flag should indicate that we do not want to trust the width and
119     // height of fly frames
120     bUseFlyCache = aIo.GetMinorVersion() >= 1;
121 
122 	sal_uInt8 cFlags;
123 	sal_uInt32 nIndex, nOffset;
124 
125 	aIo.OpenRec( SW_LAYCACHE_IO_REC_PAGES );
126 	aIo.OpenFlagRec();
127 	aIo.CloseFlagRec();
128 	while( aIo.BytesLeft() && !aIo.HasError() )
129 	{
130 		switch( aIo.Peek() )
131 		{
132 		case SW_LAYCACHE_IO_REC_PARA:
133 			aIo.OpenRec( SW_LAYCACHE_IO_REC_PARA );
134 			cFlags = aIo.OpenFlagRec();
135 			aIo.GetStream() >> nIndex;
136 			if( (cFlags & 0x01) != 0 )
137 				aIo.GetStream() >> nOffset;
138 			else
139 				nOffset = STRING_LEN;
140 			aIo.CloseFlagRec();
141 			Insert( SW_LAYCACHE_IO_REC_PARA, nIndex, (xub_StrLen)nOffset );
142 			aIo.CloseRec( SW_LAYCACHE_IO_REC_PARA );
143 			break;
144 		case SW_LAYCACHE_IO_REC_TABLE:
145 			aIo.OpenRec( SW_LAYCACHE_IO_REC_TABLE );
146 			aIo.OpenFlagRec();
147             aIo.GetStream() >> nIndex
148                             >> nOffset;
149 			Insert( SW_LAYCACHE_IO_REC_TABLE, nIndex, (xub_StrLen)nOffset );
150 			aIo.CloseFlagRec();
151 			aIo.CloseRec( SW_LAYCACHE_IO_REC_TABLE );
152 			break;
153         case SW_LAYCACHE_IO_REC_FLY:
154         {
155             aIo.OpenRec( SW_LAYCACHE_IO_REC_FLY );
156 			aIo.OpenFlagRec();
157 			aIo.CloseFlagRec();
158             long nX, nY, nW, nH;
159             sal_uInt16 nPgNum;
160             aIo.GetStream() >> nPgNum >> nIndex
161                     >> nX >> nY >> nW >> nH;
162             SwFlyCache* pFly = new SwFlyCache( nPgNum, nIndex, nX, nY, nW, nH );
163             aFlyCache.Insert( pFly, aFlyCache.Count() );
164             aIo.CloseRec( SW_LAYCACHE_IO_REC_FLY );
165 			break;
166         }
167 		default:
168 			aIo.SkipRec();
169 			break;
170 		}
171 	}
172 	aIo.CloseRec( SW_LAYCACHE_IO_REC_PAGES );
173 
174 	return !aIo.HasError();
175 }
176 
177 /*-----------------28.5.2001 10:19------------------
178  * SwLayoutCache::Write(..)
179  * writes the index (more precise: the difference between
180  * the index and the first index of the document content)
181  * of the first paragraph/table at the top of every page.
182  * If at the top of a page is the rest of a paragraph/table
183  * from the bottom of the previous page, the character/row
184  * number is stored, too.
185  * The position, size and page number of the text frames
186  * are stored, too
187  * --------------------------------------------------*/
188 
189 void SwLayoutCache::Write( SvStream &rStream, const SwDoc& rDoc )
190 {
191     if( rDoc.GetCurrentLayout() ) // the layout itself ..	//swmod 080218
192     {
193 		SwLayCacheIoImpl aIo( rStream, sal_True );
194         // We want to save the relative index, so we need the index
195         // of the first content
196         sal_uLong nStartOfContent = rDoc.GetNodes().GetEndOfContent().
197                                 StartOfSectionNode()->GetIndex();
198         // The first page..
199         SwPageFrm* pPage = (SwPageFrm*)rDoc.GetCurrentLayout()->Lower();	//swmod 080218
200 
201 		aIo.OpenRec( SW_LAYCACHE_IO_REC_PAGES );
202 		aIo.OpenFlagRec( 0, 0 );
203 		aIo.CloseFlagRec();
204         while( pPage )
205         {
206             if( pPage->GetPrev() )
207             {
208                 SwLayoutFrm* pLay = pPage->FindBodyCont();
209                 SwFrm* pTmp = pLay ? pLay->ContainsAny() : NULL;
210                 // We are only interested in paragraph or table frames,
211                 // a section frames contains paragraphs/tables.
212                 if( pTmp && pTmp->IsSctFrm() )
213                     pTmp = ((SwSectionFrm*)pTmp)->ContainsAny();
214 
215                 if( pTmp ) // any content
216                 {
217                     if( pTmp->IsTxtFrm() )
218                     {
219                         sal_uLong nNdIdx = ((SwTxtFrm*)pTmp)->GetNode()->GetIndex();
220                         if( nNdIdx > nStartOfContent )
221                         {
222                             /*  Open Paragraph Record */
223                             aIo.OpenRec( SW_LAYCACHE_IO_REC_PARA );
224                             sal_Bool bFollow = ((SwTxtFrm*)pTmp)->IsFollow();
225                             aIo.OpenFlagRec( bFollow ? 0x01 : 0x00,
226                                             bFollow ? 8 : 4 );
227                             nNdIdx -= nStartOfContent;
228                             aIo.GetStream() << static_cast<sal_uInt32>(nNdIdx);
229                             if( bFollow )
230                                 aIo.GetStream() << static_cast<sal_uInt32>(((SwTxtFrm*)pTmp)->GetOfst());
231                             aIo.CloseFlagRec();
232                             /*  Close Paragraph Record */
233                             aIo.CloseRec( SW_LAYCACHE_IO_REC_PARA );
234                         }
235                     }
236                     else if( pTmp->IsTabFrm() )
237                     {
238                         SwTabFrm* pTab = (SwTabFrm*)pTmp;
239                         sal_uLong nOfst = STRING_LEN;
240                         if( pTab->IsFollow() )
241                         {
242                             // If the table is a follow, we have to look for the
243                             // master and to count all rows to get the row number
244                             nOfst = 0;
245                             if( pTab->IsFollow() )
246                                 pTab = pTab->FindMaster( true );
247                             while( pTab != pTmp )
248                             {
249                                 SwFrm* pSub = pTab->Lower();
250                                 while( pSub )
251                                 {
252                                     ++nOfst;
253                                     pSub = pSub->GetNext();
254                                 }
255                                 pTab = pTab->GetFollow();
256                                 ASSERT( pTab, "Table follow without master" );
257                             }
258                         }
259                         do
260                         {
261                             sal_uLong nNdIdx =
262                                     pTab->GetTable()->GetTableNode()->GetIndex();
263                             if( nNdIdx > nStartOfContent )
264                             {
265                                 /* Open Table Record */
266                                 aIo.OpenRec( SW_LAYCACHE_IO_REC_TABLE );
267                                 aIo.OpenFlagRec( 0, 8 );
268                                 nNdIdx -= nStartOfContent;
269                                 aIo.GetStream() << static_cast<sal_uInt32>(nNdIdx)
270                                                 << static_cast<sal_uInt32>(nOfst);
271                                 aIo.CloseFlagRec();
272                                 /* Close Table Record  */
273                                 aIo.CloseRec( SW_LAYCACHE_IO_REC_TABLE );
274                             }
275                             // If the table has a follow on the next page,
276                             // we know already the row number and store this
277                             // immediately.
278                             if( pTab->GetFollow() )
279                             {
280                                 if( nOfst == STRING_LEN )
281                                     nOfst = 0;
282                                 do
283                                 {
284                                     SwFrm* pSub = pTab->Lower();
285                                     while( pSub )
286                                     {
287                                         ++nOfst;
288                                         pSub = pSub->GetNext();
289                                     }
290                                     pTab = pTab->GetFollow();
291                                     SwPageFrm *pTabPage = pTab->FindPageFrm();
292                                     if( pTabPage != pPage )
293                                     {
294                                         ASSERT( pPage->GetPhyPageNum() <
295                                                 pTabPage->GetPhyPageNum(),
296                                                 "Looping Tableframes" );
297                                         pPage = pTabPage;
298                                         break;
299                                     }
300                                 } while ( pTab->GetFollow() );
301                             }
302                             else
303                                 break;
304                         } while( pTab );
305                     }
306                 }
307             }
308             if( pPage->GetSortedObjs() )
309             {
310                 SwSortedObjs &rObjs = *pPage->GetSortedObjs();
311                 for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
312                 {
313                     SwAnchoredObject* pAnchoredObj = rObjs[i];
314                     if ( pAnchoredObj->ISA(SwFlyFrm) )
315                     {
316                         SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
317                         if( pFly->Frm().Left() != WEIT_WECH &&
318                             !pFly->GetAnchorFrm()->FindFooterOrHeader() )
319                         {
320                             const SwContact *pC =
321                                     ::GetUserCall(pAnchoredObj->GetDrawObj());
322                             if( pC )
323                             {
324                                 sal_uInt32 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
325                                 sal_uInt16 nPageNum = pPage->GetPhyPageNum();
326                                 /* Open Fly Record */
327                                 aIo.OpenRec( SW_LAYCACHE_IO_REC_FLY );
328                                 aIo.OpenFlagRec( 0, 0 );
329                                 aIo.CloseFlagRec();
330                                 SwRect &rRct = pFly->Frm();
331                                 sal_Int32 nX = rRct.Left() - pPage->Frm().Left();
332                                 sal_Int32 nY = rRct.Top() - pPage->Frm().Top();
333                                 aIo.GetStream() << nPageNum << nOrdNum
334                                                 << nX << nY << rRct.Width()
335                                                 << rRct.Height();
336                                 /* Close Fly Record  */
337                                 aIo.CloseRec( SW_LAYCACHE_IO_REC_FLY );
338                             }
339                         }
340                     }
341                 }
342             }
343             pPage = (SwPageFrm*)pPage->GetNext();
344         }
345 		aIo.CloseRec( SW_LAYCACHE_IO_REC_PAGES );
346     }
347 }
348 
349 #ifdef DBG_UTIL
350 sal_Bool SwLayoutCache::CompareLayout( const SwDoc& rDoc ) const
351 {
352     if( !pImpl )
353         return sal_True;
354     const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout();
355     sal_Bool bRet = sal_True;
356     if( pRootFrm )
357     {
358         sal_uInt16 nIndex = 0;
359         sal_uLong nStartOfContent = rDoc.GetNodes().GetEndOfContent().
360                                 StartOfSectionNode()->GetIndex();
361         SwPageFrm* pPage = (SwPageFrm*)pRootFrm->Lower();
362         if( pPage )
363             pPage = (SwPageFrm*)pPage->GetNext();
364         while( pPage )
365         {
366             if( nIndex >= pImpl->Count() )
367             {
368                 if( bRet )
369                     bRet = sal_False;
370                 break;
371             }
372             SwLayoutFrm* pLay = pPage->FindBodyCont();
373             SwFrm* pTmp = pLay ? pLay->ContainsAny() : NULL;
374             if( pTmp && pTmp->IsSctFrm() )
375                 pTmp = ((SwSectionFrm*)pTmp)->ContainsAny();
376             if( pTmp )
377             {
378                 if( pTmp->IsTxtFrm() )
379                 {
380                     sal_uLong nNdIdx = ((SwTxtFrm*)pTmp)->GetNode()->GetIndex();
381                     if( nNdIdx > nStartOfContent )
382                     {
383 						sal_Bool bFollow = ((SwTxtFrm*)pTmp)->IsFollow();
384                         nNdIdx -= nStartOfContent;
385                         if( pImpl->GetBreakIndex( nIndex ) != nNdIdx ||
386                             SW_LAYCACHE_IO_REC_PARA !=
387                             pImpl->GetBreakType( nIndex ) ||
388                             ( bFollow ? ((SwTxtFrm*)pTmp)->GetOfst()
389                               : STRING_LEN ) != pImpl->GetBreakOfst( nIndex ) )
390                         {
391                             if( bRet )
392                                 bRet = sal_False;
393                         }
394                         ++nIndex;
395                     }
396                 }
397                 else if( pTmp->IsTabFrm() )
398                 {
399                     SwTabFrm* pTab = (SwTabFrm*)pTmp;
400                     sal_uLong nOfst = STRING_LEN;
401                     if( pTab->IsFollow() )
402                     {
403                         nOfst = 0;
404                         if( pTab->IsFollow() )
405                             pTab = pTab->FindMaster( true );
406                         while( pTab != pTmp )
407                         {
408                             SwFrm* pSub = pTab->Lower();
409                             while( pSub )
410                             {
411                                 ++nOfst;
412                                 pSub = pSub->GetNext();
413                             }
414                             pTab = pTab->GetFollow();
415                         }
416                     }
417                     do
418                     {
419                         sal_uLong nNdIdx =
420                                 pTab->GetTable()->GetTableNode()->GetIndex();
421                         if( nNdIdx > nStartOfContent )
422                         {
423                             nNdIdx -= nStartOfContent;
424                             if( pImpl->GetBreakIndex( nIndex ) != nNdIdx ||
425                                 SW_LAYCACHE_IO_REC_TABLE !=
426                                 pImpl->GetBreakType( nIndex ) ||
427                                nOfst != pImpl->GetBreakOfst( nIndex ) )
428                             {
429                                 if( bRet )
430                                     bRet = sal_False;
431                             }
432                             ++nIndex;
433                         }
434                         if( pTab->GetFollow() )
435                         {
436                             if( nOfst == STRING_LEN )
437                                 nOfst = 0;
438                             do
439                             {
440                                 SwFrm* pSub = pTab->Lower();
441                                 while( pSub )
442                                 {
443                                     ++nOfst;
444                                     pSub = pSub->GetNext();
445                                 }
446                                 pTab = pTab->GetFollow();
447                                 SwPageFrm *pTabPage = pTab->FindPageFrm();
448                                 if( pTabPage != pPage )
449                                 {
450                                     pPage = pTabPage;
451                                     break;
452                                 }
453                             } while ( pTab->GetFollow() );
454                         }
455                         else
456                             break;
457                     } while( pTab );
458                 }
459             }
460             pPage = (SwPageFrm*)pPage->GetNext();
461         }
462     }
463     return bRet;
464 }
465 #endif
466 
467 void SwLayoutCache::ClearImpl()
468 {
469     if( !IsLocked() )
470     {
471         delete pImpl;
472         pImpl = 0;
473     }
474 }
475 
476 
477 SwLayoutCache::~SwLayoutCache()
478 {
479     ASSERT( !nLockCount, "Deleting a locked SwLayoutCache!?" );
480     delete pImpl;
481 }
482 
483 /*-----------------28.5.2001 10:47------------------
484  * SwActualSection,
485  *  a help class to create not nested section frames
486  *  for nested sections.
487  * --------------------------------------------------*/
488 
489 SwActualSection::SwActualSection( SwActualSection *pUp,
490 								  SwSectionFrm	  *pSect,
491 								  SwSectionNode	  *pNd ) :
492 	pUpper( pUp ),
493 	pSectFrm( pSect ),
494 	pSectNode( pNd )
495 {
496 	if ( !pSectNode )
497 	{
498 		const SwNodeIndex *pIndex = pSect->GetFmt()->GetCntnt().GetCntntIdx();
499         pSectNode = pIndex->GetNode().FindSectionNode();
500     }
501 }
502 
503 /*-----------------28.5.2001 11:09------------------
504  * SwLayHelper
505  *  is the helper class, which utilizes the layout cache information
506  *  to distribute the document content to the rigth pages.
507  * It's used by the _InsertCnt(..)-function.
508  * If there's no layout cache, the distibution to the pages is more
509  * a guess, but a guess with statistical background.
510  * --------------------------------------------------*/
511 
512 SwLayHelper::SwLayHelper( SwDoc *pD, SwFrm* &rpF, SwFrm* &rpP, SwPageFrm* &rpPg,
513             SwLayoutFrm* &rpL, SwActualSection* &rpA, sal_Bool &rB,
514             sal_uLong nNodeIndex, sal_Bool bCache )
515     : rpFrm( rpF ), rpPrv( rpP ), rpPage( rpPg ), rpLay( rpL ),
516       rpActualSection( rpA ), rbBreakAfter(rB), pDoc(pD), nMaxParaPerPage( 25 ),
517       nParagraphCnt( bCache ? 0 : USHRT_MAX ), bFirst( bCache )
518 {
519     pImpl = pDoc->GetLayoutCache() ? pDoc->GetLayoutCache()->LockImpl() : NULL;
520     if( pImpl )
521     {
522         nMaxParaPerPage = 1000;
523         nStartOfContent = pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()
524                           ->GetIndex();
525         nNodeIndex -= nStartOfContent;
526         nIndex = 0;
527         nFlyIdx = 0;
528         while( nIndex < pImpl->Count() && (*pImpl)[ nIndex ] < nNodeIndex )
529             ++nIndex;
530         if( nIndex >= pImpl->Count() )
531         {
532             pDoc->GetLayoutCache()->UnlockImpl();
533             pImpl = NULL;
534         }
535     }
536     else
537     {
538         nIndex = USHRT_MAX;
539         nStartOfContent = ULONG_MAX;
540     }
541 }
542 
543 SwLayHelper::~SwLayHelper()
544 {
545     if( pImpl )
546     {
547         ASSERT( pDoc && pDoc->GetLayoutCache(), "Missing layoutcache" );
548         pDoc->GetLayoutCache()->UnlockImpl();
549     }
550 }
551 
552 /*-----------------23.5.2001 16:40------------------
553  * SwLayHelper::CalcPageCount() does not really calculate the page count,
554  * it returns the page count value from the layout cache, if available,
555  * otherwise it estimates the page count.
556  * --------------------------------------------------*/
557 
558 sal_uLong SwLayHelper::CalcPageCount()
559 {
560     sal_uLong nPgCount;
561     SwLayCacheImpl *pCache = pDoc->GetLayoutCache() ?
562                              pDoc->GetLayoutCache()->LockImpl() : NULL;
563     if( pCache )
564     {
565         nPgCount = pCache->Count() + 1;
566         pDoc->GetLayoutCache()->UnlockImpl();
567     }
568     else
569     {
570 		nPgCount = pDoc->GetDocStat().nPage;
571         if ( nPgCount <= 10 ) // no page insertion for less than 10 pages
572 			nPgCount = 0;
573 		sal_uLong nNdCount = pDoc->GetDocStat().nPara;
574 		if ( nNdCount <= 1 )
575 		{
576             //Estimates the number of paragraphs.
577 			sal_uLong nTmp = pDoc->GetNodes().GetEndOfContent().GetIndex() -
578 						pDoc->GetNodes().GetEndOfExtras().GetIndex();
579             //Tables have a little overhead..
580 			nTmp -= pDoc->GetTblFrmFmts()->Count() * 25;
581             //Fly frames, too ..
582 			nTmp -= (pDoc->GetNodes().GetEndOfAutotext().GetIndex() -
583 					   pDoc->GetNodes().GetEndOfInserts().GetIndex()) / 3 * 5;
584 			if ( nTmp > 0 )
585 				nNdCount = nTmp;
586 		}
587         if ( nNdCount > 100 ) // no estimation below this value
588 		{
589 			if ( nPgCount > 0 )
590 				nMaxParaPerPage = nNdCount / nPgCount;
591 			else
592 			{
593 				nMaxParaPerPage = Max( sal_uLong(20),
594 									   sal_uLong(20 + nNdCount / 1000 * 3) );
595 #ifdef PM2
596 				const sal_uLong nMax = 49;
597 #else
598 				const sal_uLong nMax = 53;
599 #endif
600 				nMaxParaPerPage = Min( nMaxParaPerPage, nMax );
601 				nPgCount = nNdCount / nMaxParaPerPage;
602 			}
603             if ( nNdCount < 1000 )
604                 nPgCount = 0;// no progress bar for small documents
605             ViewShell *pSh = 0;
606             if( rpLay && rpLay->getRootFrm() )
607                 pSh = rpLay->getRootFrm()->GetCurrShell();
608             if( pSh && pSh->GetViewOptions()->getBrowseMode() )
609 				nMaxParaPerPage *= 6;
610 		}
611     }
612     return nPgCount;
613 }
614 
615 /*-----------------23.5.2001 16:44------------------
616  * SwLayHelper::CheckInsertPage()
617  * inserts a page and return sal_True, if
618  * - the break after flag is set
619  * - the actual content wants a break before
620  * - the maximum count of paragraph/rows is reached
621  *
622  * The break after flag is set, if the actual content
623  * wants a break after.
624  * --------------------------------------------------*/
625 
626 sal_Bool SwLayHelper::CheckInsertPage()
627 {
628 	sal_Bool bEnd = 0 == rpPage->GetNext();
629     const SwAttrSet* pAttr = rpFrm->GetAttrSet();
630 	const SvxFmtBreakItem& rBrk = pAttr->GetBreak();
631 	const SwFmtPageDesc& rDesc = pAttr->GetPageDesc();
632     // --> FME 2004-10-26 #118195# Do not evaluate page description if frame
633     // is a follow frame!
634     const SwPageDesc* pDesc = rpFrm->IsFlowFrm() &&
635                               SwFlowFrm::CastFlowFrm( rpFrm )->IsFollow() ?
636                               0 :
637                               rDesc.GetPageDesc();
638     // <--
639 
640 	sal_Bool bBrk = nParagraphCnt > nMaxParaPerPage || rbBreakAfter;
641 	rbBreakAfter = rBrk.GetBreak() == SVX_BREAK_PAGE_AFTER ||
642 				   rBrk.GetBreak() == SVX_BREAK_PAGE_BOTH;
643 	if ( !bBrk )
644 		bBrk = rBrk.GetBreak() == SVX_BREAK_PAGE_BEFORE ||
645 			   rBrk.GetBreak() == SVX_BREAK_PAGE_BOTH;
646 
647 	if ( bBrk || pDesc )
648 	{
649 		sal_uInt16 nPgNum = 0;
650 		if ( !pDesc )
651 			pDesc = rpPage->GetPageDesc()->GetFollow();
652 		else
653 		{
654 			if ( 0 != (nPgNum = rDesc.GetNumOffset()) )
655 				((SwRootFrm*)rpPage->GetUpper())->SetVirtPageNum(sal_True);
656 		}
657 		sal_Bool bNextPageOdd = !rpPage->OnRightPage();
658 		sal_Bool bInsertEmpty = sal_False;
659 		if( nPgNum && bNextPageOdd != ( ( nPgNum % 2 ) != 0 ) )
660 		{
661 			bNextPageOdd = !bNextPageOdd;
662 			bInsertEmpty = sal_True;
663 		}
664 		::InsertNewPage( (SwPageDesc&)*pDesc, rpPage->GetUpper(),
665 						 bNextPageOdd, bInsertEmpty, sal_False, rpPage->GetNext() );
666 		if ( bEnd )
667 		{
668 			ASSERT( rpPage->GetNext(), "Keine neue Seite?" );
669 			do
670 			{	rpPage = (SwPageFrm*)rpPage->GetNext();
671 			} while ( rpPage->GetNext() );
672 		}
673 		else
674 		{
675 			ASSERT( rpPage->GetNext(), "Keine neue Seite?" );
676 			rpPage = (SwPageFrm*)rpPage->GetNext();
677 			if ( rpPage->IsEmptyPage() )
678 			{
679 				ASSERT( rpPage->GetNext(), "Keine neue Seite?" );
680 				rpPage = (SwPageFrm*)rpPage->GetNext();
681 			}
682 		}
683 		rpLay = rpPage->FindBodyCont();
684 		while( rpLay->Lower() )
685 			rpLay = (SwLayoutFrm*)rpLay->Lower();
686 		return sal_True;
687 	}
688 	return sal_False;
689 }
690 
691 // --> OD 2006-03-22 #b6375613#
692 bool lcl_HasTextFrmAnchoredObjs( SwTxtFrm* p_pTxtFrm )
693 {
694     bool bHasTextFrmAnchoredObjs( false );
695 
696     const SwSpzFrmFmts* pSpzFrmFmts = p_pTxtFrm->GetTxtNode()->GetDoc()->GetSpzFrmFmts();
697     for ( sal_uInt16 i = 0; i < pSpzFrmFmts->Count(); ++i )
698     {
699         SwFrmFmt *pFmt = (SwFrmFmt*)(*pSpzFrmFmts)[i];
700         const SwFmtAnchor &rAnch = pFmt->GetAnchor();
701         if ( rAnch.GetCntntAnchor() &&
702              ((rAnch.GetAnchorId() == FLY_AT_PARA) ||
703               (rAnch.GetAnchorId() == FLY_AT_CHAR)) &&
704              rAnch.GetCntntAnchor()->nNode.GetIndex() ==
705                                         p_pTxtFrm->GetTxtNode()->GetIndex() )
706         {
707             bHasTextFrmAnchoredObjs = true;
708             break;
709         }
710     }
711 
712     return bHasTextFrmAnchoredObjs;
713 }
714 
715 void lcl_ApplyWorkaroundForB6375613( SwFrm* p_pFirstFrmOnNewPage )
716 {
717     SwTxtFrm* pFirstTextFrmOnNewPage = dynamic_cast<SwTxtFrm*>(p_pFirstFrmOnNewPage);
718     //
719     if ( pFirstTextFrmOnNewPage &&
720          !pFirstTextFrmOnNewPage->IsFollow() &&
721          pFirstTextFrmOnNewPage->GetTxt().Len() == 0 &&
722          lcl_HasTextFrmAnchoredObjs( pFirstTextFrmOnNewPage ) )
723     {
724         // apply page break before at this text frame to assure, that it doesn't flow backward.
725         const SvxBreak eBreak =
726                     pFirstTextFrmOnNewPage->GetAttrSet()->GetBreak().GetBreak();
727         if ( eBreak == SVX_BREAK_NONE )
728         {
729             pFirstTextFrmOnNewPage->GetTxtNode()->LockModify();
730             SwDoc* pDoc( pFirstTextFrmOnNewPage->GetTxtNode()->GetDoc() );
731             IDocumentContentOperations* pIDCO = pFirstTextFrmOnNewPage->GetTxtNode()->getIDocumentContentOperations();
732             const SwPaM aTmpPaM( *(pFirstTextFrmOnNewPage->GetTxtNode()) );
733             pIDCO->InsertPoolItem( aTmpPaM,
734                 SvxFmtBreakItem( SVX_BREAK_PAGE_BEFORE, RES_BREAK ), 0 );
735             pFirstTextFrmOnNewPage->GetTxtNode()->UnlockModify();
736 
737             uno::Reference< document::XDocumentInfoSupplier > xDoc(
738                                         pDoc->GetDocShell()->GetBaseModel(),
739                                         uno::UNO_QUERY);
740             uno::Reference< beans::XPropertySet > xDocInfo(
741                                         xDoc->getDocumentInfo(),
742                                         uno::UNO_QUERY );
743             try
744             {
745                 xDocInfo->setPropertyValue( rtl::OUString::createFromAscii("WorkaroundForB6375613Applied"), uno::makeAny( true ) );
746             }
747             catch( uno::Exception& )
748             {
749             }
750         }
751     }
752 }
753 // <--
754 
755 /*-----------------28.5.2001 11:31------------------
756  * SwLayHelper::CheckInsert
757  *  is the entry point for the _InsertCnt-function.
758  *  The document content index is checked either it is
759  *  in the layout cache either it's time to insert a page
760  *  cause the maximal estimation of content per page is reached.
761  *  A really big table or long paragraph may contains more than
762  *  one page, in this case the needed count of pages will inserted.
763  * --------------------------------------------------*/
764 
765 sal_Bool SwLayHelper::CheckInsert( sal_uLong nNodeIndex )
766 {
767     sal_Bool bRet = sal_False;
768     sal_Bool bLongTab = sal_False;
769     sal_uLong nMaxRowPerPage( 0 );
770     nNodeIndex -= nStartOfContent;
771     sal_uInt16 nRows( 0 );
772     if( rpFrm->IsTabFrm() )
773     {
774         //Inside a table counts every row as a paragraph
775         SwFrm *pLow = ((SwTabFrm*)rpFrm)->Lower();
776         nRows = 0;
777         do
778         {
779             ++nRows;
780             pLow = pLow->GetNext();
781         } while ( pLow );
782         nParagraphCnt += nRows;
783         if( !pImpl && nParagraphCnt > nMaxParaPerPage + 10 )
784         {
785             // OD 09.04.2003 #108698# - improve heuristics:
786             // Assume that a table, which has more than three times the quantity
787             // of maximal paragraphs per page rows, consists of rows, which have
788             // the height of a normal paragraph. Thus, allow as much rows per page
789             // as much paragraphs are allowed.
790             if ( nRows > ( 3*nMaxParaPerPage ) )
791             {
792                 nMaxRowPerPage = nMaxParaPerPage;
793             }
794             else
795             {
796                 SwFrm *pTmp = ((SwTabFrm*)rpFrm)->Lower();
797                 if( pTmp->GetNext() )
798                     pTmp = pTmp->GetNext();
799                 pTmp = ((SwRowFrm*)pTmp)->Lower();
800                 sal_uInt16 nCnt = 0;
801                 do
802                 {
803                     ++nCnt;
804                     pTmp = pTmp->GetNext();
805                 } while( pTmp );
806                 nMaxRowPerPage = Max( sal_uLong(2), nMaxParaPerPage / nCnt );
807             }
808             bLongTab = sal_True;
809         }
810     }
811     else
812         ++nParagraphCnt;
813     if( bFirst && pImpl && nIndex < pImpl->Count() &&
814         pImpl->GetBreakIndex( nIndex ) == nNodeIndex &&
815         ( pImpl->GetBreakOfst( nIndex ) < STRING_LEN ||
816           ( ++nIndex < pImpl->Count() &&
817           pImpl->GetBreakIndex( nIndex ) == nNodeIndex ) ) )
818         bFirst = sal_False;
819 #if OSL_DEBUG_LEVEL > 1
820     sal_uLong nBreakIndex = ( pImpl && nIndex < pImpl->Count() ) ?
821                         pImpl->GetBreakIndex(nIndex) : 0xffff;
822     (void)nBreakIndex;
823 #endif
824     // OD 09.04.2003 #108698# - always split a big tables.
825     if ( !bFirst ||
826          ( rpFrm->IsTabFrm() && bLongTab )
827        )
828     {
829         sal_uLong nRowCount = 0;
830         do
831         {
832             if( pImpl || bLongTab )
833             {
834 #if OSL_DEBUG_LEVEL > 1
835                 sal_uLong nBrkIndex = ( pImpl && nIndex < pImpl->Count() ) ?
836                         pImpl->GetBreakIndex(nIndex) : 0xffff;
837                 (void)nBrkIndex;
838 #endif
839                 xub_StrLen nOfst = STRING_LEN;
840                 sal_uInt16 nType = SW_LAYCACHE_IO_REC_PAGES;
841                 if( bLongTab )
842                 {
843                     rbBreakAfter = sal_True;
844                     nOfst = static_cast<xub_StrLen>(nRowCount + nMaxRowPerPage);
845                 }
846                 else
847                 {
848                     while( nIndex < pImpl->Count() &&
849                            pImpl->GetBreakIndex(nIndex) < nNodeIndex)
850                         ++nIndex;
851                     if( nIndex < pImpl->Count() &&
852                         pImpl->GetBreakIndex(nIndex) == nNodeIndex )
853                     {
854                         nType = pImpl->GetBreakType( nIndex );
855                         nOfst = pImpl->GetBreakOfst( nIndex++ );
856                         rbBreakAfter = sal_True;
857                     }
858                 }
859 
860                 if( nOfst < STRING_LEN )
861                 {
862                     sal_Bool bSplit = sal_False;
863                     sal_uInt16 nRepeat( 0 );
864                     if( !bLongTab && rpFrm->IsTxtFrm() &&
865                         SW_LAYCACHE_IO_REC_PARA == nType &&
866                         nOfst<((SwTxtFrm*)rpFrm)->GetTxtNode()->GetTxt().Len() )
867                         bSplit = sal_True;
868                     else if( rpFrm->IsTabFrm() && nRowCount < nOfst &&
869                              ( bLongTab || SW_LAYCACHE_IO_REC_TABLE == nType ) )
870                     {
871                         nRepeat = ((SwTabFrm*)rpFrm)->
872                                   GetTable()->GetRowsToRepeat();
873                         bSplit = nOfst < nRows && nRowCount + nRepeat < nOfst;
874                         bLongTab = bLongTab && bSplit;
875                     }
876                     if( bSplit )
877                     {
878                         rpFrm->InsertBehind( rpLay, rpPrv );
879                         rpFrm->Frm().Pos() = rpLay->Frm().Pos();
880                         rpFrm->Frm().Pos().Y() += 1;
881                         rpPrv = rpFrm;
882                         if( rpFrm->IsTabFrm() )
883                         {
884                             SwTabFrm* pTab = (SwTabFrm*)rpFrm;
885                             // --> OD 2004-09-23 #i33629#, #i29955#
886                             ::RegistFlys( pTab->FindPageFrm(), pTab );
887                             // <--
888                             SwFrm *pRow = pTab->Lower();
889                             SwTabFrm *pFoll = new SwTabFrm( *pTab );
890 
891                             SwFrm *pPrv;
892                             if( nRepeat > 0 )
893                             {
894                                 bDontCreateObjects = sal_True; //frmtool
895 
896                                 // Insert new headlines:
897                                 sal_uInt16 nRowIdx = 0;
898                                 SwRowFrm* pHeadline = 0;
899                                 while( nRowIdx < nRepeat )
900                                 {
901                                     ASSERT( pTab->GetTable()->GetTabLines()[ nRowIdx ], "Table ohne Zeilen?" );
902                                     pHeadline =
903                                         new SwRowFrm( *pTab->GetTable()->GetTabLines()[ nRowIdx ], pTab );
904                                     pHeadline->SetRepeatedHeadline( true );
905                                     pHeadline->InsertBefore( pFoll, 0 );
906                                     pHeadline->RegistFlys();
907 
908                                     ++nRowIdx;
909                                 }
910 
911                                 bDontCreateObjects = sal_False;
912                                 pPrv = pHeadline;
913                                 nRows = nRows + nRepeat;
914                             }
915                             else
916                                 pPrv = 0;
917                             while( pRow && nRowCount < nOfst )
918                             {
919                                 pRow = pRow->GetNext();
920                                 ++nRowCount;
921                             }
922                             while ( pRow )
923                             {
924                                 SwFrm* pNxt = pRow->GetNext();
925                                 pRow->Remove();
926                                 pRow->InsertBehind( pFoll, pPrv );
927                                 pPrv = pRow;
928                                 pRow = pNxt;
929                             }
930                             rpFrm = pFoll;
931                         }
932                         else
933                         {
934                             SwTxtFrm *pNew = new SwTxtFrm( ((SwTxtFrm*)rpFrm)->
935                                                             GetTxtNode(), rpFrm );
936                             pNew->_SetIsFollow( sal_True );
937                             pNew->ManipOfst( nOfst );
938                             pNew->SetFollow( ((SwTxtFrm*)rpFrm)->GetFollow() );
939                             ((SwTxtFrm*)rpFrm)->SetFollow( pNew );
940                             rpFrm = pNew;
941                         }
942                     }
943                 }
944             }
945 
946             SwPageFrm* pLastPage = rpPage;
947             if( CheckInsertPage() )
948             {
949                 // --> OD 2006-03-21 #b6375613#
950                 if ( pDoc->ApplyWorkaroundForB6375613() )
951                 {
952                     lcl_ApplyWorkaroundForB6375613( rpFrm );
953                 }
954                 // <--
955                 _CheckFlyCache( pLastPage );
956                 if( rpPrv && rpPrv->IsTxtFrm() && !rpPrv->GetValidSizeFlag() )
957                     rpPrv->Frm().Height( rpPrv->GetUpper()->Prt().Height() );
958 
959                 bRet = sal_True;
960                 rpPrv = 0;
961                 nParagraphCnt = 0;
962 
963                 if ( rpActualSection )
964                 {
965                     //Hatte der SectionFrm ueberhaupt Inhalt? Wenn
966                     //nicht kann er gleich umgehaengt werden.
967                     SwSectionFrm *pSct;
968                     bool bInit = false;
969                     if ( !rpActualSection->GetSectionFrm()->ContainsCntnt())
970                     {
971                         pSct = rpActualSection->GetSectionFrm();
972                         pSct->Remove();
973                     }
974                     else
975                     {
976                         pSct = new SwSectionFrm(
977                             *rpActualSection->GetSectionFrm(), sal_False );
978                         rpActualSection->GetSectionFrm()->SimpleFormat();
979                         bInit = true;
980                     }
981                     rpActualSection->SetSectionFrm( pSct );
982                     pSct->InsertBehind( rpLay, 0 );
983                     if( bInit )
984                         pSct->Init();
985                     pSct->Frm().Pos() = rpLay->Frm().Pos();
986                     pSct->Frm().Pos().Y() += 1; //wg. Benachrichtigungen.
987 
988                     rpLay = pSct;
989                     if ( rpLay->Lower() && rpLay->Lower()->IsLayoutFrm() )
990                         rpLay = rpLay->GetNextLayoutLeaf();
991                 }
992             }
993         } while( bLongTab || ( pImpl && nIndex < pImpl->Count() &&
994                  (*pImpl)[ nIndex ] == nNodeIndex ) );
995     }
996     bFirst = sal_False;
997     return bRet;
998 }
999 
1000 struct SdrObjectCompare
1001 {
1002   bool operator()( const SdrObject* pF1, const SdrObject* pF2 ) const
1003   {
1004     return pF1->GetOrdNum() < pF2->GetOrdNum();
1005   }
1006 };
1007 
1008 struct FlyCacheCompare
1009 {
1010   bool operator()( const SwFlyCache* pC1, const SwFlyCache* pC2 ) const
1011   {
1012     return pC1->nOrdNum < pC2->nOrdNum;
1013   }
1014 };
1015 
1016  /*-----------------28.6.2001 14:40------------------
1017   * SwLayHelper::_CheckFlyCache(..)
1018   * If a new page is inserted, the last page is analysed.
1019   * If there are text frames with default position, the fly cache
1020   * is checked, if these frames are stored in the cache.
1021   * --------------------------------------------------*/
1022 
1023 void SwLayHelper::_CheckFlyCache( SwPageFrm* pPage )
1024 {
1025     if( !pImpl || !pPage )
1026         return;
1027     sal_uInt16 nFlyCount = pImpl->GetFlyCount();
1028     // Any text frames at the page, fly cache avaiable?
1029     if( pPage->GetSortedObjs() && nFlyIdx < nFlyCount )
1030     {
1031         SwSortedObjs &rObjs = *pPage->GetSortedObjs();
1032         sal_uInt16 nPgNum = pPage->GetPhyPageNum();
1033 
1034 /*
1035 
1036         //
1037         // NOTE: This code assumes that all objects have already been
1038         // inserted into the drawing layout, so that the cached objects
1039         // can be identified by their ordnum. Unfortunately this function
1040         // is called with page n if page n+1 has been inserted. Thus
1041         // not all the objects have been inserted and the ordnums cannot
1042         // be used to identify the objects.
1043         //
1044 
1045         for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )  // check objects
1046         {
1047             SdrObject *pO = rObjs[i];
1048             if ( pO->ISA(SwVirtFlyDrawObj) )  // a text frame?
1049             {
1050                 SwFlyFrm *pFly = ((SwVirtFlyDrawObj*)pO)->GetFlyFrm();
1051                 if( pFly->Frm().Left() == WEIT_WECH && pFly->GetAnchor() &&
1052                     !pFly->GetAnchor()->FindFooterOrHeader() )
1053                 {   // Only frame with default position and not in header/footer
1054                     const SwContact *pC = (SwContact*)GetUserCall(pO);
1055                     if( pC )
1056                     {
1057                         sal_uLong nOrdNum = pO->GetOrdNum(); // the Id
1058                         SwFlyCache* pFlyC;
1059                         while( nFlyIdx < nFlyCount && ( pFlyC = pImpl->
1060                                GetFlyCache(nFlyIdx) )->nPageNum < nPgNum)
1061                             ++nFlyIdx;
1062                         if( nFlyIdx < nFlyCount &&
1063                             pFlyC->nPageNum == nPgNum )
1064                         {
1065                             sal_uInt16 nIdx = nFlyIdx;
1066                             while( nIdx < nFlyCount && ( pFlyC = pImpl->
1067                                    GetFlyCache( nIdx ) )->nPageNum == nPgNum &&
1068                                    pFlyC->nOrdNum != nOrdNum )
1069                                 ++nIdx;
1070                             if( nIdx < nFlyCount && pFlyC->nPageNum == nPgNum &&
1071                                 pFlyC->nOrdNum == nOrdNum )
1072                             {   // we get the stored information
1073                                 pFly->Frm().Pos().X() = pFlyC->Left() +
1074                                                         pPage->Frm().Left();
1075                                 pFly->Frm().Pos().Y() = pFlyC->Top() +
1076                                                         pPage->Frm().Top();
1077                                 pFly->Frm().Width( pFlyC->Width() );
1078                                 pFly->Frm().Height( pFlyC->Height() );
1079                             }
1080                         }
1081                     }
1082                 }
1083             }
1084         }
1085  */
1086 
1087         //
1088         // NOTE: Here we do not use the absolute ordnums but
1089         // relative ordnums for the objects on this page.
1090 
1091         // skip fly frames from pages before the current page
1092         SwFlyCache* pFlyC;
1093         while( nFlyIdx < nFlyCount && ( pFlyC = pImpl->
1094                GetFlyCache(nFlyIdx) )->nPageNum < nPgNum)
1095             ++nFlyIdx;
1096 
1097         // sort cached objects on this page by ordnum
1098         std::set< const SwFlyCache*, FlyCacheCompare > aFlyCacheSet;
1099         sal_uInt16 nIdx = nFlyIdx;
1100 
1101         while( nIdx < nFlyCount && ( pFlyC = pImpl->
1102                GetFlyCache( nIdx ) )->nPageNum == nPgNum )
1103         {
1104             aFlyCacheSet.insert( pFlyC );
1105             ++nIdx;
1106         }
1107 
1108         // sort objects on this page by ordnum
1109         std::set< const SdrObject*, SdrObjectCompare > aFlySet;
1110         for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
1111         {
1112             SwAnchoredObject* pAnchoredObj = rObjs[i];
1113             if ( pAnchoredObj->ISA(SwFlyFrm) )  // a text frame?
1114             {
1115                 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
1116                 if( pFly->GetAnchorFrm() &&
1117                     !pFly->GetAnchorFrm()->FindFooterOrHeader() )
1118                 {
1119                     const SwContact *pC = ::GetUserCall( pAnchoredObj->GetDrawObj() );
1120                     if( pC )
1121                     {
1122                         aFlySet.insert( pAnchoredObj->GetDrawObj() );
1123                     }
1124                 }
1125             }
1126         }
1127 
1128         if ( aFlyCacheSet.size() == aFlySet.size() )
1129         {
1130             std::set< const SwFlyCache*, FlyCacheCompare >::iterator aFlyCacheSetIt =
1131                     aFlyCacheSet.begin();
1132             std::set< const SdrObject*, SdrObjectCompare >::iterator aFlySetIt =
1133                     aFlySet.begin();
1134 
1135             while ( aFlyCacheSetIt != aFlyCacheSet.end() )
1136             {
1137                 const SwFlyCache* pFlyCache = *aFlyCacheSetIt;
1138                 SwFlyFrm* pFly = ((SwVirtFlyDrawObj*)*aFlySetIt)->GetFlyFrm();
1139 
1140                 if ( pFly->Frm().Left() == WEIT_WECH )
1141                 {
1142                     // we get the stored information
1143                     pFly->Frm().Pos().X() = pFlyCache->Left() +
1144                                             pPage->Frm().Left();
1145                     pFly->Frm().Pos().Y() = pFlyCache->Top() +
1146                                             pPage->Frm().Top();
1147                     if ( pImpl->IsUseFlyCache() )
1148                     {
1149                         pFly->Frm().Width( pFlyCache->Width() );
1150                         pFly->Frm().Height( pFlyCache->Height() );
1151                     }
1152                 }
1153 
1154                 ++aFlyCacheSetIt;
1155                 ++aFlySetIt;
1156             }
1157         }
1158     }
1159 }
1160 
1161 /*-----------------28.6.2001 14:48------------------
1162  * SwLayHelper::CheckPageFlyCache(..)
1163  * looks for the given text frame in the fly cache and sets
1164  * the position and size, if possible.
1165  * The fly cache is sorted by pages and we start searching with the given page.
1166  * If we found the page number in the fly cache, we set
1167  * the rpPage parameter to the right page, if possible.
1168  * --------------------------------------------------*/
1169 
1170 sal_Bool SwLayHelper::CheckPageFlyCache( SwPageFrm* &rpPage, SwFlyFrm* pFly )
1171 {
1172     if( !pFly->GetAnchorFrm() || !pFly->GetVirtDrawObj() ||
1173         pFly->GetAnchorFrm()->FindFooterOrHeader() )
1174         return sal_False;
1175     sal_Bool bRet = sal_False;
1176     SwDoc* pDoc = rpPage->GetFmt()->GetDoc();
1177     SwLayCacheImpl *pCache = pDoc->GetLayoutCache() ?
1178                              pDoc->GetLayoutCache()->LockImpl() : NULL;
1179     if( pCache )
1180     {
1181         sal_uInt16 nPgNum = rpPage->GetPhyPageNum();
1182         sal_uInt16 nIdx = 0;
1183         sal_uInt16 nCnt = pCache->GetFlyCount();
1184         sal_uLong nOrdNum = pFly->GetVirtDrawObj()->GetOrdNum();
1185         SwFlyCache* pFlyC = 0;
1186 
1187         // skip fly frames from pages before the current page
1188         while( nIdx < nCnt &&
1189                nPgNum > (pFlyC = pCache->GetFlyCache( nIdx ))->nPageNum )
1190             ++nIdx;
1191 
1192         while( nIdx < nCnt &&
1193                nOrdNum != (pFlyC = pCache->GetFlyCache( nIdx ))->nOrdNum )
1194             ++nIdx;
1195         if( nIdx < nCnt )
1196         {
1197             SwPageFrm *pPage = rpPage;
1198             while( pPage && pPage->GetPhyPageNum() < pFlyC->nPageNum )
1199                 pPage = (SwPageFrm*)pPage->GetNext();
1200             // --> OD 2005-02-22 #i43266# - if the found page is an empty page,
1201             // take the previous one (take next one, if previous one doesn't exists)
1202             if ( pPage && pPage->IsEmptyPage() )
1203             {
1204                 pPage = static_cast<SwPageFrm*>( pPage->GetPrev()
1205                                                  ? pPage->GetPrev()
1206                                                  : pPage->GetNext() );
1207             }
1208             // <--
1209             if( pPage )
1210             {
1211                 rpPage = pPage;
1212                 pFly->Frm().Pos().X() = pFlyC->Left() + pPage->Frm().Left();
1213                 pFly->Frm().Pos().Y() = pFlyC->Top() + pPage->Frm().Top();
1214                 if ( pCache->IsUseFlyCache() )
1215                 {
1216                     pFly->Frm().Width( pFlyC->Width() );
1217                     pFly->Frm().Height( pFlyC->Height() );
1218                 }
1219                 bRet = sal_True;
1220             }
1221         }
1222         pDoc->GetLayoutCache()->UnlockImpl();
1223     }
1224     return bRet;
1225 }
1226 
1227 // -----------------------------------------------------------------------------
1228 
1229 SwLayCacheIoImpl::SwLayCacheIoImpl( SvStream& rStrm, sal_Bool bWrtMd ) :
1230 	pStream( &rStrm ),
1231 	nMajorVersion(SW_LAYCACHE_IO_VERSION_MAJOR),
1232 	nMinorVersion(SW_LAYCACHE_IO_VERSION_MINOR),
1233 	bWriteMode( bWrtMd ),
1234 	bError( sal_False  )
1235 {
1236 	if( bWriteMode )
1237 		*pStream << nMajorVersion
1238 				 <<	nMinorVersion;
1239 
1240 	else
1241 		*pStream >> nMajorVersion
1242 				 >>	nMinorVersion;
1243 }
1244 
1245 sal_Bool SwLayCacheIoImpl::OpenRec( sal_uInt8 cType )
1246 {
1247 	sal_Bool bRes = sal_True;
1248 	size_t nLvl = aRecTypes.size();
1249 	ASSERT( nLvl == aRecSizes.Count(), "OpenRec: Level" );
1250 	sal_uInt32 nPos = pStream->Tell();
1251 	if( bWriteMode )
1252 	{
1253 		aRecTypes.push_back( cType );
1254 		aRecSizes.Insert( nPos, nLvl );
1255 		*pStream << (sal_uInt32) 0;
1256 	}
1257 	else
1258 	{
1259 		sal_uInt32 nVal;
1260 		*pStream >> nVal;
1261 		sal_uInt8 cRecTyp = (sal_uInt8)nVal;
1262 		aRecTypes.push_back( cRecTyp );
1263 		sal_uInt32 nSize = nVal >> 8;
1264 		aRecSizes.Insert( nPos + nSize, nLvl );
1265 		if( !nVal || cRecTyp != cType ||
1266 			pStream->GetErrorCode() != SVSTREAM_OK || pStream->IsEof() )
1267 		{
1268 			ASSERT( nVal, "OpenRec: Record-Header is 0" );
1269 			ASSERT( cRecTyp == cType,
1270 					"OpenRec: Wrong Record Type" );
1271 			aRecTypes.back() = 0;
1272 			aRecSizes[nLvl] = pStream->Tell();
1273 			bRes = sal_False;
1274 			bError = sal_True;
1275 		}
1276 	}
1277 	return bRes;
1278 }
1279 
1280 // Close record
1281 
1282 sal_Bool SwLayCacheIoImpl::CloseRec( sal_uInt8 )
1283 {
1284 	sal_Bool bRes = sal_True;
1285 	size_t nLvl = aRecTypes.size();
1286 	ASSERT( nLvl == aRecSizes.Count(), "CloseRec: wrong Level" );
1287 	ASSERT( nLvl, "CloseRec: no levels" );
1288 	if( nLvl )
1289 	{
1290 		nLvl--;
1291 		sal_uInt32 nPos = pStream->Tell();
1292 		if( bWriteMode )
1293 		{
1294 			sal_uInt32 nBgn = aRecSizes[nLvl];
1295 			pStream->Seek( nBgn );
1296 			sal_uInt32 nSize = nPos - nBgn;
1297 			sal_uInt32 nVal = ( nSize << 8 ) | aRecTypes.back();
1298 			*pStream << nVal;
1299 			pStream->Seek( nPos );
1300 			if( pStream->GetError() != SVSTREAM_OK )
1301 			 	bRes = sal_False;
1302 		}
1303 		else
1304 		{
1305 			sal_uInt32 n = aRecSizes[nLvl];
1306 			ASSERT( n >= nPos, "CloseRec: to much data read" );
1307 			if( n != nPos )
1308 			{
1309 				pStream->Seek( n );
1310 				if( n < nPos )
1311 				 	bRes = sal_False;
1312 			}
1313 			if( pStream->GetErrorCode() != SVSTREAM_OK )
1314 				bRes = sal_False;
1315 		}
1316 
1317 		aRecTypes.pop_back();
1318 		aRecSizes.Remove( nLvl, 1 );
1319 	}
1320 
1321 	if( !bRes )
1322 		bError = sal_True;
1323 
1324 	return bRes;
1325 }
1326 
1327 sal_uInt32 SwLayCacheIoImpl::BytesLeft()
1328 {
1329 	sal_uInt16 nLvl = aRecSizes.Count();
1330 	sal_uInt32 n = 0;
1331 	if( !bError && nLvl )
1332 	{
1333 		sal_uInt32 nEndPos = aRecSizes[ nLvl-1 ];
1334 		sal_uInt32 nPos = pStream->Tell();
1335 		if( nEndPos > nPos )
1336 			n = nEndPos - nPos;
1337 	}
1338 
1339 	return n;
1340 }
1341 
1342 sal_uInt8 SwLayCacheIoImpl::Peek()
1343 {
1344 	sal_uInt8 c = 0;
1345 	if( !bError )
1346 	{
1347 		sal_uInt32 nPos = pStream->Tell();
1348 		*pStream >> c;
1349 		pStream->Seek( nPos );
1350 		if( pStream->GetErrorCode() != SVSTREAM_OK )
1351 		{
1352 			c = 0;
1353 			bError = sal_True;
1354 		}
1355 	}
1356 	return c;
1357 }
1358 
1359 void SwLayCacheIoImpl::SkipRec()
1360 {
1361 	sal_uInt8 c = Peek();
1362 	OpenRec( c );
1363 	pStream->Seek( aRecSizes[aRecSizes.Count()-1] );
1364 	CloseRec( c );
1365 }
1366 
1367 sal_uInt8 SwLayCacheIoImpl::OpenFlagRec()
1368 {
1369 	ASSERT( !bWriteMode, "OpenFlagRec illegal in write  mode" );
1370 	sal_uInt8 cFlags;
1371 	*pStream >> cFlags;
1372 	nFlagRecEnd = pStream->Tell() + ( cFlags & 0x0F );
1373 	return (cFlags >> 4);
1374 }
1375 
1376 void SwLayCacheIoImpl::OpenFlagRec( sal_uInt8 nFlags, sal_uInt8 nLen )
1377 {
1378 	ASSERT( bWriteMode, "OpenFlagRec illegal in read  mode" );
1379 	ASSERT( (nFlags & 0xF0) == 0, "illegal flags set" );
1380 	ASSERT( nLen < 16, "wrong flag record length" );
1381 	sal_uInt8 cFlags = (nFlags << 4) + nLen;
1382 	*pStream << cFlags;
1383 	nFlagRecEnd = pStream->Tell() + nLen;
1384 }
1385 
1386 void SwLayCacheIoImpl::CloseFlagRec()
1387 {
1388 	if( bWriteMode )
1389 	{
1390 		ASSERT( pStream->Tell() == nFlagRecEnd, "Wrong amount of data written" );
1391 	}
1392 	else
1393 	{
1394 		ASSERT( pStream->Tell() <= nFlagRecEnd, "To many data read" );
1395 		if( pStream->Tell() != nFlagRecEnd )
1396 			pStream->Seek( nFlagRecEnd );
1397 	}
1398 }
1399