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