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