1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
21 #include <editeng/formatbreakitem.hxx>
22 #include <tools/stream.hxx>
24 #include <docstat.hxx>
26 #include <fmtpdsc.hxx>
27 #include <laycache.hxx>
28 #include <layhelp.hxx>
29 #include <pagefrm.hxx>
30 #include <rootfrm.hxx>
33 #include <swtable.hxx>
37 #include <bodyfrm.hxx>
38 #include <ndindex.hxx>
39 #include <sectfrm.hxx>
41 #include <fmtcntnt.hxx>
42 #include <pagedesc.hxx>
43 #include <frmtool.hxx>
44 #include <dflyobj.hxx>
45 #include <dcontact.hxx>
46 #include "viewopt.hxx"
49 // OD 2004-05-24 #i28701#
50 #include <sortedobjs.hxx>
54 #include <poolfmt.hxx>
59 using namespace ::com::sun::star
;
62 * Reading and writing of the layout cache.
63 * The layout cache is not necessary, but it improves
64 * the performance and reduces the text flow during
66 * The layout cache contains the index of the paragraphs/tables
67 * at the top of every page, so it's possible to create
68 * the right count of pages and to distribute the document content
69 * to this pages before the formatting starts.
72 void SwLayoutCache::Read( SvStream
&rStream
)
76 pImpl
= new SwLayCacheImpl
;
77 if( !pImpl
->Read( rStream
) )
85 //-----------------------------------------------------------------------------
87 void SwLayCacheImpl::Insert( sal_uInt16 nType
, sal_uLong nIndex
, xub_StrLen nOffset
)
89 aType
.push_back( nType
);
90 std::vector
<sal_uLong
>::push_back( nIndex
);
91 aOffset
.push_back( nOffset
);
94 bool SwLayCacheImpl::Read( SvStream
& rStream
)
96 SwLayCacheIoImpl
aIo( rStream
, false );
97 if( aIo
.GetMajorVersion() > SW_LAYCACHE_IO_VERSION_MAJOR
)
100 // Due to an evil bug in the layout cache (#102759#), we cannot trust the
101 // sizes of fly frames which have been written using the "old" layout cache.
102 // This flag should indicate that we do not want to trust the width and
103 // height of fly frames
104 bUseFlyCache
= aIo
.GetMinorVersion() >= 1;
106 aIo
.OpenRec( SW_LAYCACHE_IO_REC_PAGES
);
109 while( aIo
.BytesLeft() && !aIo
.HasError() )
111 sal_uInt32
nIndex(0), nOffset(0);
115 case SW_LAYCACHE_IO_REC_PARA
:
117 aIo
.OpenRec( SW_LAYCACHE_IO_REC_PARA
);
118 sal_uInt8 cFlags
= aIo
.OpenFlagRec();
119 aIo
.GetStream() >> nIndex
;
120 if( (cFlags
& 0x01) != 0 )
121 aIo
.GetStream() >> nOffset
;
123 nOffset
= STRING_LEN
;
125 Insert( SW_LAYCACHE_IO_REC_PARA
, nIndex
, (xub_StrLen
)nOffset
);
126 aIo
.CloseRec( SW_LAYCACHE_IO_REC_PARA
);
129 case SW_LAYCACHE_IO_REC_TABLE
:
130 aIo
.OpenRec( SW_LAYCACHE_IO_REC_TABLE
);
132 aIo
.GetStream() >> nIndex
134 Insert( SW_LAYCACHE_IO_REC_TABLE
, nIndex
, (xub_StrLen
)nOffset
);
136 aIo
.CloseRec( SW_LAYCACHE_IO_REC_TABLE
);
138 case SW_LAYCACHE_IO_REC_FLY
:
140 aIo
.OpenRec( SW_LAYCACHE_IO_REC_FLY
);
143 sal_Int32
nX(0), nY(0), nW(0), nH(0);
144 sal_uInt16
nPgNum(0);
145 aIo
.GetStream() >> nPgNum
>> nIndex
146 >> nX
>> nY
>> nW
>> nH
;
147 SwFlyCache
* pFly
= new SwFlyCache( nPgNum
, nIndex
, nX
, nY
, nW
, nH
);
148 aFlyCache
.push_back( pFly
);
149 aIo
.CloseRec( SW_LAYCACHE_IO_REC_FLY
);
157 aIo
.CloseRec( SW_LAYCACHE_IO_REC_PAGES
);
159 return !aIo
.HasError();
163 * SwLayoutCache::Write(..)
164 * writes the index (more precise: the difference between
165 * the index and the first index of the document content)
166 * of the first paragraph/table at the top of every page.
167 * If at the top of a page is the rest of a paragraph/table
168 * from the bottom of the previous page, the character/row
169 * number is stored, too.
170 * The position, size and page number of the text frames
174 void SwLayoutCache::Write( SvStream
&rStream
, const SwDoc
& rDoc
)
176 if( rDoc
.GetCurrentLayout() ) // the layout itself .. //swmod 080218
178 SwLayCacheIoImpl
aIo( rStream
, true );
179 // We want to save the relative index, so we need the index
180 // of the first content
181 sal_uLong nStartOfContent
= rDoc
.GetNodes().GetEndOfContent().
182 StartOfSectionNode()->GetIndex();
184 SwPageFrm
* pPage
= (SwPageFrm
*)rDoc
.GetCurrentLayout()->Lower(); //swmod 080218
186 aIo
.OpenRec( SW_LAYCACHE_IO_REC_PAGES
);
187 aIo
.OpenFlagRec( 0, 0 );
191 if( pPage
->GetPrev() )
193 SwLayoutFrm
* pLay
= pPage
->FindBodyCont();
194 SwFrm
* pTmp
= pLay
? pLay
->ContainsAny() : NULL
;
195 // We are only interested in paragraph or table frames,
196 // a section frames contains paragraphs/tables.
197 if( pTmp
&& pTmp
->IsSctFrm() )
198 pTmp
= ((SwSectionFrm
*)pTmp
)->ContainsAny();
200 if( pTmp
) // any content
202 if( pTmp
->IsTxtFrm() )
204 sal_uLong nNdIdx
= ((SwTxtFrm
*)pTmp
)->GetNode()->GetIndex();
205 if( nNdIdx
> nStartOfContent
)
207 /* Open Paragraph Record */
208 aIo
.OpenRec( SW_LAYCACHE_IO_REC_PARA
);
209 sal_Bool bFollow
= ((SwTxtFrm
*)pTmp
)->IsFollow();
210 aIo
.OpenFlagRec( bFollow
? 0x01 : 0x00,
212 nNdIdx
-= nStartOfContent
;
213 aIo
.GetStream() << static_cast<sal_uInt32
>(nNdIdx
);
215 aIo
.GetStream() << static_cast<sal_uInt32
>(((SwTxtFrm
*)pTmp
)->GetOfst());
217 /* Close Paragraph Record */
218 aIo
.CloseRec( SW_LAYCACHE_IO_REC_PARA
);
221 else if( pTmp
->IsTabFrm() )
223 SwTabFrm
* pTab
= (SwTabFrm
*)pTmp
;
224 sal_uLong nOfst
= STRING_LEN
;
225 if( pTab
->IsFollow() )
227 // If the table is a follow, we have to look for the
228 // master and to count all rows to get the row number
230 if( pTab
->IsFollow() )
231 pTab
= pTab
->FindMaster( true );
232 while( pTab
!= pTmp
)
234 SwFrm
* pSub
= pTab
->Lower();
238 pSub
= pSub
->GetNext();
240 pTab
= pTab
->GetFollow();
241 OSL_ENSURE( pTab
, "Table follow without master" );
247 pTab
->GetTable()->GetTableNode()->GetIndex();
248 if( nNdIdx
> nStartOfContent
)
250 /* Open Table Record */
251 aIo
.OpenRec( SW_LAYCACHE_IO_REC_TABLE
);
252 aIo
.OpenFlagRec( 0, 8 );
253 nNdIdx
-= nStartOfContent
;
254 aIo
.GetStream() << static_cast<sal_uInt32
>(nNdIdx
)
255 << static_cast<sal_uInt32
>(nOfst
);
257 /* Close Table Record */
258 aIo
.CloseRec( SW_LAYCACHE_IO_REC_TABLE
);
260 // If the table has a follow on the next page,
261 // we know already the row number and store this
263 if( pTab
->GetFollow() )
265 if( nOfst
== STRING_LEN
)
269 SwFrm
* pSub
= pTab
->Lower();
273 pSub
= pSub
->GetNext();
275 pTab
= pTab
->GetFollow();
276 SwPageFrm
*pTabPage
= pTab
->FindPageFrm();
277 if( pTabPage
!= pPage
)
279 OSL_ENSURE( pPage
->GetPhyPageNum() <
280 pTabPage
->GetPhyPageNum(),
281 "Looping Tableframes" );
285 } while ( pTab
->GetFollow() );
293 if( pPage
->GetSortedObjs() )
295 SwSortedObjs
&rObjs
= *pPage
->GetSortedObjs();
296 for ( sal_uInt16 i
= 0; i
< rObjs
.Count(); ++i
)
298 SwAnchoredObject
* pAnchoredObj
= rObjs
[i
];
299 if ( pAnchoredObj
->ISA(SwFlyFrm
) )
301 SwFlyFrm
*pFly
= static_cast<SwFlyFrm
*>(pAnchoredObj
);
302 if( pFly
->Frm().Left() != FAR_AWAY
&&
303 !pFly
->GetAnchorFrm()->FindFooterOrHeader() )
305 const SwContact
*pC
=
306 ::GetUserCall(pAnchoredObj
->GetDrawObj());
309 sal_uInt32 nOrdNum
= pAnchoredObj
->GetDrawObj()->GetOrdNum();
310 sal_uInt16 nPageNum
= pPage
->GetPhyPageNum();
311 /* Open Fly Record */
312 aIo
.OpenRec( SW_LAYCACHE_IO_REC_FLY
);
313 aIo
.OpenFlagRec( 0, 0 );
315 SwRect
&rRct
= pFly
->Frm();
316 sal_Int32 nX
= rRct
.Left() - pPage
->Frm().Left();
317 sal_Int32 nY
= rRct
.Top() - pPage
->Frm().Top();
318 aIo
.GetStream() << nPageNum
<< nOrdNum
320 << static_cast<sal_Int32
>(rRct
.Width())
321 << static_cast<sal_Int32
>(rRct
.Height());
322 /* Close Fly Record */
323 aIo
.CloseRec( SW_LAYCACHE_IO_REC_FLY
);
329 pPage
= (SwPageFrm
*)pPage
->GetNext();
331 aIo
.CloseRec( SW_LAYCACHE_IO_REC_PAGES
);
336 sal_Bool
SwLayoutCache::CompareLayout( const SwDoc
& rDoc
) const
340 const SwRootFrm
*pRootFrm
= rDoc
.GetCurrentLayout();
343 sal_uInt16 nIndex
= 0;
344 sal_uLong nStartOfContent
= rDoc
.GetNodes().GetEndOfContent().
345 StartOfSectionNode()->GetIndex();
346 SwPageFrm
* pPage
= (SwPageFrm
*)pRootFrm
->Lower();
348 pPage
= (SwPageFrm
*)pPage
->GetNext();
351 if( nIndex
>= pImpl
->size() )
354 SwLayoutFrm
* pLay
= pPage
->FindBodyCont();
355 SwFrm
* pTmp
= pLay
? pLay
->ContainsAny() : NULL
;
356 if( pTmp
&& pTmp
->IsSctFrm() )
357 pTmp
= ((SwSectionFrm
*)pTmp
)->ContainsAny();
360 if( pTmp
->IsTxtFrm() )
362 sal_uLong nNdIdx
= ((SwTxtFrm
*)pTmp
)->GetNode()->GetIndex();
363 if( nNdIdx
> nStartOfContent
)
365 sal_Bool bFollow
= ((SwTxtFrm
*)pTmp
)->IsFollow();
366 nNdIdx
-= nStartOfContent
;
367 if( pImpl
->GetBreakIndex( nIndex
) != nNdIdx
||
368 SW_LAYCACHE_IO_REC_PARA
!=
369 pImpl
->GetBreakType( nIndex
) ||
370 ( bFollow
? ((SwTxtFrm
*)pTmp
)->GetOfst()
371 : STRING_LEN
) != pImpl
->GetBreakOfst( nIndex
) )
378 else if( pTmp
->IsTabFrm() )
380 SwTabFrm
* pTab
= (SwTabFrm
*)pTmp
;
381 sal_uLong nOfst
= STRING_LEN
;
382 if( pTab
->IsFollow() )
385 if( pTab
->IsFollow() )
386 pTab
= pTab
->FindMaster( true );
387 while( pTab
!= pTmp
)
389 SwFrm
* pSub
= pTab
->Lower();
393 pSub
= pSub
->GetNext();
395 pTab
= pTab
->GetFollow();
401 pTab
->GetTable()->GetTableNode()->GetIndex();
402 if( nNdIdx
> nStartOfContent
)
404 nNdIdx
-= nStartOfContent
;
405 if( pImpl
->GetBreakIndex( nIndex
) != nNdIdx
||
406 SW_LAYCACHE_IO_REC_TABLE
!=
407 pImpl
->GetBreakType( nIndex
) ||
408 nOfst
!= pImpl
->GetBreakOfst( nIndex
) )
414 if( pTab
->GetFollow() )
416 if( nOfst
== STRING_LEN
)
420 SwFrm
* pSub
= pTab
->Lower();
424 pSub
= pSub
->GetNext();
426 pTab
= pTab
->GetFollow();
427 SwPageFrm
*pTabPage
= pTab
->FindPageFrm();
428 if( pTabPage
!= pPage
)
433 } while ( pTab
->GetFollow() );
440 pPage
= (SwPageFrm
*)pPage
->GetNext();
447 void SwLayoutCache::ClearImpl()
457 SwLayoutCache::~SwLayoutCache()
459 OSL_ENSURE( !nLockCount
, "Deleting a locked SwLayoutCache!?" );
465 * a help class to create not nested section frames
466 * for nested sections.
469 SwActualSection::SwActualSection( SwActualSection
*pUp
,
471 SwSectionNode
*pNd
) :
478 const SwNodeIndex
*pIndex
= pSect
->GetFmt()->GetCntnt().GetCntntIdx();
479 pSectNode
= pIndex
->GetNode().FindSectionNode();
485 * is the helper class, which utilizes the layout cache information
486 * to distribute the document content to the rigth pages.
487 * It's used by the _InsertCnt(..)-function.
488 * If there's no layout cache, the distibution to the pages is more
489 * a guess, but a guess with statistical background.
492 SwLayHelper::SwLayHelper( SwDoc
*pD
, SwFrm
* &rpF
, SwFrm
* &rpP
, SwPageFrm
* &rpPg
,
493 SwLayoutFrm
* &rpL
, SwActualSection
* &rpA
, sal_Bool
&rB
,
494 sal_uLong nNodeIndex
, bool bCache
)
495 : rpFrm( rpF
), rpPrv( rpP
), rpPage( rpPg
), rpLay( rpL
),
496 rpActualSection( rpA
), rbBreakAfter(rB
), pDoc(pD
), nMaxParaPerPage( 25 ),
497 nParagraphCnt( bCache
? 0 : USHRT_MAX
), bFirst( bCache
)
499 pImpl
= pDoc
->GetLayoutCache() ? pDoc
->GetLayoutCache()->LockImpl() : NULL
;
502 nMaxParaPerPage
= 1000;
503 nStartOfContent
= pDoc
->GetNodes().GetEndOfContent().StartOfSectionNode()
505 nNodeIndex
-= nStartOfContent
;
508 while( nIndex
< pImpl
->size() && (*pImpl
)[ nIndex
] < nNodeIndex
)
510 if( nIndex
>= pImpl
->size() )
512 pDoc
->GetLayoutCache()->UnlockImpl();
519 nStartOfContent
= ULONG_MAX
;
523 SwLayHelper::~SwLayHelper()
527 OSL_ENSURE( pDoc
&& pDoc
->GetLayoutCache(), "Missing layoutcache" );
528 pDoc
->GetLayoutCache()->UnlockImpl();
533 * SwLayHelper::CalcPageCount() does not really calculate the page count,
534 * it returns the page count value from the layout cache, if available,
535 * otherwise it estimates the page count.
538 sal_uLong
SwLayHelper::CalcPageCount()
541 SwLayCacheImpl
*pCache
= pDoc
->GetLayoutCache() ?
542 pDoc
->GetLayoutCache()->LockImpl() : NULL
;
545 nPgCount
= pCache
->size() + 1;
546 pDoc
->GetLayoutCache()->UnlockImpl();
550 nPgCount
= pDoc
->GetDocStat().nPage
;
551 if ( nPgCount
<= 10 ) // no page insertion for less than 10 pages
553 sal_uLong nNdCount
= pDoc
->GetDocStat().nPara
;
556 //Estimates the number of paragraphs.
557 sal_uLong nTmp
= pDoc
->GetNodes().GetEndOfContent().GetIndex() -
558 pDoc
->GetNodes().GetEndOfExtras().GetIndex();
559 //Tables have a little overhead..
560 nTmp
-= pDoc
->GetTblFrmFmts()->size() * 25;
562 nTmp
-= (pDoc
->GetNodes().GetEndOfAutotext().GetIndex() -
563 pDoc
->GetNodes().GetEndOfInserts().GetIndex()) / 3 * 5;
567 if ( nNdCount
> 100 ) // no estimation below this value
570 nMaxParaPerPage
= nNdCount
/ nPgCount
;
573 nMaxParaPerPage
= std::max( sal_uLong(20),
574 sal_uLong(20 + nNdCount
/ 1000 * 3) );
575 const sal_uLong nMax
= 53;
576 nMaxParaPerPage
= std::min( nMaxParaPerPage
, nMax
);
577 nPgCount
= nNdCount
/ nMaxParaPerPage
;
579 if ( nNdCount
< 1000 )
580 nPgCount
= 0;// no progress bar for small documents
582 if( rpLay
&& rpLay
->getRootFrm() )
583 pSh
= rpLay
->getRootFrm()->GetCurrShell();
584 if( pSh
&& pSh
->GetViewOptions()->getBrowseMode() )
585 nMaxParaPerPage
*= 6;
592 * SwLayHelper::CheckInsertPage()
593 * inserts a page and return true, if
594 * - the break after flag is set
595 * - the actual content wants a break before
596 * - the maximum count of paragraph/rows is reached
598 * The break after flag is set, if the actual content
599 * wants a break after.
602 bool SwLayHelper::CheckInsertPage()
604 bool bEnd
= 0 == rpPage
->GetNext();
605 const SwAttrSet
* pAttr
= rpFrm
->GetAttrSet();
606 const SvxFmtBreakItem
& rBrk
= pAttr
->GetBreak();
607 const SwFmtPageDesc
& rDesc
= pAttr
->GetPageDesc();
608 // #118195# Do not evaluate page description if frame
609 // is a follow frame!
610 const SwPageDesc
* pDesc
= rpFrm
->IsFlowFrm() &&
611 SwFlowFrm::CastFlowFrm( rpFrm
)->IsFollow() ?
615 bool bBrk
= nParagraphCnt
> nMaxParaPerPage
|| rbBreakAfter
;
616 rbBreakAfter
= rBrk
.GetBreak() == SVX_BREAK_PAGE_AFTER
||
617 rBrk
.GetBreak() == SVX_BREAK_PAGE_BOTH
;
619 bBrk
= rBrk
.GetBreak() == SVX_BREAK_PAGE_BEFORE
||
620 rBrk
.GetBreak() == SVX_BREAK_PAGE_BOTH
;
624 sal_uInt16 nPgNum
= 0;
626 pDesc
= rpPage
->GetPageDesc()->GetFollow();
629 if ( 0 != (nPgNum
= rDesc
.GetNumOffset()) )
630 ((SwRootFrm
*)rpPage
->GetUpper())->SetVirtPageNum(sal_True
);
632 bool bNextPageOdd
= !rpPage
->OnRightPage();
633 bool bInsertEmpty
= false;
634 if( nPgNum
&& bNextPageOdd
!= ( ( nPgNum
% 2 ) != 0 ) )
636 bNextPageOdd
= !bNextPageOdd
;
639 // If the page style is changing, we'll have a first page.
640 bool bNextPageFirst
= pDesc
!= rpPage
->GetPageDesc();
641 ::InsertNewPage( (SwPageDesc
&)*pDesc
, rpPage
->GetUpper(),
642 bNextPageOdd
, bNextPageFirst
, bInsertEmpty
, sal_False
, rpPage
->GetNext() );
645 OSL_ENSURE( rpPage
->GetNext(), "No new page?" );
647 { rpPage
= (SwPageFrm
*)rpPage
->GetNext();
648 } while ( rpPage
->GetNext() );
652 OSL_ENSURE( rpPage
->GetNext(), "No new page?" );
653 rpPage
= (SwPageFrm
*)rpPage
->GetNext();
654 if ( rpPage
->IsEmptyPage() )
656 OSL_ENSURE( rpPage
->GetNext(), "No new page?" );
657 rpPage
= (SwPageFrm
*)rpPage
->GetNext();
660 rpLay
= rpPage
->FindBodyCont();
661 while( rpLay
->Lower() )
662 rpLay
= (SwLayoutFrm
*)rpLay
->Lower();
669 * SwLayHelper::CheckInsert
670 * is the entry point for the _InsertCnt-function.
671 * The document content index is checked either it is
672 * in the layout cache either it's time to insert a page
673 * cause the maximal estimation of content per page is reached.
674 * A really big table or long paragraph may contains more than
675 * one page, in this case the needed count of pages will inserted.
678 bool SwLayHelper::CheckInsert( sal_uLong nNodeIndex
)
681 bool bLongTab
= false;
682 sal_uLong
nMaxRowPerPage( 0 );
683 nNodeIndex
-= nStartOfContent
;
684 sal_uInt16
nRows( 0 );
685 if( rpFrm
->IsTabFrm() )
687 //Inside a table counts every row as a paragraph
688 SwFrm
*pLow
= ((SwTabFrm
*)rpFrm
)->Lower();
693 pLow
= pLow
->GetNext();
695 nParagraphCnt
+= nRows
;
696 if( !pImpl
&& nParagraphCnt
> nMaxParaPerPage
+ 10 )
698 // OD 09.04.2003 #108698# - improve heuristics:
699 // Assume that a table, which has more than three times the quantity
700 // of maximal paragraphs per page rows, consists of rows, which have
701 // the height of a normal paragraph. Thus, allow as much rows per page
702 // as much paragraphs are allowed.
703 if ( nRows
> ( 3*nMaxParaPerPage
) )
705 nMaxRowPerPage
= nMaxParaPerPage
;
709 SwFrm
*pTmp
= ((SwTabFrm
*)rpFrm
)->Lower();
710 if( pTmp
->GetNext() )
711 pTmp
= pTmp
->GetNext();
712 pTmp
= ((SwRowFrm
*)pTmp
)->Lower();
717 pTmp
= pTmp
->GetNext();
719 nMaxRowPerPage
= std::max( sal_uLong(2), nMaxParaPerPage
/ nCnt
);
726 if( bFirst
&& pImpl
&& nIndex
< pImpl
->size() &&
727 pImpl
->GetBreakIndex( nIndex
) == nNodeIndex
&&
728 ( pImpl
->GetBreakOfst( nIndex
) < STRING_LEN
||
729 ( ++nIndex
< pImpl
->size() &&
730 pImpl
->GetBreakIndex( nIndex
) == nNodeIndex
) ) )
732 #if OSL_DEBUG_LEVEL > 1
733 sal_uLong nBreakIndex
= ( pImpl
&& nIndex
< pImpl
->size() ) ?
734 pImpl
->GetBreakIndex(nIndex
) : 0xffff;
737 // OD 09.04.2003 #108698# - always split a big tables.
739 ( rpFrm
->IsTabFrm() && bLongTab
)
742 sal_uLong nRowCount
= 0;
745 if( pImpl
|| bLongTab
)
747 #if OSL_DEBUG_LEVEL > 1
748 sal_uLong nBrkIndex
= ( pImpl
&& nIndex
< pImpl
->size() ) ?
749 pImpl
->GetBreakIndex(nIndex
) : 0xffff;
752 xub_StrLen nOfst
= STRING_LEN
;
753 sal_uInt16 nType
= SW_LAYCACHE_IO_REC_PAGES
;
756 rbBreakAfter
= sal_True
;
757 nOfst
= static_cast<xub_StrLen
>(nRowCount
+ nMaxRowPerPage
);
761 while( nIndex
< pImpl
->size() &&
762 pImpl
->GetBreakIndex(nIndex
) < nNodeIndex
)
764 if( nIndex
< pImpl
->size() &&
765 pImpl
->GetBreakIndex(nIndex
) == nNodeIndex
)
767 nType
= pImpl
->GetBreakType( nIndex
);
768 nOfst
= pImpl
->GetBreakOfst( nIndex
++ );
769 rbBreakAfter
= sal_True
;
773 if( nOfst
< STRING_LEN
)
776 sal_uInt16
nRepeat( 0 );
777 if( !bLongTab
&& rpFrm
->IsTxtFrm() &&
778 SW_LAYCACHE_IO_REC_PARA
== nType
&&
779 nOfst
<((SwTxtFrm
*)rpFrm
)->GetTxtNode()->GetTxt().getLength())
781 else if( rpFrm
->IsTabFrm() && nRowCount
< nOfst
&&
782 ( bLongTab
|| SW_LAYCACHE_IO_REC_TABLE
== nType
) )
784 nRepeat
= ((SwTabFrm
*)rpFrm
)->
785 GetTable()->GetRowsToRepeat();
786 bSplit
= nOfst
< nRows
&& nRowCount
+ nRepeat
< nOfst
;
787 bLongTab
= bLongTab
&& bSplit
;
791 rpFrm
->InsertBehind( rpLay
, rpPrv
);
792 rpFrm
->Frm().Pos() = rpLay
->Frm().Pos();
793 rpFrm
->Frm().Pos().Y() += 1;
795 if( rpFrm
->IsTabFrm() )
797 SwTabFrm
* pTab
= (SwTabFrm
*)rpFrm
;
798 // #i33629#, #i29955#
799 ::RegistFlys( pTab
->FindPageFrm(), pTab
);
800 SwFrm
*pRow
= pTab
->Lower();
801 SwTabFrm
*pFoll
= new SwTabFrm( *pTab
);
806 bDontCreateObjects
= true; //frmtool
808 // Insert new headlines:
809 sal_uInt16 nRowIdx
= 0;
810 SwRowFrm
* pHeadline
= 0;
811 while( nRowIdx
< nRepeat
)
813 OSL_ENSURE( pTab
->GetTable()->GetTabLines()[ nRowIdx
], "Table ohne Zeilen?" );
815 new SwRowFrm( *pTab
->GetTable()->GetTabLines()[ nRowIdx
], pTab
);
816 pHeadline
->SetRepeatedHeadline( true );
817 pHeadline
->InsertBefore( pFoll
, 0 );
818 pHeadline
->RegistFlys();
823 bDontCreateObjects
= false;
825 nRows
= nRows
+ nRepeat
;
829 while( pRow
&& nRowCount
< nOfst
)
831 pRow
= pRow
->GetNext();
836 SwFrm
* pNxt
= pRow
->GetNext();
838 pRow
->InsertBehind( pFoll
, pPrv
);
846 SwTxtFrm
*const pNew
= static_cast<SwTxtFrm
*>(
847 static_cast<SwTxtFrm
*>(rpFrm
)
848 ->GetTxtNode()->MakeFrm(rpFrm
));
849 pNew
->ManipOfst( nOfst
);
850 pNew
->SetFollow( ((SwTxtFrm
*)rpFrm
)->GetFollow() );
851 ((SwTxtFrm
*)rpFrm
)->SetFollow( pNew
);
858 SwPageFrm
* pLastPage
= rpPage
;
859 if( CheckInsertPage() )
861 _CheckFlyCache( pLastPage
);
862 if( rpPrv
&& rpPrv
->IsTxtFrm() && !rpPrv
->GetValidSizeFlag() )
863 rpPrv
->Frm().Height( rpPrv
->GetUpper()->Prt().Height() );
869 if ( rpActualSection
)
871 //Did the SectionFrm even have a content? If not, we can
872 //directly put it somewhere else
875 if ( !rpActualSection
->GetSectionFrm()->ContainsCntnt())
877 pSct
= rpActualSection
->GetSectionFrm();
882 pSct
= new SwSectionFrm(
883 *rpActualSection
->GetSectionFrm(), sal_False
);
884 rpActualSection
->GetSectionFrm()->SimpleFormat();
887 rpActualSection
->SetSectionFrm( pSct
);
888 pSct
->InsertBehind( rpLay
, 0 );
891 pSct
->Frm().Pos() = rpLay
->Frm().Pos();
892 pSct
->Frm().Pos().Y() += 1; //because of the notifications
895 if ( rpLay
->Lower() && rpLay
->Lower()->IsLayoutFrm() )
896 rpLay
= rpLay
->GetNextLayoutLeaf();
899 } while( bLongTab
|| ( pImpl
&& nIndex
< pImpl
->size() &&
900 (*pImpl
)[ nIndex
] == nNodeIndex
) );
906 struct SdrObjectCompare
908 bool operator()( const SdrObject
* pF1
, const SdrObject
* pF2
) const
910 return pF1
->GetOrdNum() < pF2
->GetOrdNum();
914 struct FlyCacheCompare
916 bool operator()( const SwFlyCache
* pC1
, const SwFlyCache
* pC2
) const
918 return pC1
->nOrdNum
< pC2
->nOrdNum
;
923 * SwLayHelper::_CheckFlyCache(..)
924 * If a new page is inserted, the last page is analysed.
925 * If there are text frames with default position, the fly cache
926 * is checked, if these frames are stored in the cache.
929 void SwLayHelper::_CheckFlyCache( SwPageFrm
* pPage
)
931 if( !pImpl
|| !pPage
)
933 sal_uInt16 nFlyCount
= pImpl
->GetFlyCount();
934 // Any text frames at the page, fly cache avaiable?
935 if( pPage
->GetSortedObjs() && nFlyIdx
< nFlyCount
)
937 SwSortedObjs
&rObjs
= *pPage
->GetSortedObjs();
938 sal_uInt16 nPgNum
= pPage
->GetPhyPageNum();
941 // NOTE: Here we do not use the absolute ordnums but
942 // relative ordnums for the objects on this page.
944 // skip fly frames from pages before the current page
946 while( nFlyIdx
< nFlyCount
&& ( pFlyC
= pImpl
->
947 GetFlyCache(nFlyIdx
) )->nPageNum
< nPgNum
)
950 // sort cached objects on this page by ordnum
951 std::set
< const SwFlyCache
*, FlyCacheCompare
> aFlyCacheSet
;
952 sal_uInt16 nIdx
= nFlyIdx
;
954 while( nIdx
< nFlyCount
&& ( pFlyC
= pImpl
->
955 GetFlyCache( nIdx
) )->nPageNum
== nPgNum
)
957 aFlyCacheSet
.insert( pFlyC
);
961 // sort objects on this page by ordnum
962 std::set
< const SdrObject
*, SdrObjectCompare
> aFlySet
;
963 for ( sal_uInt16 i
= 0; i
< rObjs
.Count(); ++i
)
965 SwAnchoredObject
* pAnchoredObj
= rObjs
[i
];
966 if ( pAnchoredObj
->ISA(SwFlyFrm
) ) // a text frame?
968 SwFlyFrm
*pFly
= static_cast<SwFlyFrm
*>(pAnchoredObj
);
969 if( pFly
->GetAnchorFrm() &&
970 !pFly
->GetAnchorFrm()->FindFooterOrHeader() )
972 const SwContact
*pC
= ::GetUserCall( pAnchoredObj
->GetDrawObj() );
975 aFlySet
.insert( pAnchoredObj
->GetDrawObj() );
981 if ( aFlyCacheSet
.size() == aFlySet
.size() )
983 std::set
< const SwFlyCache
*, FlyCacheCompare
>::iterator aFlyCacheSetIt
=
984 aFlyCacheSet
.begin();
985 std::set
< const SdrObject
*, SdrObjectCompare
>::iterator aFlySetIt
=
988 while ( aFlyCacheSetIt
!= aFlyCacheSet
.end() )
990 const SwFlyCache
* pFlyCache
= *aFlyCacheSetIt
;
991 SwFlyFrm
* pFly
= ((SwVirtFlyDrawObj
*)*aFlySetIt
)->GetFlyFrm();
993 if ( pFly
->Frm().Left() == FAR_AWAY
)
995 // we get the stored information
996 pFly
->Frm().Pos().X() = pFlyCache
->Left() +
998 pFly
->Frm().Pos().Y() = pFlyCache
->Top() +
1000 if ( pImpl
->IsUseFlyCache() )
1002 pFly
->Frm().Width( pFlyCache
->Width() );
1003 pFly
->Frm().Height( pFlyCache
->Height() );
1015 * SwLayHelper::CheckPageFlyCache(..)
1016 * looks for the given text frame in the fly cache and sets
1017 * the position and size, if possible.
1018 * The fly cache is sorted by pages and we start searching with the given page.
1019 * If we found the page number in the fly cache, we set
1020 * the rpPage parameter to the right page, if possible.
1023 bool SwLayHelper::CheckPageFlyCache( SwPageFrm
* &rpPage
, SwFlyFrm
* pFly
)
1025 if( !pFly
->GetAnchorFrm() || !pFly
->GetVirtDrawObj() ||
1026 pFly
->GetAnchorFrm()->FindFooterOrHeader() )
1029 SwDoc
* pDoc
= rpPage
->GetFmt()->GetDoc();
1030 SwLayCacheImpl
*pCache
= pDoc
->GetLayoutCache() ?
1031 pDoc
->GetLayoutCache()->LockImpl() : NULL
;
1034 sal_uInt16 nPgNum
= rpPage
->GetPhyPageNum();
1035 sal_uInt16 nIdx
= 0;
1036 sal_uInt16 nCnt
= pCache
->GetFlyCount();
1037 sal_uLong nOrdNum
= pFly
->GetVirtDrawObj()->GetOrdNum();
1038 SwFlyCache
* pFlyC
= 0;
1040 // skip fly frames from pages before the current page
1041 while( nIdx
< nCnt
&&
1042 nPgNum
> (pFlyC
= pCache
->GetFlyCache( nIdx
))->nPageNum
)
1045 while( nIdx
< nCnt
&&
1046 nOrdNum
!= (pFlyC
= pCache
->GetFlyCache( nIdx
))->nOrdNum
)
1050 SwPageFrm
*pPage
= rpPage
;
1051 while( pPage
&& pPage
->GetPhyPageNum() < pFlyC
->nPageNum
)
1052 pPage
= (SwPageFrm
*)pPage
->GetNext();
1053 // #i43266# - if the found page is an empty page,
1054 // take the previous one (take next one, if previous one doesn't exists)
1055 if ( pPage
&& pPage
->IsEmptyPage() )
1057 pPage
= static_cast<SwPageFrm
*>( pPage
->GetPrev()
1059 : pPage
->GetNext() );
1064 pFly
->Frm().Pos().X() = pFlyC
->Left() + pPage
->Frm().Left();
1065 pFly
->Frm().Pos().Y() = pFlyC
->Top() + pPage
->Frm().Top();
1066 if ( pCache
->IsUseFlyCache() )
1068 pFly
->Frm().Width( pFlyC
->Width() );
1069 pFly
->Frm().Height( pFlyC
->Height() );
1074 pDoc
->GetLayoutCache()->UnlockImpl();
1079 // -----------------------------------------------------------------------------
1081 SwLayCacheIoImpl::SwLayCacheIoImpl( SvStream
& rStrm
, bool bWrtMd
) :
1083 nMajorVersion(SW_LAYCACHE_IO_VERSION_MAJOR
),
1084 nMinorVersion(SW_LAYCACHE_IO_VERSION_MINOR
),
1085 bWriteMode( bWrtMd
),
1089 *pStream
<< nMajorVersion
1093 *pStream
>> nMajorVersion
1097 bool SwLayCacheIoImpl::OpenRec( sal_uInt8 cType
)
1100 sal_uInt32 nPos
= pStream
->Tell();
1103 aRecords
.push_back( RecTypeSize(cType
, nPos
) );
1104 *pStream
<< (sal_uInt32
) 0;
1110 sal_uInt8 cRecTyp
= (sal_uInt8
)nVal
;
1111 if( !nVal
|| cRecTyp
!= cType
||
1112 pStream
->GetErrorCode() != SVSTREAM_OK
|| pStream
->IsEof() )
1114 OSL_ENSURE( nVal
, "OpenRec: Record-Header is 0" );
1115 OSL_ENSURE( cRecTyp
== cType
, "OpenRec: Wrong Record Type" );
1116 aRecords
.push_back( RecTypeSize(0, pStream
->Tell()) );
1122 sal_uInt32 nSize
= nVal
>> 8;
1123 aRecords
.push_back( RecTypeSize(cRecTyp
, nPos
+nSize
) );
1131 bool SwLayCacheIoImpl::CloseRec( sal_uInt8
)
1134 OSL_ENSURE( !aRecords
.empty(), "CloseRec: no levels" );
1135 if( !aRecords
.empty() )
1137 sal_uInt32 nPos
= pStream
->Tell();
1140 sal_uInt32 nBgn
= aRecords
.back().size
;
1141 pStream
->Seek( nBgn
);
1142 sal_uInt32 nSize
= nPos
- nBgn
;
1143 sal_uInt32 nVal
= ( nSize
<< 8 ) | aRecords
.back().type
;
1145 pStream
->Seek( nPos
);
1146 if( pStream
->GetError() != SVSTREAM_OK
)
1151 sal_uInt32 n
= aRecords
.back().size
;
1152 OSL_ENSURE( n
>= nPos
, "CloseRec: to much data read" );
1159 if( pStream
->GetErrorCode() != SVSTREAM_OK
)
1162 aRecords
.pop_back();
1171 sal_uInt32
SwLayCacheIoImpl::BytesLeft()
1174 if( !bError
&& !aRecords
.empty() )
1176 sal_uInt32 nEndPos
= aRecords
.back().size
;
1177 sal_uInt32 nPos
= pStream
->Tell();
1178 if( nEndPos
> nPos
)
1184 sal_uInt8
SwLayCacheIoImpl::Peek()
1189 sal_uInt32 nPos
= pStream
->Tell();
1191 pStream
->Seek( nPos
);
1192 if( pStream
->GetErrorCode() != SVSTREAM_OK
)
1201 void SwLayCacheIoImpl::SkipRec()
1203 sal_uInt8 c
= Peek();
1205 pStream
->Seek( aRecords
.back().size
);
1209 sal_uInt8
SwLayCacheIoImpl::OpenFlagRec()
1211 OSL_ENSURE( !bWriteMode
, "OpenFlagRec illegal in write mode" );
1212 sal_uInt8
cFlags(0);
1214 nFlagRecEnd
= pStream
->Tell() + ( cFlags
& 0x0F );
1215 return (cFlags
>> 4);
1218 void SwLayCacheIoImpl::OpenFlagRec( sal_uInt8 nFlags
, sal_uInt8 nLen
)
1220 OSL_ENSURE( bWriteMode
, "OpenFlagRec illegal in read mode" );
1221 OSL_ENSURE( (nFlags
& 0xF0) == 0, "illegal flags set" );
1222 OSL_ENSURE( nLen
< 16, "wrong flag record length" );
1223 sal_uInt8 cFlags
= (nFlags
<< 4) + nLen
;
1225 nFlagRecEnd
= pStream
->Tell() + nLen
;
1228 void SwLayCacheIoImpl::CloseFlagRec()
1232 OSL_ENSURE( pStream
->Tell() == nFlagRecEnd
, "Wrong amount of data written" );
1236 OSL_ENSURE( pStream
->Tell() <= nFlagRecEnd
, "To many data read" );
1237 if( pStream
->Tell() != nFlagRecEnd
)
1238 pStream
->Seek( nFlagRecEnd
);
1242 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */