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