1 /************************************************************************/
2 /* */
3 /* Get headers and footers for a certain page/position. */
4 /* */
5 /************************************************************************/
6
7 # include "docBufConfig.h"
8
9 # include <appDebugon.h>
10
11 # include "docBuf.h"
12 # include "docTreeNode.h"
13 # include <docTreeType.h>
14
15 /************************************************************************/
16 /* */
17 /* Kinds of Headers/Footers. */
18 /* */
19 /* The arrays are a mapping from the options to the header/footer data */
20 /* structure that is used in the implementation. */
21 /* */
22 /************************************************************************/
23
24 const int DOC_HeaderScopes[PAGES__COUNT]=
25 {
26 DOCinFIRST_HEADER, /* PAGES_FIRST_PAGE */
27 DOCinRIGHT_HEADER, /* PAGES_SUBSEQUENT_PAGES */
28 DOCinRIGHT_HEADER, /* PAGES_ALL_PAGES */
29 DOCinRIGHT_HEADER, /* PAGES_ODD_PAGES */
30 DOCinLEFT_HEADER, /* PAGES_EVEN_PAGES */
31 };
32
33 const int DOC_FooterScopes[PAGES__COUNT]=
34 {
35 DOCinFIRST_FOOTER, /* PAGES_FIRST_PAGE */
36 DOCinRIGHT_FOOTER, /* PAGES_SUBSEQUENT_PAGES */
37 DOCinRIGHT_FOOTER, /* PAGES_ALL_PAGES */
38 DOCinRIGHT_FOOTER, /* PAGES_ODD_PAGES */
39 DOCinLEFT_FOOTER, /* PAGES_EVEN_PAGES */
40 };
41
42 /************************************************************************/
43 /* */
44 /* Determine what header/footer applies for a certain page. */
45 /* */
46 /************************************************************************/
47
docCheckTreeIsEmpty(int * pIsEmpty,const BufferDocument * bd,const DocumentTree * dt)48 static int docCheckTreeIsEmpty( int * pIsEmpty,
49 const BufferDocument * bd,
50 const DocumentTree * dt )
51 {
52 int isEmpty= 1;
53
54 if ( dt && dt->dtRoot )
55 {
56 DocumentPosition dpBegin;
57 DocumentPosition dpNext;
58
59 if ( docHeadPosition( &dpBegin, dt->dtRoot ) )
60 { LDEB(1); docInitDocumentPosition( &dpBegin ); }
61
62 dpNext= dpBegin;
63 if ( ! docNextPosition( &dpNext ) )
64 { isEmpty= 0; }
65 else{
66 const ParagraphProperties * pp= &(dpBegin.dpNode->biParaProperties);
67
68 if ( pp->ppTableNesting > 0 )
69 { isEmpty= 0; }
70
71 if ( docBorderNumberIsBorder( bd, pp->ppTopBorderNumber ) )
72 { isEmpty= 0; }
73 if ( docBorderNumberIsBorder( bd, pp->ppBottomBorderNumber ) )
74 { isEmpty= 0; }
75 if ( docBorderNumberIsBorder( bd, pp->ppLeftBorderNumber ) )
76 { isEmpty= 0; }
77 if ( docBorderNumberIsBorder( bd, pp->ppRightBorderNumber ) )
78 { isEmpty= 0; }
79 if ( docBorderNumberIsBorder( bd, pp->ppBetweenBorderNumber ) )
80 { isEmpty= 0; }
81 if ( docBorderNumberIsBorder( bd, pp->ppBarNumber ) )
82 { isEmpty= 0; }
83
84 if ( docShadingNumberIsShading( bd, pp->ppShadingNumber ) )
85 { isEmpty= 0; }
86 }
87 }
88
89 if ( pIsEmpty )
90 { *pIsEmpty= isEmpty; }
91
92 return 0;
93 }
94
95 /************************************************************************/
96 /* */
97 /* Decide what header should go to this page. */
98 /* */
99 /************************************************************************/
100
docWhatPageHeader(DocumentTree ** pTree,int * pIsEmpty,const BufferItem * bodySectNode,int page,const BufferDocument * bd)101 int docWhatPageHeader( DocumentTree ** pTree,
102 int * pIsEmpty,
103 const BufferItem * bodySectNode,
104 int page,
105 const BufferDocument * bd )
106 {
107 const DocumentProperties * dp= &(bd->bdProperties);
108 const SectionProperties * sp= &(bodySectNode->biSectProperties);
109
110 SectHeadersFooters * shf= bodySectNode->biSectHeadersFooters;
111 DocumentTree * tree= (DocumentTree *)0;
112
113 if ( ! shf )
114 { XDEB(shf); return -1; }
115
116 if ( page == bodySectNode->biTopPosition.lpPage && sp->spHasTitlePage )
117 {
118 tree= &(shf->shfFirstPageHeader);
119 docCheckTreeIsEmpty( pIsEmpty, bd, tree );
120 if ( pTree )
121 { *pTree= tree; }
122 return DOCinFIRST_HEADER;
123 }
124
125 if ( page % 2 && dp->dpHasFacingPages )
126 {
127 tree= &(shf->shfLeftPageHeader);
128 docCheckTreeIsEmpty( pIsEmpty, bd, tree );
129 if ( pTree )
130 { *pTree= tree; }
131 return DOCinLEFT_HEADER;
132 }
133 else{
134 tree= &(shf->shfRightPageHeader);
135 docCheckTreeIsEmpty( pIsEmpty, bd, tree );
136 if ( pTree )
137 { *pTree= tree; }
138 return DOCinRIGHT_HEADER;
139 }
140 }
141
docWhatPageFooter(DocumentTree ** pTree,int * pIsEmpty,const BufferItem * bodySectNode,int page,const BufferDocument * bd)142 int docWhatPageFooter( DocumentTree ** pTree,
143 int * pIsEmpty,
144 const BufferItem * bodySectNode,
145 int page,
146 const BufferDocument * bd )
147 {
148 const DocumentProperties * dp= &(bd->bdProperties);
149 const SectionProperties * sp= &(bodySectNode->biSectProperties);
150
151 SectHeadersFooters * shf= bodySectNode->biSectHeadersFooters;
152 DocumentTree * tree= (DocumentTree *)0;
153
154 if ( ! shf )
155 { XDEB(shf); return -1; }
156
157 if ( page == bodySectNode->biTopPosition.lpPage && sp->spHasTitlePage )
158 {
159 tree= &(shf->shfFirstPageFooter);
160 docCheckTreeIsEmpty( pIsEmpty, bd, tree );
161 if ( pTree )
162 { *pTree= tree; }
163 return DOCinFIRST_FOOTER;
164 }
165
166 if ( page % 2 && dp->dpHasFacingPages )
167 {
168 tree= &(shf->shfLeftPageFooter);
169 docCheckTreeIsEmpty( pIsEmpty, bd, tree );
170 if ( pTree )
171 { *pTree= tree; }
172 return DOCinLEFT_FOOTER;
173 }
174 else{
175 tree= &(shf->shfRightPageFooter);
176 docCheckTreeIsEmpty( pIsEmpty, bd, tree );
177 if ( pTree )
178 { *pTree= tree; }
179 return DOCinRIGHT_FOOTER;
180 }
181 }
182
183 /************************************************************************/
184 /* */
185 /* Decide what footer should go to this page. */
186 /* */
187 /************************************************************************/
188
docWhatPagesForHeaderFooter(const DocumentProperties * dp,const SectionProperties * sp,int treeType)189 int docWhatPagesForHeaderFooter( const DocumentProperties * dp,
190 const SectionProperties * sp,
191 int treeType )
192 {
193 switch( treeType )
194 {
195 case DOCinFIRST_HEADER:
196 case DOCinFIRST_FOOTER:
197 return PAGES_FIRST_PAGE;
198
199 case DOCinLEFT_HEADER:
200 case DOCinLEFT_FOOTER:
201 return PAGES_EVEN_PAGES;
202
203 case DOCinRIGHT_HEADER:
204 case DOCinRIGHT_FOOTER:
205 if ( dp->dpHasFacingPages )
206 { return PAGES_ODD_PAGES; }
207 else{
208 if ( sp->spHasTitlePage )
209 { return PAGES_SUBSEQUENT_PAGES; }
210 else{ return PAGES_ALL_PAGES; }
211 }
212 /*unreachable*/
213
214 default:
215 LDEB(treeType);
216 return -1;
217 }
218 }
219
220 /************************************************************************/
221 /* */
222 /* Return a particular header or footer by scope. */
223 /* */
224 /************************************************************************/
225
docSectionHeaderFooter(const BufferItem * bodySectNode,unsigned char * pApplies,const DocumentProperties * dp,int treeType)226 DocumentTree * docSectionHeaderFooter(
227 const BufferItem * bodySectNode,
228 unsigned char * pApplies,
229 const DocumentProperties * dp,
230 int treeType )
231 {
232 const SectionProperties * sp= &(bodySectNode->biSectProperties);
233 SectHeadersFooters * shf= bodySectNode->biSectHeadersFooters;
234
235 if ( ! shf )
236 { XDEB(shf); return (DocumentTree *)0; }
237
238 switch( treeType )
239 {
240 case DOCinBODY:
241 LDEB(treeType); return (DocumentTree *)0;
242
243 case DOCinFIRST_HEADER:
244 if ( pApplies )
245 { *pApplies= sp->spHasTitlePage; }
246 return &(shf->shfFirstPageHeader);
247
248 case DOCinLEFT_HEADER:
249 if ( pApplies )
250 { *pApplies= dp->dpHasFacingPages; }
251 return &(shf->shfLeftPageHeader);
252
253 case DOCinRIGHT_HEADER:
254 if ( pApplies )
255 { *pApplies= 1; }
256 return &(shf->shfRightPageHeader);
257
258 case DOCinFIRST_FOOTER:
259 if ( pApplies )
260 { *pApplies= sp->spHasTitlePage; }
261 return &(shf->shfFirstPageFooter);
262
263 case DOCinLEFT_FOOTER:
264 if ( pApplies )
265 { *pApplies= dp->dpHasFacingPages; }
266 return &(shf->shfLeftPageFooter);
267
268 case DOCinRIGHT_FOOTER:
269 if ( pApplies )
270 { *pApplies= 1; }
271 return &(shf->shfRightPageFooter);
272
273 default:
274 LDEB(treeType); return (DocumentTree *)0;
275 }
276 }
277
docSectionHasHeaderFooter(const BufferItem * bodySectNode,unsigned char * pApplies,const DocumentProperties * dp,int treeType)278 int docSectionHasHeaderFooter( const BufferItem * bodySectNode,
279 unsigned char * pApplies,
280 const DocumentProperties * dp,
281 int treeType )
282 {
283 DocumentTree * dt;
284
285 dt= docSectionHeaderFooter( bodySectNode, pApplies, dp, treeType );
286 if ( ! dt || ! dt->dtRoot )
287 { return 0; }
288
289 return 1;
290 }
291
292 /************************************************************************/
293 /* */
294 /* Return the first page where a particular kind of header/footer can */
295 /* be used in a document. The existence of the tree is checked by the */
296 /* caller. */
297 /* */
298 /************************************************************************/
299
docSectionHeaderFooterFirstPage(int * pUsedByDocument,const BufferItem * bodySectNode,int treeType,const DocumentProperties * dp)300 int docSectionHeaderFooterFirstPage(
301 int * pUsedByDocument,
302 const BufferItem * bodySectNode,
303 int treeType,
304 const DocumentProperties * dp )
305 {
306 const SectionProperties * sp= &(bodySectNode->biSectProperties);
307 int topPage= bodySectNode->biTopPosition.lpPage;
308 int belowPage= bodySectNode->biBelowPosition.lpPage;
309 int page;
310
311 const BufferItem * prevBi= (const BufferItem *)0;
312
313 if ( bodySectNode->biNumberInParent > 0 )
314 {
315 prevBi= bodySectNode->biParent->biChildren[
316 bodySectNode->biNumberInParent- 1];
317
318 if ( prevBi->biBelowPosition.lpPage >= belowPage )
319 { *pUsedByDocument= 0; return -1; }
320 }
321
322 switch( treeType )
323 {
324 case DOCinBODY:
325 LDEB(treeType); *pUsedByDocument= 0; return -1;
326
327 case DOCinFIRST_HEADER:
328 case DOCinFIRST_FOOTER:
329 if ( ! sp->spHasTitlePage )
330 { *pUsedByDocument= 0; return -1; }
331
332 if ( prevBi && prevBi->biBelowPosition.lpPage >= topPage )
333 { *pUsedByDocument= 0; return topPage;
334 }
335 page= topPage;
336 break;
337
338 case DOCinLEFT_HEADER:
339 case DOCinLEFT_FOOTER:
340 if ( ! dp->dpHasFacingPages )
341 { *pUsedByDocument= 0; return -1; }
342 if ( topPage % 2 )
343 {
344 if ( sp->spHasTitlePage )
345 { page= topPage+ 2; }
346 else{ page= topPage; }
347 }
348 else{ page= topPage+ 1; }
349 break;
350
351 case DOCinRIGHT_HEADER:
352 case DOCinRIGHT_FOOTER:
353 if ( dp->dpHasFacingPages )
354 {
355 if ( topPage % 2 == 0 )
356 {
357 if ( sp->spHasTitlePage )
358 { page= topPage+ 2; }
359 else{ page= topPage; }
360 }
361 else{ page= topPage+ 1; }
362 }
363 else{
364 if ( sp->spHasTitlePage )
365 { page= topPage+ 1; }
366 else{ page= topPage; }
367 }
368 break;
369
370 default:
371 LDEB(treeType); *pUsedByDocument= 0; return -1;
372 }
373
374 *pUsedByDocument= page <= bodySectNode->biBelowPosition.lpPage;
375
376 return page;
377 }
378
379 /************************************************************************/
380 /* */
381 /* Return the Header/Footer corrsponding to 'treeType'. If the */
382 /* selection itself is in an external tree, go to the section in the */
383 /* body to get the header or footer. */
384 /* */
385 /************************************************************************/
386
docGetHeaderFooter(DocumentTree ** pEi,BufferItem ** pBodySectNode,const DocumentPosition * dp,BufferDocument * bd,int treeType)387 int docGetHeaderFooter( DocumentTree ** pEi,
388 BufferItem ** pBodySectNode,
389 const DocumentPosition * dp,
390 BufferDocument * bd,
391 int treeType )
392 {
393 DocumentTree * eiDp;
394 DocumentTree * eiHdFt;
395 BufferItem * bodySectNode;
396 unsigned char applies= 1;
397
398 if ( docGetTreeOfNode( &eiDp, &bodySectNode, bd, dp->dpNode ) )
399 { LDEB(1); return -1; }
400
401 eiHdFt= docSectionHeaderFooter( bodySectNode, &applies,
402 &(bd->bdProperties), treeType );
403 if ( ! eiHdFt )
404 { XDEB(eiHdFt); return -1; }
405
406 *pEi= eiHdFt; *pBodySectNode= bodySectNode; return 0;
407 }
408
409 /************************************************************************/
410 /* */
411 /* Determine whether that document has headers and footers at all. */
412 /* */
413 /************************************************************************/
414
docInquireHeadersFooters(int * pDocHasHeaders,int * pDocHasFooters,const BufferDocument * bd)415 int docInquireHeadersFooters( int * pDocHasHeaders,
416 int * pDocHasFooters,
417 const BufferDocument * bd )
418 {
419 int i;
420 int hasPageHeader= 0;
421 int hasPageFooter= 0;
422
423 const BufferItem * bodyBi= bd->bdBody.dtRoot;
424
425 for ( i= 0; i < bodyBi->biChildCount; i++ )
426 {
427 int j;
428 BufferItem * sectBi= bodyBi->biChildren[i];
429
430 for ( j= 0; j < PAGES__COUNT; j++ )
431 {
432 DocumentTree * dt;
433 unsigned char applies;
434
435 applies= 1;
436 dt= docSectionHeaderFooter( sectBi, &applies,
437 &(bd->bdProperties), DOC_HeaderScopes[j] );
438 if ( dt && dt->dtRoot && applies )
439 { hasPageHeader= 1; }
440
441 applies= 1;
442 dt= docSectionHeaderFooter( sectBi, &applies,
443 &(bd->bdProperties), DOC_FooterScopes[j] );
444 if ( dt && dt->dtRoot && applies )
445 { hasPageFooter= 1; }
446 }
447 }
448
449 *pDocHasHeaders= hasPageHeader;
450 *pDocHasFooters= hasPageFooter;
451 return 0;
452 }
453
454 /************************************************************************/
455 /* */
456 /* Find the page, nearest to the current page that can hold a */
457 /* particular kinfd of header or footer. */
458 /* */
459 /************************************************************************/
460
461 static int DOC_TryPageOffsets[]= { 0, 1, -1, 2 };
462
docHeaderFooterPage(const BufferDocument * bd,const BufferItem * bodySectNode,int currentPage,int treeType)463 int docHeaderFooterPage( const BufferDocument * bd,
464 const BufferItem * bodySectNode,
465 int currentPage,
466 int treeType )
467 {
468 switch( treeType )
469 {
470 int isEmpty;
471 int i;
472 DocumentTree * eiTry;
473 int ttForPg;
474
475 case DOCinFIRST_HEADER:
476 case DOCinFIRST_FOOTER:
477 return bodySectNode->biTopPosition.lpPage;
478 break;
479
480 case DOCinLEFT_HEADER:
481 case DOCinRIGHT_HEADER:
482 for ( i= 0; i < sizeof(DOC_TryPageOffsets)/sizeof(int); i++ )
483 {
484 int pg= currentPage+ DOC_TryPageOffsets[i];
485
486 if ( pg < bodySectNode->biTopPosition.lpPage ||
487 pg > bodySectNode->biBelowPosition.lpPage )
488 { continue; }
489
490 ttForPg= docWhatPageHeader( &eiTry, &isEmpty,
491 bodySectNode, pg, bd );
492 if ( ttForPg == treeType )
493 { return pg; }
494 }
495 break;
496
497 case DOCinLEFT_FOOTER:
498 case DOCinRIGHT_FOOTER:
499 for ( i= 0; i < sizeof(DOC_TryPageOffsets)/sizeof(int); i++ )
500 {
501 int pg= currentPage+ DOC_TryPageOffsets[i];
502
503 if ( pg < bodySectNode->biTopPosition.lpPage ||
504 pg > bodySectNode->biBelowPosition.lpPage )
505 { continue; }
506
507 ttForPg= docWhatPageFooter( &eiTry, &isEmpty,
508 bodySectNode, pg, bd );
509 if ( ttForPg == treeType )
510 { return pg; }
511 }
512 break;
513
514 default:
515 LDEB(treeType); return -1;
516 }
517
518 return -1;
519 }
520
521
522 /************************************************************************/
523 /* */
524 /* Force recalculation of header/fooet layout. */
525 /* */
526 /************************************************************************/
527
docInvalidateSectHeaderFooterLayout(BufferItem * sectBi)528 void docInvalidateSectHeaderFooterLayout( BufferItem * sectBi )
529 {
530 SectHeadersFooters * shf= sectBi->biSectHeadersFooters;
531
532 if ( shf )
533 {
534 docInvalidateTreeLayout( &(shf->shfFirstPageHeader) );
535 docInvalidateTreeLayout( &(shf->shfLeftPageHeader) );
536 docInvalidateTreeLayout( &(shf->shfRightPageHeader) );
537
538 docInvalidateTreeLayout( &(shf->shfFirstPageFooter) );
539 docInvalidateTreeLayout( &(shf->shfLeftPageFooter) );
540 docInvalidateTreeLayout( &(shf->shfRightPageFooter) );
541 }
542
543 return;
544 }
545
546 /************************************************************************/
547 /* */
548 /* Bookkeeping of section headers and footers. */
549 /* */
550 /************************************************************************/
551
docCleanSectHeadersFooters(BufferDocument * bd,SectHeadersFooters * shf)552 void docCleanSectHeadersFooters( BufferDocument * bd,
553 SectHeadersFooters * shf )
554 {
555 docCleanDocumentTree( bd, &(shf->shfFirstPageHeader) );
556 docCleanDocumentTree( bd, &(shf->shfLeftPageHeader) );
557 docCleanDocumentTree( bd, &(shf->shfRightPageHeader) );
558
559 docCleanDocumentTree( bd, &(shf->shfFirstPageFooter) );
560 docCleanDocumentTree( bd, &(shf->shfLeftPageFooter) );
561 docCleanDocumentTree( bd, &(shf->shfRightPageFooter) );
562
563 return;
564 }
565
docInitSectHeadersFooters(SectHeadersFooters * shf)566 void docInitSectHeadersFooters( SectHeadersFooters * shf )
567 {
568 docInitDocumentTree( &(shf->shfFirstPageHeader) );
569 docInitDocumentTree( &(shf->shfLeftPageHeader) );
570 docInitDocumentTree( &(shf->shfRightPageHeader) );
571
572 docInitDocumentTree( &(shf->shfFirstPageFooter) );
573 docInitDocumentTree( &(shf->shfLeftPageFooter) );
574 docInitDocumentTree( &(shf->shfRightPageFooter) );
575 }
576