diff options
author | Andreas Martens <ama@openoffice.org> | 2001-05-29 11:41:34 +0000 |
---|---|---|
committer | Andreas Martens <ama@openoffice.org> | 2001-05-29 11:41:34 +0000 |
commit | 2e8783d6c38eaf367c39ee2ee6c20fa2d4f23662 (patch) | |
tree | 5fada10d0b3fd45111e78da056fddc4396cffd0c | |
parent | 9ffefe939f98b7f571c56637c2e9e7e1fce14a06 (diff) |
Fix #87530#: Save/load layout cache information
-rw-r--r-- | sw/source/core/doc/docnew.cxx | 31 | ||||
-rw-r--r-- | sw/source/core/inc/laycache.hxx | 106 | ||||
-rw-r--r-- | sw/source/core/layout/calcmove.cxx | 6 | ||||
-rw-r--r-- | sw/source/core/layout/frmtool.cxx | 387 | ||||
-rw-r--r-- | sw/source/core/layout/laycache.cxx | 1039 | ||||
-rw-r--r-- | sw/source/core/layout/layhelp.hxx | 233 | ||||
-rw-r--r-- | sw/source/core/layout/makefile.mk | 6 |
7 files changed, 1486 insertions, 322 deletions
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx index 4918f5fe3ea0..fc400c614870 100644 --- a/sw/source/core/doc/docnew.cxx +++ b/sw/source/core/doc/docnew.cxx @@ -2,9 +2,9 @@ * * $RCSfile: docnew.cxx,v $ * - * $Revision: 1.14 $ + * $Revision: 1.15 $ * - * last change: $Author: mtg $ $Date: 2001-05-11 18:35:50 $ + * last change: $Author: ama $ $Date: 2001-05-29 12:32:09 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -217,6 +217,9 @@ #ifndef _BREAKIT_HXX #include <breakit.hxx> #endif +#ifndef _LAYCACHE_HXX +#include <laycache.hxx> +#endif #ifndef _MVSAVE_HXX #include <mvsave.hxx> #endif @@ -629,6 +632,7 @@ SwDoc::~SwDoc() delete pColumnContFmt; delete pDfltCharFmt; delete pDfltFrmFmt; + delete pLayoutCache; } @@ -976,3 +980,26 @@ void SwDoc::ClearForbiddenCharacters( USHORT nLang ) } } +/*-----------------28.5.2001 10:06------------------ + * SwDoc: + * Reading and writing of the layout cache. + *--------------------------------------------------*/ + +void SwDoc::ReadLayoutCache( SvStream& rStream ) +{ + if( !pLayoutCache ) + pLayoutCache = new SwLayoutCache(); + if( !pLayoutCache->IsLocked() ) + { + pLayoutCache->GetLockCount() |= 0x8000; + pLayoutCache->Read( rStream ); + pLayoutCache->GetLockCount() &= 0x7fff; + } +} + +void SwDoc::WriteLayoutCache( SvStream& rStream ) +{ + pLayoutCache->Write( rStream, *this ); +} + + diff --git a/sw/source/core/inc/laycache.hxx b/sw/source/core/inc/laycache.hxx new file mode 100644 index 000000000000..ab3f5a81f12f --- /dev/null +++ b/sw/source/core/inc/laycache.hxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * $RCSfile: laycache.hxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: ama $ $Date: 2001-05-29 12:41:34 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#ifndef _LAYCACHE_HXX +#define _LAYCACHE_HXX + + +class SwDoc; +class SwLayCacheImpl; + +/************************************************************************* + * class SwLayoutCache + * + * This class allows to save layout information in the file and it contains + * this information after loading of a file. + * Call Write(..) with a stream and the document to save and the page break + * information of the document will be written. + * Call Read(..) with a stream and the member pLayCacheImpl will + * read the information from the stream and store it in an internal structur. + * There's a simple locking mechanism at these classes, + * if somebody reads the information, he increments the lock count by 1, + * during the Read(..) function the lock count will set to $8000. + * + **************************************************************************/ + +class SwLayoutCache +{ + SwLayCacheImpl *pImpl; + USHORT nLockCount; +public: + SwLayoutCache() : pImpl( NULL ), nLockCount( 0 ) {} + ~SwLayoutCache(); + + void Read( SvStream &rStream ); + void Write( SvStream &rStream, const SwDoc& rDoc ); + + void ClearImpl(); + sal_Bool IsLocked() const { return nLockCount > 0; } + USHORT& GetLockCount() { return nLockCount; } + SwLayCacheImpl *LockImpl() + { if( nLockCount & 0x8000 ) return NULL; ++nLockCount; return pImpl; } + void UnlockImpl() { --nLockCount; } + +#ifndef PRODUCT + sal_Bool CompareLayout( const SwDoc& rDoc ) const; +#endif +}; + +#endif diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx index dab5f7d59f14..d1b2222eb999 100644 --- a/sw/source/core/layout/calcmove.cxx +++ b/sw/source/core/layout/calcmove.cxx @@ -2,9 +2,9 @@ * * $RCSfile: calcmove.cxx,v $ * - * $Revision: 1.2 $ + * $Revision: 1.3 $ * - * last change: $Author: ama $ $Date: 2000-12-06 12:27:40 $ + * last change: $Author: ama $ $Date: 2001-05-29 12:33:12 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -176,8 +176,6 @@ BOOL SwCntntFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, BOOL, BOOL & ) const SwFrm *pPrevFrm = pNewUpper->Lower(); while ( pPrevFrm ) { - if( !pPrevFrm->GetNext() && !pPrevFrm->IsValid() ) - return TRUE; aRect.Top( pPrevFrm->Frm().Bottom() ); pPrevFrm = pPrevFrm->GetNext(); } diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx index dbfd89dca3f3..999397f60059 100644 --- a/sw/source/core/layout/frmtool.cxx +++ b/sw/source/core/layout/frmtool.cxx @@ -2,9 +2,9 @@ * * $RCSfile: frmtool.cxx,v $ * - * $Revision: 1.7 $ + * $Revision: 1.8 $ * - * last change: $Author: ama $ $Date: 2001-05-11 09:50:35 $ + * last change: $Author: ama $ $Date: 2001-05-29 12:37:16 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -85,15 +85,9 @@ #ifndef _SVX_BRSHITEM_HXX //autogen #include <svx/brshitem.hxx> #endif -#ifndef _SVX_BRKITEM_HXX //autogen -#include <svx/brkitem.hxx> -#endif #ifndef _SVX_KEEPITEM_HXX //autogen #include <svx/keepitem.hxx> #endif -#ifndef _SVX_SIZEITEM_HXX //autogen -#include <svx/sizeitem.hxx> -#endif #ifndef _SVX_SHADITEM_HXX //autogen #include <svx/shaditem.hxx> #endif @@ -117,15 +111,6 @@ #ifndef _FMTANCHR_HXX //autogen #include <fmtanchr.hxx> #endif -#ifndef _FMTPDSC_HXX //autogen -#include <fmtpdsc.hxx> -#endif -#ifndef _FMTPDSC_HXX //autogen -#include <fmtpdsc.hxx> -#endif -#ifndef _FMTPDSC_HXX //autogen -#include <fmtpdsc.hxx> -#endif #ifndef _FMTHDFT_HXX //autogen #include <fmthdft.hxx> #endif @@ -135,12 +120,6 @@ #ifndef _FMTFSIZE_HXX //autogen #include <fmtfsize.hxx> #endif -#ifndef _FMTCNCT_HXX //autogen -#include <fmtcnct.hxx> -#endif -#ifndef _DOCSTAT_HXX //autogen -#include <docstat.hxx> -#endif #ifndef _DOCARY_HXX #include <docary.hxx> #endif @@ -150,11 +129,8 @@ #ifndef _SWMODULE_HXX #include <swmodule.hxx> #endif -#include "rootfrm.hxx" #include "pagefrm.hxx" -#include "cntfrm.hxx" #include "colfrm.hxx" -#include "flyfrm.hxx" #include "doc.hxx" #include "fesh.hxx" #include "viewimp.hxx" @@ -163,8 +139,6 @@ #include "dcontact.hxx" #include "frmtool.hxx" #include "docsh.hxx" -#include "swtable.hxx" -#include "errhdl.hxx" #include "tabfrm.hxx" #include "rowfrm.hxx" #include "ftnfrm.hxx" @@ -179,7 +153,12 @@ #include "node2lay.hxx" #include "ndole.hxx" #include "ndtxt.hxx" -#include "fmtclds.hxx" // SwFmtCol +#ifndef _LAYHELP_HXX +#include <layhelp.hxx> +#endif +#ifndef _LAYCACHE_HXX +#include <laycache.hxx> +#endif #include "mdiexp.hxx" #include "statstr.hrc" @@ -194,6 +173,8 @@ FASTBOOL bSetCompletePaintOnInvalidate = FALSE; BYTE StackHack::nCnt = 0; BOOL StackHack::bLocked = FALSE; + + /************************************************************************* |* |* SwFrmNotify::SwFrmNotify() @@ -1026,111 +1007,6 @@ void AppendAllObjs( const SwSpzFrmFmts *pTbl ) aCpy.Remove( 0, aCpy.Count() ); } -BOOL MA_FASTCALL lcl_CheckInsertPage( SwFrm *pFrm, SwPageFrm *&rpPage, - SwLayoutFrm *&rpLay, - ULONG nParagraphCnt, - ULONG nMaxParaPerPage, BOOL &rbBreakAfter ) -{ - FASTBOOL bEnd = 0 == rpPage->GetNext(); - const SwAttrSet *pAttr = pFrm->GetAttrSet(); - const SvxFmtBreakItem &rBrk = pAttr->GetBreak(); - const SwFmtPageDesc &rDesc = pAttr->GetPageDesc(); - const SwPageDesc *pDesc = rDesc.GetPageDesc(); - - BOOL bBrk = nParagraphCnt > nMaxParaPerPage || rbBreakAfter; - rbBreakAfter = rBrk.GetBreak() == SVX_BREAK_PAGE_AFTER || - rBrk.GetBreak() == SVX_BREAK_PAGE_BOTH; - if ( !bBrk ) - bBrk = rBrk.GetBreak() == SVX_BREAK_PAGE_BEFORE || - rBrk.GetBreak() == SVX_BREAK_PAGE_BOTH; - - if ( bBrk || pDesc ) - { - USHORT nPgNum = 0; - if ( !pDesc ) - pDesc = rpPage->GetPageDesc()->GetFollow(); - else - { - if ( 0 != (nPgNum = rDesc.GetNumOffset()) ) - ((SwRootFrm*)rpPage->GetUpper())->SetVirtPageNum(TRUE); - } - BOOL bOdd = !rpPage->OnRightPage(); - BOOL bInsertEmpty = FALSE; - if( nPgNum && bOdd != ( ( nPgNum % 2 ) != 0 ) ) - { - bOdd = !bOdd; - bInsertEmpty = TRUE; - } - ::InsertNewPage( (SwPageDesc&)*pDesc, rpPage->GetUpper(), - bOdd, bInsertEmpty, FALSE, rpPage->GetNext() ); - if ( bEnd ) - { - ASSERT( rpPage->GetNext(), "Keine neue Seite?" ); - do - { rpPage = (SwPageFrm*)rpPage->GetNext(); - } while ( rpPage->GetNext() ); - } - else - { - ASSERT( rpPage->GetNext(), "Keine neue Seite?" ); - rpPage = (SwPageFrm*)rpPage->GetNext(); - if ( rpPage->IsEmptyPage() ) - { - ASSERT( rpPage->GetNext(), "Keine neue Seite?" ); - rpPage = (SwPageFrm*)rpPage->GetNext(); - } - } - rpLay = rpPage->FindBodyCont(); - while( rpLay->Lower() ) - rpLay = (SwLayoutFrm*)rpLay->Lower(); - return TRUE; - } - return FALSE; -} - -//Solange eine Section "offen" ist ist im InsertCnt ein Pointer auf die -//Hilfsklasse SwActualSection vorhanden. -//Bei Seitenumbruchen wird fuer "offene" Sections entsprechend ein Follow -//erzeugt. -//Da Bereiche ineinander verschachtelt sein koennen, sich aber wiederum im -//Layout nicht ineinander verschachteln, hat die Klasse eine Pointer auf ihren -//Upper wenn eine "innere" Section notwendig ist. Wenn diese abgeschlossen ist -//wird einfach wieder der "Upper" weiterverwendet (im Layout muss dafuer -//natuerlich wieder ein entsprechender Frame erzeugt werden. - -//!!Nicht fuer im Layout verschachtelte Bereiche funktionsfaehig. - -class SwActualSection -{ - SwActualSection *pUpper; - SwSectionFrm *pSectFrm; - SwSectionNode *pSectNode; -public: - SwActualSection( SwActualSection *pUpper, - SwSectionFrm *pSect, - SwSectionNode *pNd ); - - SwSectionFrm *GetSectionFrm() { return pSectFrm; } - void SetSectionFrm( SwSectionFrm *p ) { pSectFrm = p; } - SwSectionNode *GetSectionNode() { return pSectNode;} - SwActualSection *GetUpper() { return pUpper; } -}; - -SwActualSection::SwActualSection( SwActualSection *pUp, - SwSectionFrm *pSect, - SwSectionNode *pNd ) : - pUpper( pUp ), - pSectFrm( pSect ), - pSectNode( pNd ) -{ - if ( !pSectNode ) - { - const SwNodeIndex *pIndex = pSect->GetFmt()->GetCntnt().GetCntntIdx(); - pSectNode = pSect->GetFmt()->GetDoc()->GetNodes()[*pIndex]-> - FindSectionNode(); - } -} - void MA_FASTCALL _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc, ULONG nIndex, BOOL bPages, ULONG nEndIndex, SwFrm *pPrv ) @@ -1154,76 +1030,44 @@ void MA_FASTCALL _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc, //Wenn in der DocStatistik eine brauchebare Seitenzahl angegeben ist //(wird beim Schreiben gepflegt), so wird von dieser Seitenanzahl //ausgegengen. - ULONG nMaxParaPerPage = 25; - ULONG nPgCount; BOOL bStartPercent = bPages && !nEndIndex && - !SfxProgress::GetActiveProgress() && - !SfxProgress::GetActiveProgress( pDoc->GetDocShell() ); - if ( bStartPercent ) - { - nPgCount = pDoc->GetDocStat().nPage; - if ( nPgCount <= 10 ) //darunter machen wir es nicht. - nPgCount = 0; - ULONG nNdCount = pDoc->GetDocStat().nPara; - if ( nNdCount <= 1 ) - { - //Anzahl der Absaetze schaetzen. - ULONG nTmp = pDoc->GetNodes().GetEndOfContent().GetIndex() - - pDoc->GetNodes().GetEndOfExtras().GetIndex(); - //Fuer Die Tabellen ziehen wir einiges wg. der Start-/EndNodes ab. - nTmp -= pDoc->GetTblFrmFmts()->Count() * 25; - //Fuer die Rahmen ziehen auch nocheinmal etwa 5 Absaetze ab. - nTmp -= (pDoc->GetNodes().GetEndOfAutotext().GetIndex() - - pDoc->GetNodes().GetEndOfInserts().GetIndex()) / 3 * 5; - if ( nTmp > 0 ) - nNdCount = nTmp; - } - if ( nNdCount < 1000 ) - bStartPercent = FALSE; - if ( nNdCount > 100 ) //darunter machen wir es nicht - { - if ( nPgCount > 0 ) - nMaxParaPerPage = nNdCount / nPgCount; - else - { - nMaxParaPerPage = Max( ULONG(20), - ULONG(20 + nNdCount / 1000 * 3) ); - //Standard ASCII-Leerzeilen -#ifdef PM2 - const ULONG nMax = 49; -#elif MAC - const ULONG nMax = 56; -#elif UNIX - const ULONG nMax = 57; -#else - const ULONG nMax = 53; -#endif - nMaxParaPerPage = Min( nMaxParaPerPage, nMax ); - nPgCount = nNdCount / nMaxParaPerPage; - } - if ( pDoc->IsBrowseMode() ) - nMaxParaPerPage *= 6; - } - } + !SfxProgress::GetActiveProgress() && + !SfxProgress::GetActiveProgress( pDoc->GetDocShell() ); + + SwPageFrm *pPage = pLay->FindPageFrm(); + const SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts(); + SwFrm *pFrm = 0; + BOOL bBreakAfter = FALSE; + + SwActualSection *pActualSection = 0; + SwLayHelper *pPageMaker; //Wenn das Layout erzeugt wird (bPages == TRUE) steuern wir den Progress //an. Flys und DrawObjekte werden dann nicht gleich verbunden, dies //passiert erst am Ende der Funktion. - if ( bPages && bStartPercent ) + if ( bPages ) { - ::StartProgress( STR_STATSTR_LAYOUTINIT, 1, nPgCount, pDoc->GetDocShell()); - bObjsDirect = FALSE; + // Attention: the SwLayHelper class uses references to the content-, + // page-, layout-frame etc. and may change them! + pPageMaker = new SwLayHelper( pDoc, pFrm, pPrv, pPage, pLay, + pActualSection, bBreakAfter, nIndex, 0 == nEndIndex ); + if( bStartPercent ) + { + ULONG nPageCount = pPageMaker->CalcPageCount(); + if( nPageCount ) + { + ::StartProgress( STR_STATSTR_LAYOUTINIT, 1, nPageCount, + pDoc->GetDocShell()); + bObjsDirect = FALSE; + } + else + bStartPercent = FALSE; + } } + else + pPageMaker = NULL; - SwPageFrm *pPage = pLay->FindPageFrm(); - const SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts(); - SwFrm *pFrm = 0; - USHORT nParagraphCnt = 0; - BOOL bBreakAfter = FALSE; - BOOL bFirst = TRUE; - - SwActualSection *pActualSection = 0; //Siehe Dokumentation oben bei der - if( pLay->IsInSct() && //Klassendefinition + if( pLay->IsInSct() && ( pLay->IsSctFrm() || pLay->GetUpper() ) ) // Hierdurch werden Frischlinge // abgefangen, deren Flags noch nicht ermittelt werden koennen, // so z.B. beim Einfuegen einer Tabelle @@ -1245,6 +1089,12 @@ void MA_FASTCALL _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc, } } + //If a section is "open", the pActualSection points to an SwActualSection. + //If the page breaks, for "open" sections a follow will created. + //For nested sections (which have, however, not a nested layout), + //the SwActualSection class has a member, which points to an upper(section). + //When the "inner" section finishs, the upper will used instead. + while( TRUE ) { SwNode *pNd = pDoc->GetNodes()[nIndex]; @@ -1253,61 +1103,10 @@ void MA_FASTCALL _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc, SwCntntNode* pNode = (SwCntntNode*)pNd; pFrm = pNode->IsTxtNode() ? new SwTxtFrm( (SwTxtNode*)pNode ) : pNode->MakeFrm(); - if ( bPages ) - { - ++nParagraphCnt; - if ( !bFirst || nEndIndex ) - { - if ( bFirst ) - nParagraphCnt = USHRT_MAX; + if( pPageMaker && pPageMaker->CheckInsert( nIndex ) + && bStartPercent ) + ::SetProgressState( pPage->GetPhyPageNum(),pDoc->GetDocShell()); - if ( lcl_CheckInsertPage( pFrm, pPage, pLay, nParagraphCnt, - nMaxParaPerPage, bBreakAfter ) ) - { - pPrv = 0; - nParagraphCnt = 0; - if ( bPages && bStartPercent ) - ::SetProgressState( pPage->GetPhyPageNum(), pDoc->GetDocShell()); - - if ( pActualSection ) - { - //Hatte der SectionFrm ueberhaupt Inhalt? Wenn - //nicht kann er gleich umgehaengt werden. - SwFrm *pFrm; - if ( !pActualSection->GetSectionFrm()->ContainsCntnt()) - { - pFrm = pActualSection->GetSectionFrm(); - pFrm->Remove(); - } - else - { - pFrm = new SwSectionFrm( - *pActualSection->GetSectionFrm(), FALSE ); - pActualSection->GetSectionFrm()->SimpleFormat(); - pFrm->Frm().Width( pLay->Prt().Width() ); - pFrm->Prt().Width( pLay->Prt().Width() ); - if( ((SwSectionFrm*)pFrm)->Lower() && - ((SwSectionFrm*)pFrm)->Lower()->IsColumnFrm()) - { - const SwFmtCol &rCol = - ((SwSectionFrm*)pFrm)->GetFmt()->GetCol(); - ((SwSectionFrm*)pFrm)->AdjustColumns( - &rCol, FALSE ); - } - } - pActualSection->SetSectionFrm( (SwSectionFrm*)pFrm ); - pFrm->InsertBehind( pLay, 0 ); - pFrm->Frm().Pos() = pLay->Frm().Pos(); - pFrm->Frm().Pos().Y() += 1; //wg. Benachrichtigungen. - - pLay = (SwLayoutFrm*)pFrm; - if ( pLay->Lower() && pLay->Lower()->IsLayoutFrm() ) - pLay = pLay->GetNextLayoutLeaf(); - } - } - } - bFirst = FALSE; - } pFrm->InsertBehind( pLay, pPrv ); pFrm->Frm().Pos() = pLay->Frm().Pos(); pFrm->Frm().Pos().Y() += 1; //wg. Benachrichtigungen. @@ -1321,66 +1120,9 @@ void MA_FASTCALL _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc, SwTableNode *pTblNode = (SwTableNode*)pNd; pFrm = pTblNode->MakeFrm(); - if ( bPages ) - { - //Fuer die Seiten zaehlt jede Zeile als ein Absatz. - SwFrm *pLow = ((SwTabFrm*)pFrm)->Lower(); - do - { ++nParagraphCnt; - pLow = pLow->GetNext(); - } while ( pLow ); - - if ( !bFirst || nEndIndex ) - { - if ( bFirst ) - nParagraphCnt = USHRT_MAX; - - if ( lcl_CheckInsertPage( pFrm, pPage, pLay, nParagraphCnt, - nMaxParaPerPage, bBreakAfter ) ) - { - pPrv = 0; - nParagraphCnt = 0; - if ( bPages && bStartPercent ) - ::SetProgressState( pPage->GetPhyPageNum(), pDoc->GetDocShell()); - - if ( pActualSection ) - { - //Hatte der SectionFrm ueberhaupt Inhalt? Wenn - //nicht kann er gleich umgehaengt werden. - SwFrm *pFrm; - if ( !pActualSection->GetSectionFrm()->ContainsCntnt()) - { - pFrm = pActualSection->GetSectionFrm(); - pFrm->Remove(); - } - else - { - pFrm = new SwSectionFrm( - *pActualSection->GetSectionFrm(), FALSE ); - pActualSection->GetSectionFrm()->SimpleFormat(); - pFrm->Frm().Width( pLay->Prt().Width() ); - pFrm->Prt().Width( pLay->Prt().Width() ); - if( ((SwSectionFrm*)pFrm)->Lower() && - ((SwSectionFrm*)pFrm)->Lower()->IsColumnFrm()) - { - const SwFmtCol &rCol = - ((SwSectionFrm*)pFrm)->GetFmt()->GetCol(); - ((SwSectionFrm*)pFrm)->AdjustColumns( - &rCol, FALSE ); - } - } - pActualSection->SetSectionFrm( (SwSectionFrm*)pFrm ); - pFrm->InsertBehind( pLay, 0 ); - pFrm->Frm().Pos() = pLay->Frm().Pos(); - pFrm->Frm().Pos().Y() += 1; //wg. Benachrichtigungen. - - pLay = (SwLayoutFrm*)pFrm; - if ( pLay->Lower() && pLay->Lower()->IsLayoutFrm() ) - pLay = pLay->GetNextLayoutLeaf(); - } - } - } - } + if( pPageMaker && pPageMaker->CheckInsert( nIndex ) + && bStartPercent ) + ::SetProgressState( pPage->GetPhyPageNum(),pDoc->GetDocShell()); pFrm->InsertBehind( pLay, pPrv ); if ( bObjsDirect && pTbl->Count() ) @@ -1540,6 +1282,20 @@ void MA_FASTCALL _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc, ::EndProgress( pDoc->GetDocShell() ); } + if( pPageMaker ) + { + delete pPageMaker; + if( pDoc->GetLayoutCache() ) + { +#ifndef PRODUCT +#ifdef DEBUG + pDoc->GetLayoutCache()->CompareLayout( *pDoc ); +#endif +#endif + pDoc->GetLayoutCache()->ClearImpl(); + } + } + if ( bOldIdle ) pDoc->StartIdleTimer(); pDoc->GetRootFrm()->SetCallbackActionEnabled( bOldCallbackActionEnabled ); @@ -1561,9 +1317,6 @@ void MakeFrms( SwDoc *pDoc, const SwNodeIndex &rSttIdx, SwFrm* pFrm; while( 0 != (pFrm = aNode2Layout.NextFrm()) ) { - //Fuer klare Verhaeltnisse sorgen. Wenn ein Prev da ist - //alle Nachfolger von diesem auf die folgenden Seite - //schieben SwLayoutFrm *pUpper = pFrm->GetUpper(); SwFtnFrm* pFtnFrm = pUpper->FindFtnFrm(); BOOL bOldLock, bOldFtn; @@ -1587,11 +1340,15 @@ void MakeFrms( SwDoc *pDoc, const SwNodeIndex &rSttIdx, } else bOldLock = TRUE; + +#ifndef PRODUCT +#ifdef DEBUG // Wenn pFrm sich nicht bewegen kann, koennen wir auch niemanden // auf die naechste Seite schieben. Innerhalb eines Rahmens auch // nicht ( in der 1. Spalte eines Rahmens waere pFrm Moveable()! ) // Auch in spaltigen Bereichen in Tabellen waere pFrm Moveable. - if ( !pFrm->IsInFly() && pFrm->IsMoveable() && + static BOOL bTest = FALSE; + if ( bTest && !pFrm->IsInFly() && pFrm->IsMoveable() && (!pFrm->IsInTab() || pFrm->IsTabFrm() ) ) { SwFrm *pMove = pFrm; @@ -1697,6 +1454,8 @@ void MakeFrms( SwDoc *pDoc, const SwNodeIndex &rSttIdx, pFrm->IsInDocBody(), nEndIdx, pPrev ); } else +#endif +#endif { BOOL bSplit; SwFrm* pPrv = bApres ? pFrm : pFrm->GetPrev(); diff --git a/sw/source/core/layout/laycache.cxx b/sw/source/core/layout/laycache.cxx new file mode 100644 index 000000000000..349a6f8ec3b1 --- /dev/null +++ b/sw/source/core/layout/laycache.cxx @@ -0,0 +1,1039 @@ +/************************************************************************* + * + * $RCSfile: laycache.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: ama $ $Date: 2001-05-29 12:40:11 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifdef PRECOMPILED +#include "core_pch.hxx" +#endif + +#pragma hdrstop + +#include <hintids.hxx> +#ifndef _SVX_BRKITEM_HXX //autogen +#include <svx/brkitem.hxx> +#endif +#ifndef _STREAM_HXX //autogen +#include <tools/stream.hxx> +#endif +#ifndef _DOC_HXX +#include <doc.hxx> +#endif +#ifndef _DOCSTAT_HXX //autogen +#include <docstat.hxx> +#endif +#ifndef _DOCARY_HXX +#include <docary.hxx> +#endif +#ifndef _FMTPDSC_HXX //autogen +#include <fmtpdsc.hxx> +#endif +#ifndef _LAYCACHE_HXX +#include <laycache.hxx> +#endif +#ifndef _LAYHELP_HXX +#include <layhelp.hxx> +#endif +#ifndef _PAGEFRM_HXX +#include <pagefrm.hxx> +#endif +#ifndef _ROOTFRM_HXX +#include <rootfrm.hxx> +#endif +#ifndef _TXTFRM_HXX +#include <txtfrm.hxx> +#endif +#ifndef _NDTXT_HXX +#include <ndtxt.hxx> +#endif +#ifndef _SWTABLE_HXX +#include <swtable.hxx> +#endif +#ifndef _TABFRM_HXX +#include <tabfrm.hxx> +#endif +#ifndef _ROWFRM_HXX +#include <rowfrm.hxx> +#endif +#ifndef _COLFRM_HXX +#include <colfrm.hxx> +#endif +#ifndef _BODYFRM_HXX +#include <bodyfrm.hxx> +#endif +#ifndef _NODE_HXX //autogen +#include <node.hxx> +#endif +#ifndef _NDINDEX_HXX +#include <ndindex.hxx> +#endif +#ifndef _SECTFRM_HXX +#include <sectfrm.hxx> +#endif +#ifndef _FRMFMT_HXX //autogen +#include <frmfmt.hxx> +#endif +#ifndef _FMTCNTNT_HXX //autogen +#include <fmtcntnt.hxx> +#endif +#ifndef _PAGEDESC_HXX +#include <pagedesc.hxx> +#endif +#ifndef _FRMTOOL_HXX +#include <frmtool.hxx> +#endif + +/*-----------------28.5.2001 10:06------------------ + * Reading and writing of the layout cache. + * The layout cache is not necessary, but it improves + * the performance and reduces the text flow during + * the formatting. + * The layout cache contains the index of the paragraphs/tables + * at the top of every page, so it's possible to create + * the right count of pages and to distribute the document content + * to this pages before the formatting starts. + *--------------------------------------------------*/ + +void SwLayoutCache::Read( SvStream &rStream ) +{ + if( !pImpl ) + { + pImpl = new SwLayCacheImpl; + if( !pImpl->Read( rStream ) ) + { + delete pImpl; + pImpl = 0; + } + } +} + +//----------------------------------------------------------------------------- + +void SwLayCacheImpl::Insert( USHORT nType, ULONG nIndex, xub_StrLen nOffset ) +{ + aType.Insert( nType, aType.Count() ); + SvULongs::Insert( nIndex, SvULongs::Count() ); + aOffset.Insert( nOffset, aOffset.Count() ); +} + +BOOL SwLayCacheImpl::Read( SvStream& rStream ) +{ + SwLayCacheIoImpl aIo( rStream, FALSE ); + if( aIo.GetMajorVersion() > SW_LAYCACHE_IO_VERSION_MAJOR ) + return FALSE; + + BYTE cFlags; + UINT32 nIndex, nOffset; + + aIo.OpenRec( SW_LAYCACHE_IO_REC_PAGES ); + aIo.OpenFlagRec(); + aIo.CloseFlagRec(); + while( aIo.BytesLeft() && !aIo.HasError() ) + { + switch( aIo.Peek() ) + { + case SW_LAYCACHE_IO_REC_PARA: + aIo.OpenRec( SW_LAYCACHE_IO_REC_PARA ); + cFlags = aIo.OpenFlagRec(); + aIo.GetStream() >> nIndex; + if( (cFlags & 0x01) != 0 ) + aIo.GetStream() >> nOffset; + else + nOffset = STRING_LEN; + aIo.CloseFlagRec(); + Insert( SW_LAYCACHE_IO_REC_PARA, nIndex, (xub_StrLen)nOffset ); + aIo.CloseRec( SW_LAYCACHE_IO_REC_PARA ); + break; + case SW_LAYCACHE_IO_REC_TABLE: + aIo.OpenRec( SW_LAYCACHE_IO_REC_TABLE ); + aIo.OpenFlagRec(); + aIo.GetStream() >> nIndex + >> nOffset; + Insert( SW_LAYCACHE_IO_REC_TABLE, nIndex, (xub_StrLen)nOffset ); + aIo.CloseFlagRec(); + aIo.CloseRec( SW_LAYCACHE_IO_REC_TABLE ); + break; + default: + aIo.SkipRec(); + break; + } + } + aIo.CloseRec( SW_LAYCACHE_IO_REC_PAGES ); + + return !aIo.HasError(); +} + +/*-----------------28.5.2001 10:19------------------ + * SwLayoutCache::Write(..) + * writes the index (more precise: the difference between + * the index and the first index of the document content) + * of the first paragraph/table at the top of every page. + * If at the top of a page is the rest of a paragraph/table + * from the bottom of the previous page, the character/row + * number is stored, too. + * --------------------------------------------------*/ + +void SwLayoutCache::Write( SvStream &rStream, const SwDoc& rDoc ) +{ + if( rDoc.GetRootFrm() ) // the layout itself .. + { + SwLayCacheIoImpl aIo( rStream, TRUE ); + // We want to save the relative index, so we need the index + // of the first content + ULONG nStartOfContent = rDoc.GetNodes().GetEndOfContent(). + FindStartNode()->GetIndex(); + // The first page.. + SwPageFrm* pPage = (SwPageFrm*)rDoc.GetRootFrm()->Lower(); + //.. is not very interesting, cause it's clear that the first + // page starts with the first paragraph/table, do we get the + if( pPage ) // second page + pPage = (SwPageFrm*)pPage->GetNext(); + + aIo.OpenRec( SW_LAYCACHE_IO_REC_PAGES ); + aIo.OpenFlagRec( 0, 0 ); + aIo.CloseFlagRec(); + while( pPage ) + { + SwLayoutFrm* pLay = pPage->FindBodyCont(); + SwFrm* pTmp = pLay ? pLay->ContainsAny() : NULL; + // We are only interested in paragraph or table frames, + // a section frames contains paragraphs/tables. + if( pTmp && pTmp->IsSctFrm() ) + pTmp = ((SwSectionFrm*)pTmp)->ContainsAny(); + + if( pTmp ) // any content + { + if( pTmp->IsTxtFrm() ) + { + ULONG nNdIdx = ((SwTxtFrm*)pTmp)->GetNode()->GetIndex(); + if( nNdIdx > nStartOfContent ) + { + /* Open Paragraph Record */ + aIo.OpenRec( SW_LAYCACHE_IO_REC_PARA ); + BOOL bFollow = ((SwTxtFrm*)pTmp)->IsFollow(); + aIo.OpenFlagRec( bFollow ? 0x01 : 0x00, + bFollow ? 8 : 4 ); + nNdIdx -= nStartOfContent; + aIo.GetStream() << nNdIdx; + if( bFollow ) + aIo.GetStream() << (ULONG)((SwTxtFrm*)pTmp)->GetOfst(); + aIo.CloseFlagRec(); + /* Close Paragraph Record */ + aIo.CloseRec( SW_LAYCACHE_IO_REC_PARA ); + } + } + else if( pTmp->IsTabFrm() ) + { + SwTabFrm* pTab = (SwTabFrm*)pTmp; + ULONG nOfst = STRING_LEN; + if( pTab->IsFollow() ) + { + // If the table is a follow, we have to look for the + // master and to count all rows to get the row number + nOfst = 0; + while( pTab->IsFollow() ) + pTab = pTab->FindMaster(); + while( pTab != pTmp ) + { + SwFrm* pSub = pTab->Lower(); + while( pSub ) + { + ++nOfst; + pSub = pSub->GetNext(); + } + pTab = pTab->GetFollow(); + ASSERT( pTab, "Table follow without master" ); + } + } + do + { + ULONG nNdIdx = + pTab->GetTable()->GetTableNode()->GetIndex(); + if( nNdIdx > nStartOfContent ) + { + /* Open Table Record */ + aIo.OpenRec( SW_LAYCACHE_IO_REC_TABLE ); + aIo.OpenFlagRec( 0, 8 ); + nNdIdx -= nStartOfContent; + aIo.GetStream() << nNdIdx + << nOfst; + aIo.CloseFlagRec(); + /* Close Table Record */ + aIo.CloseRec( SW_LAYCACHE_IO_REC_TABLE ); + } + // If the table has a follow on the next page, + // we know already the row number and store this + // immediately. + if( pTab->GetFollow() ) + { + if( nOfst == STRING_LEN ) + nOfst = 0; + do + { + SwFrm* pSub = pTab->Lower(); + while( pSub ) + { + ++nOfst; + pSub = pSub->GetNext(); + } + pTab = pTab->GetFollow(); + SwPageFrm *pTabPage = pTab->FindPageFrm(); + if( pTabPage != pPage ) + { + ASSERT( pPage->GetPhyPageNum() < + pTabPage->GetPhyPageNum(), + "Looping Tableframes" ); + pPage = pTabPage; + break; + } + } while ( pTab->GetFollow() ); + } + else + break; + } while( pTab ); + } + } + pPage = (SwPageFrm*)pPage->GetNext(); + } + aIo.CloseRec( SW_LAYCACHE_IO_REC_PAGES ); + } +} + +#ifndef PRODUCT +sal_Bool SwLayoutCache::CompareLayout( const SwDoc& rDoc ) const +{ + sal_Bool bRet = sal_True; + if( pImpl && rDoc.GetRootFrm() ) + { + USHORT nIndex = 0; + ULONG nStartOfContent = rDoc.GetNodes().GetEndOfContent(). + FindStartNode()->GetIndex(); + SwPageFrm* pPage = (SwPageFrm*)rDoc.GetRootFrm()->Lower(); + if( pPage ) + pPage = (SwPageFrm*)pPage->GetNext(); + while( pPage ) + { + if( nIndex >= pImpl->Count() ) + { + if( bRet ) + bRet = sal_False; + break; + } + SwLayoutFrm* pLay = pPage->FindBodyCont(); + SwFrm* pTmp = pLay ? pLay->ContainsAny() : NULL; + if( pTmp && pTmp->IsSctFrm() ) + pTmp = ((SwSectionFrm*)pTmp)->ContainsAny(); + if( pTmp ) + { + if( pTmp->IsTxtFrm() ) + { + ULONG nNdIdx = ((SwTxtFrm*)pTmp)->GetNode()->GetIndex(); + if( nNdIdx > nStartOfContent ) + { + BOOL bFollow = ((SwTxtFrm*)pTmp)->IsFollow(); + nNdIdx -= nStartOfContent; + if( pImpl->GetBreakIndex( nIndex ) != nNdIdx || + SW_LAYCACHE_IO_REC_PARA != + pImpl->GetBreakType( nIndex ) || + ( bFollow ? ((SwTxtFrm*)pTmp)->GetOfst() + : STRING_LEN ) != pImpl->GetBreakOfst( nIndex ) ) + { + if( bRet ) + bRet = sal_False; + } + ++nIndex; + } + } + else if( pTmp->IsTabFrm() ) + { + SwTabFrm* pTab = (SwTabFrm*)pTmp; + ULONG nOfst = STRING_LEN; + if( pTab->IsFollow() ) + { + nOfst = 0; + while( pTab->IsFollow() ) + pTab = pTab->FindMaster(); + while( pTab != pTmp ) + { + SwFrm* pSub = pTab->Lower(); + while( pSub ) + { + ++nOfst; + pSub = pSub->GetNext(); + } + pTab = pTab->GetFollow(); + } + } + do + { + ULONG nNdIdx = + pTab->GetTable()->GetTableNode()->GetIndex(); + if( nNdIdx > nStartOfContent ) + { + nNdIdx -= nStartOfContent; + if( pImpl->GetBreakIndex( nIndex ) != nNdIdx || + SW_LAYCACHE_IO_REC_TABLE != + pImpl->GetBreakType( nIndex ) || + nOfst != pImpl->GetBreakOfst( nIndex ) ) + { + if( bRet ) + bRet = sal_False; + } + ++nIndex; + } + if( pTab->GetFollow() ) + { + if( nOfst == STRING_LEN ) + nOfst = 0; + do + { + SwFrm* pSub = pTab->Lower(); + while( pSub ) + { + ++nOfst; + pSub = pSub->GetNext(); + } + pTab = pTab->GetFollow(); + SwPageFrm *pTabPage = pTab->FindPageFrm(); + if( pTabPage != pPage ) + { + pPage = pTabPage; + break; + } + } while ( pTab->GetFollow() ); + } + else + break; + } while( pTab ); + } + } + pPage = (SwPageFrm*)pPage->GetNext(); + } + } + return bRet; +} +#endif + +void SwLayoutCache::ClearImpl() +{ + if( !IsLocked() ) + { + delete pImpl; + pImpl = 0; + } +} + + +SwLayoutCache::~SwLayoutCache() +{ + ASSERT( !nLockCount, "Deleting a locked SwLayoutCache!?" ); + delete pImpl; +} + +/*-----------------28.5.2001 10:47------------------ + * SwActualSection, + * a help class to create not nested section frames + * for nested sections. + * --------------------------------------------------*/ + +SwActualSection::SwActualSection( SwActualSection *pUp, + SwSectionFrm *pSect, + SwSectionNode *pNd ) : + pUpper( pUp ), + pSectFrm( pSect ), + pSectNode( pNd ) +{ + if ( !pSectNode ) + { + const SwNodeIndex *pIndex = pSect->GetFmt()->GetCntnt().GetCntntIdx(); + pSectNode = pSect->GetFmt()->GetDoc()->GetNodes()[*pIndex]-> + FindSectionNode(); + } +} + +/*-----------------28.5.2001 11:09------------------ + * SwLayHelper + * is the helper class, which utilizes the layout cache information + * to distribute the document content to the rigth pages. + * It's used by the _InsertCnt(..)-function. + * If there's no layout cache, the distibution to the pages is more + * a guess, but a guess with statistical background. + * --------------------------------------------------*/ + +SwLayHelper::SwLayHelper( SwDoc *pD, SwFrm* &rpF, SwFrm* &rpP, SwPageFrm* &rpPg, + SwLayoutFrm* &rpL, SwActualSection* &rpA, BOOL &rB, + ULONG nNodeIndex, BOOL bCache ) + : rpFrm( rpF ), rpPrv( rpP ), rpPage( rpPg ), rpLay( rpL ), + rpActualSection( rpA ), rbBreakAfter(rB), pDoc(pD), nMaxParaPerPage( 25 ), + nParagraphCnt( bCache ? 0 : USHRT_MAX ), bFirst( bCache ) +{ + pImpl = pDoc->GetLayoutCache() ? pDoc->GetLayoutCache()->LockImpl() : NULL; + if( pImpl ) + { + nStartOfContent = pDoc->GetNodes().GetEndOfContent().FindStartNode() + ->GetIndex(); + nNodeIndex -= nStartOfContent; + nIndex = 0; + while( nIndex < pImpl->Count() && (*pImpl)[ nIndex ] < nNodeIndex ) + ++nIndex; + if( nIndex >= pImpl->Count() ) + { + pDoc->GetLayoutCache()->UnlockImpl(); + pImpl = NULL; + } + } + else + { + pImpl = NULL; + nIndex = USHRT_MAX; + nStartOfContent = ULONG_MAX; + } +} + +SwLayHelper::~SwLayHelper() +{ + if( pImpl ) + { + ASSERT( pDoc && pDoc->GetLayoutCache(), "Missing layoutcache" ); + pDoc->GetLayoutCache()->UnlockImpl(); + } +} + +/*-----------------23.5.2001 16:40------------------ + * SwLayHelper::CalcPageCount() does not really calculate the page count, + * it returns the page count value from the layout cache, if available, + * otherwise it estimates the page count. + * --------------------------------------------------*/ + +ULONG SwLayHelper::CalcPageCount() +{ + ULONG nPgCount; + SwLayCacheImpl *pCache = pDoc->GetLayoutCache() ? + pDoc->GetLayoutCache()->LockImpl() : NULL; + if( pCache ) + { + nPgCount = pCache->Count() + 1; + pDoc->GetLayoutCache()->UnlockImpl(); + } + else + { + nPgCount = pDoc->GetDocStat().nPage; + if ( nPgCount <= 10 ) // no page insertion for less than 10 pages + nPgCount = 0; + ULONG nNdCount = pDoc->GetDocStat().nPara; + if ( nNdCount <= 1 ) + { + //Estimates the number of paragraphs. + ULONG nTmp = pDoc->GetNodes().GetEndOfContent().GetIndex() - + pDoc->GetNodes().GetEndOfExtras().GetIndex(); + //Tables have a little overhead.. + nTmp -= pDoc->GetTblFrmFmts()->Count() * 25; + //Fly frames, too .. + nTmp -= (pDoc->GetNodes().GetEndOfAutotext().GetIndex() - + pDoc->GetNodes().GetEndOfInserts().GetIndex()) / 3 * 5; + if ( nTmp > 0 ) + nNdCount = nTmp; + } + if ( nNdCount > 100 ) // no estimation below this value + { + if ( nPgCount > 0 ) + nMaxParaPerPage = nNdCount / nPgCount; + else + { + nMaxParaPerPage = Max( ULONG(20), + ULONG(20 + nNdCount / 1000 * 3) ); +#ifdef PM2 + const ULONG nMax = 49; +#elif MAC + const ULONG nMax = 56; +#elif UNIX + const ULONG nMax = 57; +#else + const ULONG nMax = 53; +#endif + nMaxParaPerPage = Min( nMaxParaPerPage, nMax ); + nPgCount = nNdCount / nMaxParaPerPage; + } + if ( nNdCount < 1000 ) + nPgCount = 0;// no progress bar for small documents + if ( pDoc->IsBrowseMode() ) + nMaxParaPerPage *= 6; + } + } + return nPgCount; +} + +/*-----------------23.5.2001 16:44------------------ + * SwLayHelper::CheckInsertPage() + * inserts a page and return TRUE, if + * - the break after flag is set + * - the actual content wants a break before + * - the maximum count of paragraph/rows is reached + * + * The break after flag is set, if the actual content + * wants a break after. + * --------------------------------------------------*/ + +BOOL SwLayHelper::CheckInsertPage() +{ + FASTBOOL bEnd = 0 == rpPage->GetNext(); + const SwAttrSet *pAttr = rpFrm->GetAttrSet(); + const SvxFmtBreakItem &rBrk = pAttr->GetBreak(); + const SwFmtPageDesc &rDesc = pAttr->GetPageDesc(); + const SwPageDesc *pDesc = rDesc.GetPageDesc(); + + BOOL bBrk = nParagraphCnt > nMaxParaPerPage || rbBreakAfter; + rbBreakAfter = rBrk.GetBreak() == SVX_BREAK_PAGE_AFTER || + rBrk.GetBreak() == SVX_BREAK_PAGE_BOTH; + if ( !bBrk ) + bBrk = rBrk.GetBreak() == SVX_BREAK_PAGE_BEFORE || + rBrk.GetBreak() == SVX_BREAK_PAGE_BOTH; + + if ( bBrk || pDesc ) + { + USHORT nPgNum = 0; + if ( !pDesc ) + pDesc = rpPage->GetPageDesc()->GetFollow(); + else + { + if ( 0 != (nPgNum = rDesc.GetNumOffset()) ) + ((SwRootFrm*)rpPage->GetUpper())->SetVirtPageNum(TRUE); + } + BOOL bOdd = !rpPage->OnRightPage(); + BOOL bInsertEmpty = FALSE; + if( nPgNum && bOdd != ( ( nPgNum % 2 ) != 0 ) ) + { + bOdd = !bOdd; + bInsertEmpty = TRUE; + } + ::InsertNewPage( (SwPageDesc&)*pDesc, rpPage->GetUpper(), + bOdd, bInsertEmpty, FALSE, rpPage->GetNext() ); + if ( bEnd ) + { + ASSERT( rpPage->GetNext(), "Keine neue Seite?" ); + do + { rpPage = (SwPageFrm*)rpPage->GetNext(); + } while ( rpPage->GetNext() ); + } + else + { + ASSERT( rpPage->GetNext(), "Keine neue Seite?" ); + rpPage = (SwPageFrm*)rpPage->GetNext(); + if ( rpPage->IsEmptyPage() ) + { + ASSERT( rpPage->GetNext(), "Keine neue Seite?" ); + rpPage = (SwPageFrm*)rpPage->GetNext(); + } + } + rpLay = rpPage->FindBodyCont(); + while( rpLay->Lower() ) + rpLay = (SwLayoutFrm*)rpLay->Lower(); + return TRUE; + } + return FALSE; +} + +/*-----------------28.5.2001 11:31------------------ + * SwLayHelper::CheckInsert + * is the entry point for the _InsertCnt-function. + * The document content index is checked either it is + * in the layout cache either it's time to insert a page + * cause the maximal estimation of content per page is reached. + * A really big table or long paragraph may contains more than + * one page, in this case the needed count of pages will inserted. + * --------------------------------------------------*/ + +BOOL SwLayHelper::CheckInsert( ULONG nNodeIndex ) +{ + BOOL bRet = FALSE; + nNodeIndex -= nStartOfContent; + USHORT nRows; + if( rpFrm->IsTabFrm() ) + { + //Inside a table counts every row as a paragraph + SwFrm *pLow = ((SwTabFrm*)rpFrm)->Lower(); + nRows = 0; + do + { + ++nRows; + pLow = pLow->GetNext(); + } while ( pLow ); + nParagraphCnt += nRows; + } + else + ++nParagraphCnt; + if( bFirst && pImpl && nIndex < pImpl->Count() && + pImpl->GetBreakIndex( nIndex ) == nNodeIndex && + ( pImpl->GetBreakOfst( nIndex ) < STRING_LEN || + ( ++nIndex < pImpl->Count() && + pImpl->GetBreakIndex( nIndex ) == nNodeIndex ) ) ) + bFirst = FALSE; + if( !bFirst ) + { + ULONG nRowCount = 0; + do + { + if( pImpl ) + { + xub_StrLen nOfst = STRING_LEN; + USHORT nType = SW_LAYCACHE_IO_REC_PAGES; + while( nIndex < pImpl->Count() && + pImpl->GetBreakIndex(nIndex) < nNodeIndex) + nIndex += 2; + if( nIndex < pImpl->Count() && + pImpl->GetBreakIndex(nIndex) == nNodeIndex ) + { + nType = pImpl->GetBreakType( nIndex ); + nOfst = pImpl->GetBreakOfst( nIndex++ ); + rbBreakAfter = sal_True; + } + if( nOfst < STRING_LEN ) + { + sal_Bool bSplit = sal_False; + sal_Bool bRepeat; + if( rpFrm->IsTxtFrm() && SW_LAYCACHE_IO_REC_PARA == nType && + nOfst<((SwTxtFrm*)rpFrm)->GetTxtNode()->GetTxt().Len() ) + bSplit = sal_True; + else if( rpFrm->IsTabFrm() && nRowCount < nOfst && + SW_LAYCACHE_IO_REC_TABLE == nType ) + { + bRepeat = ((SwTabFrm*)rpFrm)-> + GetTable()->IsHeadlineRepeat(); + bSplit = nOfst < nRows; + } + if( bSplit ) + { + rpFrm->InsertBehind( rpLay, rpPrv ); + rpFrm->Frm().Pos() = rpLay->Frm().Pos(); + rpFrm->Frm().Pos().Y() += 1; + rpPrv = rpFrm; + if( rpFrm->IsTabFrm() ) + { + SwTabFrm* pTab = (SwTabFrm*)rpFrm; + SwFrm *pRow = pTab->Lower(); + SwTabFrm *pFoll = new SwTabFrm( *pTab ); + + SwFrm *pPrv; + if( bRepeat ) + { + bDontCreateObjects = TRUE; //frmtool + SwRowFrm *pHeadline = new SwRowFrm( + *pTab->GetTable()->GetTabLines()[0] ); + pHeadline->InsertBefore( pFoll, 0 ); + bDontCreateObjects = FALSE; + pPrv = pFoll->Lower(); + ++nRows; + } + else + pPrv = 0; + while( pRow && nRowCount < nOfst ) + { + pRow = pRow->GetNext(); + ++nRowCount; + } + while ( pRow ) + { + SwFrm* pNxt = pRow->GetNext(); + pRow->Remove(); + pRow->InsertBehind( pFoll, pPrv ); + pPrv = pRow; + pRow = pNxt; + } + rpFrm = pFoll; + } + else + { + SwTxtFrm *pNew = new SwTxtFrm( ((SwTxtFrm*)rpFrm)-> + GetTxtNode() ); + pNew->_SetIsFollow( sal_True ); + pNew->ManipOfst( nOfst ); + pNew->SetFollow( ((SwTxtFrm*)rpFrm)->GetFollow() ); + ((SwTxtFrm*)rpFrm)->SetFollow( pNew ); + rpFrm = pNew; + } + } + } + +#ifndef DEBUG + if( nIndex >= pImpl->Count() ) + { + pImpl = NULL; + Cache()->UnlockImpl(); + } +#endif + } + + if( CheckInsertPage() ) + { + if( rpPrv && rpPrv->IsTxtFrm() && !rpPrv->GetValidSizeFlag() ) + rpPrv->Frm().Height( rpPrv->GetUpper()->Prt().Height() ); + + bRet = TRUE; + rpPrv = 0; + nParagraphCnt = 0; + + if ( rpActualSection ) + { + //Hatte der SectionFrm ueberhaupt Inhalt? Wenn + //nicht kann er gleich umgehaengt werden. + SwSectionFrm *pSct; + if ( !rpActualSection->GetSectionFrm()->ContainsCntnt()) + { + pSct = rpActualSection->GetSectionFrm(); + pSct->Remove(); + } + else + { + pSct = new SwSectionFrm( + *rpActualSection->GetSectionFrm(), FALSE ); + rpActualSection->GetSectionFrm()->SimpleFormat(); + pSct->Frm().Width( rpLay->Prt().Width() ); + pSct->Prt().Width( rpLay->Prt().Width() ); + } + rpActualSection->SetSectionFrm( pSct ); + pSct->InsertBehind( rpLay, 0 ); + pSct->Frm().Pos() = rpLay->Frm().Pos(); + pSct->Frm().Pos().Y() += 1; //wg. Benachrichtigungen. + + rpLay = pSct; + if ( rpLay->Lower() && rpLay->Lower()->IsLayoutFrm() ) + rpLay = rpLay->GetNextLayoutLeaf(); + } + } + } while( pImpl && nIndex < pImpl->Count() && + (*pImpl)[ nIndex ] == nNodeIndex ); + } + bFirst = FALSE; + return bRet; +} + +// ----------------------------------------------------------------------------- + +SwLayCacheIoImpl::SwLayCacheIoImpl( SvStream& rStrm, BOOL bWrtMd ) : + pStream( &rStrm ), + nMajorVersion(SW_LAYCACHE_IO_VERSION_MAJOR), + nMinorVersion(SW_LAYCACHE_IO_VERSION_MINOR), + bWriteMode( bWrtMd ), + bError( FALSE ) +{ + if( bWriteMode ) + *pStream << nMajorVersion + << nMinorVersion; + + else + *pStream >> nMajorVersion + >> nMinorVersion; +} + +BOOL SwLayCacheIoImpl::OpenRec( BYTE cType ) +{ + BOOL bRes = TRUE; + UINT16 nLvl = aRecTypes.Count(); + ASSERT( nLvl == aRecSizes.Count(), "OpenRec: Level" ); + UINT32 nPos = pStream->Tell(); + if( bWriteMode ) + { + aRecTypes.Insert( cType, nLvl ); + aRecSizes.Insert( nPos, nLvl ); + *pStream << (UINT32) 0; + } + else + { + UINT32 nVal; + *pStream >> nVal; + BYTE cRecTyp = (BYTE)nVal; + aRecTypes.Insert( cRecTyp, nLvl ); + sal_uInt32 nSize = nVal >> 8; + aRecSizes.Insert( nPos + nSize, nLvl ); + if( !nVal || cRecTyp != cType || + pStream->GetErrorCode() != SVSTREAM_OK || pStream->IsEof() ) + { + ASSERT( nVal, "OpenRec: Record-Header is 0" ); + ASSERT( cRecTyp == cType, + "OpenRec: Wrong Record Type" ); + aRecTypes[nLvl] = 0; + aRecSizes[nLvl] = pStream->Tell(); + bRes = sal_False; + bError = TRUE; + } + } + return bRes; +} + +// Close record + +BOOL SwLayCacheIoImpl::CloseRec( BYTE cType ) +{ + BOOL bRes = TRUE; + UINT16 nLvl = aRecTypes.Count(); + ASSERT( nLvl == aRecSizes.Count(), "CloseRec: wrong Level" ); + ASSERT( nLvl, "CloseRec: no levels" ); + if( nLvl ) + { + nLvl--; + ASSERT( cType == aRecTypes[nLvl], + "CloseRec: Wrong Block-Header" ); + UINT32 nPos = pStream->Tell(); + if( bWriteMode ) + { + UINT32 nBgn = aRecSizes[nLvl]; + pStream->Seek( nBgn ); + UINT32 nSize = nPos - nBgn; + UINT32 nVal = ( nSize << 8 ) | aRecTypes[nLvl]; + *pStream << nVal; + pStream->Seek( nPos ); + if( pStream->GetError() != SVSTREAM_OK ) + bRes = FALSE; + } + else + { + UINT32 n = aRecSizes[nLvl]; + ASSERT( n >= nPos, "CloseRec: to much data read" ); + if( n != nPos ) + { + pStream->Seek( n ); + if( n < nPos ) + bRes = FALSE; + } + if( pStream->GetErrorCode() != SVSTREAM_OK ) + bRes = FALSE; + } + + aRecTypes.Remove( nLvl, 1 ); + aRecSizes.Remove( nLvl, 1 ); + } + + if( !bRes ) + bError = TRUE; + + return bRes; +} + +UINT32 SwLayCacheIoImpl::BytesLeft() +{ + UINT16 nLvl = aRecSizes.Count(); + UINT32 n = 0; + if( !bError && nLvl ) + { + UINT32 nEndPos = aRecSizes[ nLvl-1 ]; + UINT32 nPos = pStream->Tell(); + if( nEndPos > nPos ) + n = nEndPos - nPos; + } + + return n; +} + +BYTE SwLayCacheIoImpl::Peek() +{ + BYTE c = 0; + if( !bError ) + { + UINT32 nPos = pStream->Tell(); + *pStream >> c; + pStream->Seek( nPos ); + if( pStream->GetErrorCode() != SVSTREAM_OK ) + { + c = 0; + bError = TRUE; + } + } + return c; +} + +void SwLayCacheIoImpl::SkipRec() +{ + BYTE c = Peek(); + OpenRec( c ); + pStream->Seek( aRecSizes[aRecSizes.Count()-1] ); + CloseRec( c ); +} + +BYTE SwLayCacheIoImpl::OpenFlagRec() +{ + ASSERT( !bWriteMode, "OpenFlagRec illegal in write mode" ); + BYTE cFlags; + *pStream >> cFlags; + nFlagRecEnd = pStream->Tell() + ( cFlags & 0x0F ); + return (cFlags >> 4); +} + +void SwLayCacheIoImpl::OpenFlagRec( BYTE nFlags, BYTE nLen ) +{ + ASSERT( bWriteMode, "OpenFlagRec illegal in read mode" ); + ASSERT( (nFlags & 0xF0) == 0, "illegal flags set" ); + ASSERT( nLen < 16, "wrong flag record length" ); + BYTE cFlags = (nFlags << 4) + nLen; + *pStream << cFlags; + nFlagRecEnd = pStream->Tell() + nLen; +} + +void SwLayCacheIoImpl::CloseFlagRec() +{ + if( bWriteMode ) + { + ASSERT( pStream->Tell() == nFlagRecEnd, "Wrong amount of data written" ); + } + else + { + ASSERT( pStream->Tell() <= nFlagRecEnd, "To many data read" ); + if( pStream->Tell() != nFlagRecEnd ) + pStream->Seek( nFlagRecEnd ); + } +} diff --git a/sw/source/core/layout/layhelp.hxx b/sw/source/core/layout/layhelp.hxx new file mode 100644 index 000000000000..e47784a9e24b --- /dev/null +++ b/sw/source/core/layout/layhelp.hxx @@ -0,0 +1,233 @@ +/************************************************************************* + * + * $RCSfile: layhelp.hxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: ama $ $Date: 2001-05-29 12:41:00 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#ifndef _LAYHELP_HXX +#define _LAYHELP_HXX + +#ifndef _SVSTDARR_HXX +#define _SVSTDARR_USHORTS +#define _SVSTDARR_ULONGS +#define _SVSTDARR_BYTES +#define _SVSTDARR_XUB_STRLEN +#include <svtools/svstdarr.hxx> +#endif + +class SwDoc; +class SwFrm; +class SwLayoutFrm; +class SwPageFrm; +class SwSectionFrm; +class SwSectionNode; +class SwLayoutCache; +class SvStream; + +/************************************************************************* + * class SwLayCacheImpl + * contains the page break information of the document (after loading) + * and is used inside the constructor of the layout rootframe to + * insert content at the right pages. + * For every page of the main text (body content, no footnotes, text frames etc.) + * we have the nodeindex of the first content at the page, + * the type of content ( table or paragraph ) + * and if it's not the first part of the table/paragraph, + * the row/character-offset inside the table/paragraph. + *************************************************************************/ + +class SwLayCacheImpl : public SvULongs +{ + SvXub_StrLens aOffset; + SvUShorts aType; + + void Insert( USHORT nType, ULONG nIndex, xub_StrLen nOffset ); + +public: + SwLayCacheImpl() : SvULongs( 20, 10 ), aOffset( 20, 10 ), aType( 20, 10 ) {} + BOOL Read( SvStream& rStream ); + + ULONG GetBreakIndex( USHORT nIdx ) const { return GetObject( nIdx ); } + xub_StrLen GetBreakOfst( USHORT nIdx ) const { return aOffset[ nIdx ]; } + USHORT GetBreakType( USHORT nIdx ) const { return aType[ nIdx ]; } +}; + +/************************************************************************* + * class SwActualSection + * helps to create the sectionframes during the _InsertCnt-function + * by controlling nested sections. + *************************************************************************/ + +class SwActualSection +{ + SwActualSection *pUpper; + SwSectionFrm *pSectFrm; + SwSectionNode *pSectNode; +public: + SwActualSection( SwActualSection *pUpper, + SwSectionFrm *pSect, + SwSectionNode *pNd ); + + SwSectionFrm *GetSectionFrm() { return pSectFrm; } + void SetSectionFrm( SwSectionFrm *p ) { pSectFrm = p; } + SwSectionNode *GetSectionNode() { return pSectNode;} + SwActualSection *GetUpper() { return pUpper; } +}; + +/************************************************************************* + * class SwLayHelper + * helps during the _InsertCnt-function to create new pages. + * If there's a layoutcache available, this information is used. + *************************************************************************/ + +class SwLayHelper +{ + SwFrm* &rpFrm; + SwFrm* &rpPrv; + SwPageFrm* &rpPage; + SwLayoutFrm* &rpLay; + SwActualSection* &rpActualSection; + BOOL &rbBreakAfter; + SwDoc* pDoc; + SwLayCacheImpl* pImpl; + ULONG nMaxParaPerPage; + ULONG nParagraphCnt; + ULONG nStartOfContent; + USHORT nIndex; + BOOL bFirst : 1; +public: + SwLayHelper( SwDoc *pD, SwFrm* &rpF, SwFrm* &rpP, SwPageFrm* &rpPg, + SwLayoutFrm* &rpL, SwActualSection* &rpA, BOOL &rBrk, + ULONG nNodeIndex, BOOL bCache ); + ~SwLayHelper(); + ULONG CalcPageCount(); + BOOL CheckInsert( ULONG nNodeIndex ); + + BOOL BreakPage( xub_StrLen& rOffs, ULONG nNodeIndex ); + BOOL CheckInsertPage(); + +}; + +/************************************************************************* + * class SwLayCacheIoImpl + * contains the data structures that are required to read and write a + * layout cache. + *************************************************************************/ + +#define SW_LAYCACHE_IO_REC_PAGES 'p' +#define SW_LAYCACHE_IO_REC_PARA 'P' +#define SW_LAYCACHE_IO_REC_TABLE 'T' + +#define SW_LAYCACHE_IO_VERSION_MAJOR 1 +#define SW_LAYCACHE_IO_VERSION_MINOR 0 + +class SwLayCacheIoImpl +{ + SvBytes aRecTypes; + SvULongs aRecSizes; + + SvStream *pStream; + + ULONG nFlagRecEnd; + + USHORT nMajorVersion; + USHORT nMinorVersion; + + BOOL bWriteMode : 1; + BOOL bError : 1; + +public: + SwLayCacheIoImpl( SvStream& rStrm, BOOL bWrtMd ); + + // Get input or output stream + SvStream& GetStream() const { return *pStream; } + + // Open a record of type "nType" + BOOL OpenRec( BYTE nType ); + + // Close a record of type "nType". This skips any unread data that + // remains in the record. + BOOL CloseRec( BYTE nType ); + + // Return the number of bytes contained in the current record that + // haven't been read by now. + UINT32 BytesLeft(); + + // Return the current record's type + BYTE Peek(); + + // Skip the current record + void SkipRec(); + + // Open a flag record for reading. The uppermost four bits are flags, + // while the lowermost are the flag record's size. Flag records cannot + // be nested. + BYTE OpenFlagRec(); + + // Open flag record for writing; + void OpenFlagRec( BYTE nFlags, BYTE nLen ); + + // Close a flag record. Any bytes left are skipped. + void CloseFlagRec(); + + BOOL HasError() const { return bError; } + + USHORT GetMajorVersion() const { return nMajorVersion; } + USHORT GetMinorVersion() const { return nMinorVersion; } +}; + +#endif diff --git a/sw/source/core/layout/makefile.mk b/sw/source/core/layout/makefile.mk index 3ecc152ebb29..9f343d18b93e 100644 --- a/sw/source/core/layout/makefile.mk +++ b/sw/source/core/layout/makefile.mk @@ -2,9 +2,9 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.2 $ +# $Revision: 1.3 $ # -# last change: $Author: cmc $ $Date: 2001-02-08 13:32:02 $ +# last change: $Author: ama $ $Date: 2001-05-29 12:38:15 $ # # The Contents of this file are made available subject to the terms of # either of the following licenses @@ -112,6 +112,7 @@ CXXFILES = \ ftnfrm.cxx \ hffrm.cxx \ layact.cxx \ + laycache.cxx \ layouter.cxx \ newfrm.cxx \ pagechg.cxx \ @@ -143,6 +144,7 @@ SLOFILES = \ $(SLO)$/ftnfrm.obj \ $(SLO)$/hffrm.obj \ $(SLO)$/layact.obj \ + $(SLO)$/laycache.obj \ $(SLO)$/layouter.obj \ $(SLO)$/newfrm.obj \ $(SLO)$/pagechg.obj \ |