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
SV_IMPL_PTRARR(SwPageFlyCache,SwFlyCachePtr)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
Insert(sal_uInt16 nType,sal_uLong nIndex,xub_StrLen nOffset)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
Read(SvStream & rStream)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
Write(SvStream & rStream,const SwDoc & rDoc)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
CompareLayout(const SwDoc & rDoc) const342 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
ClearImpl()459 void SwLayoutCache::ClearImpl()
460 {
461 if( !IsLocked() )
462 {
463 delete pImpl;
464 pImpl = 0;
465 }
466 }
467
468
~SwLayoutCache()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
SwActualSection(SwActualSection * pUp,SwSectionFrm * pSect,SwSectionNode * pNd)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
SwLayHelper(SwDoc * pD,SwFrm * & rpF,SwFrm * & rpP,SwPageFrm * & rpPg,SwLayoutFrm * & rpL,SwActualSection * & rpA,sal_Bool & rB,sal_uLong nNodeIndex,sal_Bool bCache)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
~SwLayHelper()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
CalcPageCount()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
CheckInsertPage()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#
lcl_HasTextFrmAnchoredObjs(SwTxtFrm * p_pTxtFrm)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
lcl_ApplyWorkaroundForB6375613(SwFrm * p_pFirstFrmOnNewPage)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
CheckInsert(sal_uLong nNodeIndex)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 {
operator ()SdrObjectCompare994 bool operator()( const SdrObject* pF1, const SdrObject* pF2 ) const
995 {
996 return pF1->GetOrdNum() < pF2->GetOrdNum();
997 }
998 };
999
1000 struct FlyCacheCompare
1001 {
operator ()FlyCacheCompare1002 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
_CheckFlyCache(SwPageFrm * pPage)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
CheckPageFlyCache(SwPageFrm * & rpPage,SwFlyFrm * pFly)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
SwLayCacheIoImpl(SvStream & rStrm,sal_Bool bWrtMd)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
OpenRec(sal_uInt8 cType)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
CloseRec(sal_uInt8)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
BytesLeft()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
Peek()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
SkipRec()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
OpenFlagRec()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
OpenFlagRec(sal_uInt8 nFlags,sal_uInt8 nLen)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
CloseFlagRec()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