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