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