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