Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/aux/antiword/pdf.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * pdf.c
3
 * Copyright (C) 2003-2005 A.J. van Os; Released under GNU GPL
4
 *
5
 * Description:
6
 * Functions to deal with the Adobe Portable Document Format (pdf)
7
 *
8
 */
9
 
10
#include <stdarg.h>
11
#include <string.h>
12
#include "version.h"
13
#include "antiword.h"
14
 
15
 
16
/* Constants for the file positions */
17
#define INITIAL_LOCATION_SIZE	20
18
#define INITIAL_PAGEOBJECT_SIZE	 5
19
#if defined(DEBUG)
20
#define EXTENSION_ARRAY_SIZE	10
21
#else
22
#define EXTENSION_ARRAY_SIZE	30
23
#endif /* DEBUG */
24
 
25
/* The character set */
26
static encoding_type	eEncoding = encoding_neutral;
27
/* Current creator for a PDF header */
28
static const char	*szProducer = NULL;
29
/* The height and width of a PDF page (in DrawUnits) */
30
static long		lPageHeight = LONG_MAX;
31
static long		lPageWidth = LONG_MAX;
32
/* The height of the footer on the current page (in DrawUnits) */
33
static long		lFooterHeight = 0;
34
/* Inside a footer (to prevent an infinite loop when the footer is too big) */
35
static BOOL		bInFtrSpace = FALSE;
36
/* Current font information */
37
static drawfile_fontref	tFontRefCurr = (drawfile_fontref)-1;
38
static USHORT		usFontSizeCurr = 0;
39
static int		iFontColorCurr = -1;
40
/* Current vertical position information */
41
static long		lYtopCurr = -1;
42
/* Image counter */
43
static int		iImageCount = 0;
44
/* Section index */
45
static int		iSectionIndex = 0;
46
/* Are we on the first page of the section? */
47
static BOOL		bFirstInSection = TRUE;
48
/* File positions */
49
static long		lFilePosition = 0;
50
static long		*alLocation = NULL;
51
static size_t		tLocations = 0;
52
static int		iMaxLocationNumber = 0;
53
/* File position at the start of a page */
54
static long		lStreamStart = -1;
55
/* Page objects */
56
static int		*aiPageObject = NULL;
57
static int		iPageCount = 0;
58
static size_t		tMaxPageObjects = 0;
59
/* Current object number */
60
/* 1 = root; 2 = info; 3 = pages; 4 = encoding; 5-16 = fonts; 17 = resources */
61
static int		iObjectNumberCurr = 17;
62
 
63
static void		vMoveTo(diagram_type *, long);
64
 
65
static const struct {
66
	const char	*szPDFname;
67
	const char	*szPSname;
68
} atFontname[] = {
69
	{ "Courier",			FONT_MONOSPACED_PLAIN },
70
	{ "Courier-Bold",		FONT_MONOSPACED_BOLD },
71
	{ "Courier-Oblique",		FONT_MONOSPACED_ITALIC },
72
	{ "Courier-BoldOblique",	FONT_MONOSPACED_BOLDITALIC },
73
	{ "Helvetica",			FONT_SANS_SERIF_PLAIN },
74
	{ "Helvetica-Bold",		FONT_SANS_SERIF_BOLD },
75
	{ "Helvetica-Oblique",		FONT_SANS_SERIF_ITALIC },
76
	{ "Helvetica-BoldOblique",	FONT_SANS_SERIF_BOLDITALIC },
77
	{ "Times-Roman",		FONT_SERIF_PLAIN },
78
	{ "Times-Bold",			FONT_SERIF_BOLD },
79
	{ "Times-Italic",		FONT_SERIF_ITALIC },
80
	{ "Times-BoldItalic",		FONT_SERIF_BOLDITALIC },
81
};
82
 
83
static const char *iso_8859_1[] = {
84
"128 /Euro",
85
"140 /ellipsis /trademark /perthousand /bullet",
86
"    /quoteleft /quoteright /guilsinglleft /guilsinglright",
87
"    /quotedblleft /quotedblright /quotedblbase /endash /emdash",
88
"    /minus /OE /oe /dagger /daggerdbl /fi /fl",
89
"160 /space /exclamdown /cent /sterling /currency",
90
"    /yen /brokenbar /section /dieresis /copyright",
91
"    /ordfeminine /guillemotleft /logicalnot /hyphen /registered",
92
"    /macron /degree /plusminus /twosuperior /threesuperior",
93
"    /acute /mu /paragraph /periodcentered /cedilla",
94
"    /onesuperior /ordmasculine /guillemotright /onequarter",
95
"    /onehalf /threequarters /questiondown /Agrave /Aacute",
96
"    /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla",
97
"    /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute",
98
"    /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute",
99
"    /Ocircumflex /Otilde /Odieresis /multiply /Oslash",
100
"    /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn",
101
"    /germandbls /agrave /aacute /acircumflex /atilde",
102
"    /adieresis /aring /ae /ccedilla /egrave /eacute",
103
"    /ecircumflex /edieresis /igrave /iacute /icircumflex",
104
"    /idieresis /eth /ntilde /ograve /oacute /ocircumflex",
105
"    /otilde /odieresis /divide /oslash /ugrave /uacute",
106
"    /ucircumflex /udieresis /yacute /thorn /ydieresis",
107
};
108
 
109
static const char *iso_8859_2[] = {
110
"160 /space /Aogonek /breve /Lslash /currency /Lcaron",
111
"    /Sacute /section /dieresis /Scaron /Scommaaccent",
112
"    /Tcaron /Zacute /hyphen /Zcaron /Zdotaccent /degree",
113
"    /aogonek /ogonek /lslash /acute /lcaron /sacute",
114
"    /caron /cedilla /scaron /scommaaccent /tcaron",
115
"    /zacute /hungarumlaut /zcaron /zdotaccent /Racute",
116
"    /Aacute /Acircumflex /Abreve /Adieresis /Lacute",
117
"    /Cacute /Ccedilla /Ccaron /Eacute /Eogonek",
118
"    /Edieresis /Ecaron /Iacute /Icircumflex /Dcaron",
119
"    /.notdef /Nacute /Ncaron /Oacute /Ocircumflex",
120
"    /Ohungarumlaut /Odieresis /multiply /Rcaron /Uring",
121
"    /Uacute /Uhungarumlaut /Udieresis /Yacute /Tcommaaccent",
122
"    /germandbls /racute /aacute /acircumflex /abreve",
123
"    /adieresis /lacute /cacute /ccedilla /ccaron /eacute",
124
"    /eogonek /edieresis /ecaron /iacute /icircumflex",
125
"    /dcaron /.notdef /nacute /ncaron /oacute /ocircumflex",
126
"    /ohungarumlaut /odieresis /divide /rcaron /uring",
127
"    /uacute /uhungarumlaut /udieresis /yacute /tcommaaccent",
128
"    /dotaccent",
129
};
130
 
131
 
132
/*
133
 * tGetFontIndex - get the font index
134
 */
135
static size_t
136
tGetFontIndex(drawfile_fontref tFontRef)
137
{
138
	const char	*szFontname;
139
	size_t		tIndex;
140
 
141
	/* Get the font name */
142
	szFontname = szGetFontname(tFontRef);
143
	fail(szFontname == NULL);
144
	if (szFontname == NULL) {
145
		return 0;
146
	}
147
 
148
	/* Find the name in the table */
149
	for (tIndex = 0; tIndex < elementsof(atFontname); tIndex++) {
150
		if (STRCEQ(atFontname[tIndex].szPSname, szFontname)) {
151
			return tIndex;
152
		}
153
	}
154
	/* Not found */
155
	DBG_DEC(tFontRef);
156
	DBG_MSG(szFontname);
157
	return 0;
158
} /* end of tGetFontIndex */
159
 
160
/*
161
 * vSetLocation - store the location of objects
162
 */
163
static void
164
vSetLocation(int iLocationNumber)
165
{
166
	fail(iLocationNumber <= 0);
167
 
168
	if ((size_t)iLocationNumber >= tLocations) {
169
		/* Extend and set to zero */
170
		tLocations += EXTENSION_ARRAY_SIZE;
171
		alLocation = xrealloc(alLocation, tLocations * sizeof(long));
172
		memset(alLocation + tLocations - EXTENSION_ARRAY_SIZE,
173
			0,
174
			EXTENSION_ARRAY_SIZE * sizeof(long));
175
		DBG_DEC(tLocations);
176
	}
177
	if (iLocationNumber > iMaxLocationNumber) {
178
		iMaxLocationNumber = iLocationNumber;
179
	}
180
 
181
	DBG_DEC_C((size_t)iLocationNumber >= tLocations, iLocationNumber);
182
	DBG_DEC_C((size_t)iLocationNumber >= tLocations, tLocations);
183
	fail((size_t)iLocationNumber >= tLocations);
184
 
185
	alLocation[iLocationNumber] = lFilePosition;
186
} /* end of vSetLocation */
187
 
188
/*
189
 * vFillNextPageObject - fil the next page object with the current object number
190
 */
191
static void
192
vFillNextPageObject(void)
193
{
194
	iPageCount++;
195
	if ((size_t)iPageCount >= tMaxPageObjects) {
196
		/* Extend the array */
197
		tMaxPageObjects += EXTENSION_ARRAY_SIZE;
198
		aiPageObject = xrealloc(aiPageObject,
199
					tMaxPageObjects * sizeof(int));
200
		DBG_DEC(tMaxPageObjects);
201
	}
202
	aiPageObject[iPageCount] = iObjectNumberCurr;
203
} /* end of vFillNextPageObject */
204
 
205
/*
206
 * vFPprintf - printf and update the fileposition
207
 *
208
 * called with arguments like fprintf(3)
209
 */
210
static void
211
vFPprintf(FILE *pOutFile, const char *szFormat, ...)
212
{
213
	va_list	tArg;
214
 
215
	va_start(tArg, szFormat);
216
	lFilePosition += vfprintf(pOutFile, szFormat, tArg);
217
	va_end(tArg);
218
} /* end of vFPprintf */
219
 
220
/*
221
 * vCreateInfoDictionary - create the document information dictionary
222
 */
223
void
224
vCreateInfoDictionary(diagram_type *pDiag, int iWordVersion)
225
{
226
	FILE	*pOutFile;
227
	const char	*szTitle, *szAuthor, *szSubject, *szCreator;
228
	const char	*szCreationDate, *szModDate;
229
 
230
	fail(pDiag == NULL);
231
	fail(pDiag->pOutFile == NULL);
232
	fail(iWordVersion < 0);
233
	fail(szProducer == NULL || szProducer[0] == '\0');
234
 
235
	szTitle = szGetTitle();
236
	szAuthor = szGetAuthor();
237
	szSubject = szGetSubject();
238
	szCreationDate = szGetCreationDate();
239
	szModDate = szGetModDate();
240
 
241
	switch (iWordVersion) {
242
	case 0: szCreator = "Word for DOS"; break;
243
	case 1: szCreator = "WinWord 1.x"; break;
244
	case 2: szCreator = "WinWord 2.0"; break;
245
	case 4: szCreator = "MacWord 4"; break;
246
	case 5: szCreator = "MacWord 5"; break;
247
	case 6: szCreator = "Word 6"; break;
248
	case 7: szCreator = "Word 7/95"; break;
249
	case 8: szCreator = "Word 97 or later"; break;
250
	default: szCreator = NULL; break;
251
	}
252
 
253
	pOutFile = pDiag->pOutFile;
254
 
255
	vSetLocation(2);
256
	vFPprintf(pOutFile, "2 0 obj\n");
257
	vFPprintf(pOutFile, "<<\n");
258
	if (szTitle != NULL && szTitle[0] != '\0') {
259
		vFPprintf(pOutFile, "/Title (%s)\n", szTitle);
260
	}
261
	if (szAuthor != NULL && szAuthor[0] != '\0') {
262
		vFPprintf(pOutFile, "/Author (%s)\n", szAuthor);
263
	}
264
	if (szSubject != NULL && szSubject[0] != '\0') {
265
		vFPprintf(pOutFile, "/Subject (%s)\n", szSubject);
266
	}
267
	if (szCreator != NULL && szCreator[0] != '\0') {
268
		vFPprintf(pOutFile, "/Creator (%s)\n", szCreator);
269
	}
270
	vFPprintf(pOutFile, "/Producer (%s %s)\n", szProducer, VERSIONSTRING);
271
	if (szCreationDate != NULL && szCreationDate[0] != '\0') {
272
		vFPprintf(pOutFile, "/CreationDate (%s)\n", szCreationDate);
273
	}
274
	if (szModDate != NULL && szModDate[0] != '\0') {
275
		vFPprintf(pOutFile, "/ModDate (%s)\n", szModDate);
276
	}
277
	vFPprintf(pOutFile, ">>\n");
278
	vFPprintf(pOutFile, "endobj\n");
279
} /* end of vCreateInfoDictionary */
280
 
281
/*
282
 * vAddHdrFtr - add a header or footer
283
 */
284
static void
285
vAddHdrFtr(diagram_type *pDiag, const hdrftr_block_type *pHdrFtrInfo)
286
{
287
	output_type	*pStart, *pPrev, *pNext;
288
 
289
	fail(pDiag == NULL);
290
	fail(pHdrFtrInfo == NULL);
291
 
292
	vStartOfParagraphPDF(pDiag, 0);
293
	pStart = pHdrFtrInfo->pText;
294
	while (pStart != NULL) {
295
		pNext = pStart;
296
		while (pNext != NULL &&
297
		       (pNext->tNextFree != 1 ||
298
		        (pNext->szStorage[0] != PAR_END &&
299
		         pNext->szStorage[0] != HARD_RETURN))) {
300
			pNext = pNext->pNext;
301
		}
302
		if (pNext == NULL) {
303
			if (bOutputContainsText(pStart)) {
304
				vAlign2Window(pDiag, pStart,
305
					lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
306
					ALIGNMENT_LEFT);
307
			} else {
308
				vMove2NextLinePDF(pDiag, pStart->usFontSize);
309
			}
310
			break;
311
		}
312
		fail(pNext->tNextFree != 1);
313
		fail(pNext->szStorage[0] != PAR_END &&
314
			pNext->szStorage[0] != HARD_RETURN);
315
 
316
		if (pStart != pNext) {
317
			/* There is something to print */
318
			pPrev = pNext->pPrev;
319
			fail(pPrev->pNext != pNext);
320
			/* Cut the chain */
321
			pPrev->pNext = NULL;
322
			if (bOutputContainsText(pStart)) {
323
				/* Print it */
324
				vAlign2Window(pDiag, pStart,
325
					lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
326
					ALIGNMENT_LEFT);
327
			} else {
328
				/* Just an empty line */
329
				vMove2NextLinePDF(pDiag, pStart->usFontSize);
330
			}
331
			/* Repair the chain */
332
			pPrev->pNext = pNext;
333
		}
334
		if (pNext->szStorage[0] == PAR_END) {
335
			vEndOfParagraphPDF(pDiag, pNext->usFontSize,
336
					(long)pNext->usFontSize * 200);
337
		}
338
		pStart = pNext->pNext;
339
	}
340
} /* end of vAddHdrFtr */
341
 
342
/*
343
 * vAddHeader - add a page header
344
 */
345
static void
346
vAddHeader(diagram_type *pDiag)
347
{
348
	const hdrftr_block_type *pHdrInfo;
349
	const hdrftr_block_type *pFtrInfo;
350
 
351
	fail(pDiag == NULL);
352
 
353
	NO_DBG_MSG("vAddHeader");
354
 
355
	pHdrInfo = pGetHdrFtrInfo(iSectionIndex, TRUE,
356
					odd(iPageCount), bFirstInSection);
357
	pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
358
					odd(iPageCount), bFirstInSection);
359
	/* Set the height of the footer of this page */
360
	lFooterHeight = pFtrInfo == NULL ? 0 : pFtrInfo->lHeight;
361
	fail(lFooterHeight < 0);
362
 
363
	if (pHdrInfo == NULL ||
364
	    pHdrInfo->pText == NULL ||
365
	    pHdrInfo->lHeight <= 0) {
366
		fail(pHdrInfo != NULL && pHdrInfo->lHeight < 0);
367
		fail(pHdrInfo != NULL &&
368
			pHdrInfo->pText != NULL &&
369
			pHdrInfo->lHeight == 0);
370
		return;
371
	}
372
 
373
	vAddHdrFtr(pDiag, pHdrInfo);
374
 
375
	DBG_DEC_C(pHdrInfo->lHeight !=
376
		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
377
		pHdrInfo->lHeight);
378
	DBG_DEC_C(pHdrInfo->lHeight !=
379
		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
380
		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop);
381
} /* end of vAddHeader */
382
 
383
/*
384
 * vAddFooter - add a page footer
385
 */
386
static void
387
vAddFooter(diagram_type *pDiag)
388
{
389
	const hdrftr_block_type *pFtrInfo;
390
 
391
	fail(pDiag == NULL);
392
 
393
	NO_DBG_MSG("vAddFooter");
394
 
395
	pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
396
					odd(iPageCount), bFirstInSection);
397
	bFirstInSection = FALSE;
398
	if (pFtrInfo == NULL ||
399
	    pFtrInfo->pText == NULL ||
400
	    pFtrInfo->lHeight <= 0) {
401
		fail(pFtrInfo != NULL && pFtrInfo->lHeight < 0);
402
		fail(pFtrInfo != NULL &&
403
			pFtrInfo->pText != NULL &&
404
			pFtrInfo->lHeight == 0);
405
		return;
406
	}
407
 
408
	bInFtrSpace = TRUE;
409
 
410
	DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, pFtrInfo->lHeight);
411
	DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, lFooterHeight);
412
	DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
413
			pDiag->lYtop);
414
	DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
415
			lFooterHeight + PS_BOTTOM_MARGIN);
416
 
417
	if (pDiag->lYtop > lFooterHeight + PS_BOTTOM_MARGIN) {
418
		/* Move down to the start of the footer */
419
		pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
420
		vMoveTo(pDiag, 0);
421
	} else if (pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN / 2) {
422
		DBG_FIXME();
423
		/*
424
		 * Move up to the start of the footer, to prevent moving
425
		 * of the bottom edge of the paper
426
		 */
427
		pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
428
		vMoveTo(pDiag, 0);
429
	}
430
 
431
	DBG_FLT_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
432
	dDrawUnits2Points(lFooterHeight + PS_BOTTOM_MARGIN - pDiag->lYtop));
433
 
434
	vAddHdrFtr(pDiag, pFtrInfo);
435
	bInFtrSpace = FALSE;
436
} /* end of vAddFooter */
437
 
438
/*
439
 * vEndPageObject - end the current page object
440
 */
441
static void
442
vEndPageObject(FILE *pOutFile)
443
{
444
	long	lStreamEnd;
445
 
446
	if (lStreamStart < 0) {
447
		/* There is no current page object */
448
		return;
449
	}
450
 
451
	vFPprintf(pOutFile, "ET\n");
452
	lStreamEnd = lFilePosition;
453
	vFPprintf(pOutFile, "endstream\n");
454
	vFPprintf(pOutFile, "endobj\n");
455
 
456
	iObjectNumberCurr++;
457
	vSetLocation(iObjectNumberCurr);
458
	vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
459
	vFPprintf(pOutFile, "%lu\n", lStreamEnd - lStreamStart);
460
	vFPprintf(pOutFile, "endobj\n");
461
} /* end of vEndPageObject */
462
 
463
/*
464
 * vMove2NextPage - move to the start of the next page
465
 */
466
static void
467
vMove2NextPage(diagram_type *pDiag, BOOL bNewSection)
468
{
469
	FILE	*pOutFile;
470
 
471
	fail(pDiag == NULL);
472
	fail(pDiag->pOutFile == NULL);
473
 
474
	pOutFile = pDiag->pOutFile;
475
 
476
	vAddFooter(pDiag);
477
	/* End the old page object */
478
	vEndPageObject(pOutFile);
479
	if (bNewSection) {
480
		iSectionIndex++;
481
		bFirstInSection = TRUE;
482
	}
483
 
484
	/* Start the new page object */
485
	iObjectNumberCurr++;
486
	vSetLocation(iObjectNumberCurr);
487
	vFillNextPageObject();
488
	vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
489
	vFPprintf(pOutFile, "<<\n");
490
	vFPprintf(pOutFile, "/Type /Page\n");
491
	vFPprintf(pOutFile, "/Parent 3 0 R\n");
492
	vFPprintf(pOutFile, "/Resources 17 0 R\n");
493
	vFPprintf(pOutFile, "/Contents %d 0 R\n", iObjectNumberCurr + 1);
494
	vFPprintf(pOutFile, ">>\n");
495
	vFPprintf(pOutFile, "endobj\n");
496
 
497
	/* Start the new text object */
498
	iObjectNumberCurr++;
499
	vSetLocation(iObjectNumberCurr);
500
	vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
501
	vFPprintf(pOutFile, "<<\n");
502
	vFPprintf(pOutFile, "/Length %d 0 R\n", iObjectNumberCurr + 1);
503
	vFPprintf(pOutFile, ">>\n");
504
	vFPprintf(pOutFile, "stream\n");
505
	lStreamStart = lFilePosition;
506
	vFPprintf(pOutFile, "BT\n");
507
 
508
	/* Set variables to their start of page values */
509
	pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
510
	tFontRefCurr = (drawfile_fontref)-1;
511
	usFontSizeCurr = 0;
512
	iFontColorCurr = -1;
513
	lYtopCurr = -1;
514
	vAddHeader(pDiag);
515
} /* end of vMove2NextPage */
516
 
517
/*
518
 * vMoveTo - move to the specified X,Y coordinates
519
 *
520
 * Move the current position of the specified diagram to its X,Y coordinates,
521
 * start on a new page if needed
522
 */
523
static void
524
vMoveTo(diagram_type *pDiag, long lLastVerticalMovement)
525
{
526
	fail(pDiag == NULL);
527
	fail(pDiag->pOutFile == NULL);
528
 
529
	if (pDiag->lYtop <= lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace) {
530
		vMove2NextPage(pDiag, FALSE);
531
		/* Repeat the last vertical movement on the new page */
532
		pDiag->lYtop -= lLastVerticalMovement;
533
	}
534
 
535
	fail(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace);
536
	DBG_DEC_C(pDiag->lYtop < PS_BOTTOM_MARGIN, pDiag->lYtop);
537
	fail(pDiag->lYtop < PS_BOTTOM_MARGIN / 3);
538
 
539
	if (pDiag->lYtop != lYtopCurr) {
540
		vFPprintf(pDiag->pOutFile, "1 0 0 1 %.2f %.2f Tm\n",
541
			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
542
			dDrawUnits2Points(pDiag->lYtop));
543
		lYtopCurr = pDiag->lYtop;
544
	}
545
} /* end of vMoveTo */
546
 
547
/*
548
 * vProloguePDF - set options and perform the PDF initialization
549
 */
550
void
551
vProloguePDF(diagram_type *pDiag,
552
	const char *szTask, const options_type *pOptions)
553
{
554
	FILE	*pOutFile;
555
 
556
	fail(pDiag == NULL);
557
	fail(pDiag->pOutFile == NULL);
558
	fail(pOptions == NULL);
559
 
560
	pOutFile = pDiag->pOutFile;
561
 
562
	eEncoding = pOptions->eEncoding;
563
 
564
	/* Create an empty location array */
565
	tLocations = INITIAL_LOCATION_SIZE;
566
	alLocation = xcalloc(tLocations, sizeof(long));
567
 
568
	/* Create an empty pageobject array */
569
	tMaxPageObjects = INITIAL_PAGEOBJECT_SIZE;
570
	aiPageObject = xcalloc(tMaxPageObjects, sizeof(int));
571
 
572
	if (pOptions->iPageHeight == INT_MAX) {
573
		lPageHeight = LONG_MAX;
574
	} else {
575
		lPageHeight = lPoints2DrawUnits(pOptions->iPageHeight);
576
	}
577
	DBG_DEC(lPageHeight);
578
	if (pOptions->iPageWidth == INT_MAX) {
579
		lPageWidth = LONG_MAX;
580
	} else {
581
		lPageWidth = lPoints2DrawUnits(pOptions->iPageWidth);
582
	}
583
	DBG_DEC(lPageWidth);
584
	lFooterHeight = 0;
585
	bInFtrSpace = FALSE;
586
 
587
	tFontRefCurr = (drawfile_fontref)-1;
588
	usFontSizeCurr = 0;
589
	iFontColorCurr = -1;
590
	lYtopCurr = -1;
591
	iPageCount = 0;
592
	iImageCount = 0;
593
	iSectionIndex = 0;
594
	bFirstInSection = TRUE;
595
	lFilePosition = 0;
596
	iMaxLocationNumber = 0;
597
	lStreamStart = -1;
598
	iObjectNumberCurr = 17;
599
	pDiag->lXleft = 0;
600
	pDiag->lYtop = 0;
601
 
602
	szProducer = szTask;
603
 
604
	vFPprintf(pOutFile, "%%PDF-1.3\n");
605
	vFPprintf(pOutFile, "%%%c%c%c%c\n", 0xe2, 0xe3, 0xcf, 0xd3);
606
 
607
	/* Root catalog */
608
	vSetLocation(1);
609
	vFPprintf(pOutFile, "1 0 obj\n");
610
	vFPprintf(pOutFile, "<<\n");
611
	vFPprintf(pOutFile, "/Type /Catalog\n");
612
	vFPprintf(pOutFile, "/Pages 3 0 R\n");
613
	vFPprintf(pOutFile, ">>\n");
614
	vFPprintf(pOutFile, "endobj\n");
615
} /* end of vProloguePDF */
616
 
617
/*
618
 * vEpiloguePDF - clean up after everything is done
619
 */
620
void
621
vEpiloguePDF(diagram_type *pDiag)
622
{
623
	FILE	*pOutFile;
624
	long	lXref;
625
	int	iIndex;
626
 
627
	fail(pDiag == NULL);
628
	fail(pDiag->pOutFile == NULL);
629
 
630
	pOutFile = pDiag->pOutFile;
631
 
632
	vAddFooter(pDiag);
633
	/* End the old page object */
634
	vEndPageObject(pOutFile);
635
 
636
	vSetLocation(3);
637
	vFPprintf(pOutFile, "3 0 obj\n");
638
	vFPprintf(pOutFile, "<<\n");
639
	vFPprintf(pOutFile, "/Type /Pages\n");
640
	vFPprintf(pOutFile, "/Count %d\n", iPageCount);
641
	vFPprintf(pOutFile, "/MediaBox [ 0 0 %.0f %.0f ]\n",
642
			dDrawUnits2Points(lPageWidth),
643
			dDrawUnits2Points(lPageHeight));
644
	vFPprintf(pOutFile, "/Kids [ ");
645
	for (iIndex = 1; iIndex <= iPageCount; iIndex++) {
646
		vFPprintf(pOutFile, "\t%d 0 R\n", aiPageObject[iIndex]);
647
	}
648
	vFPprintf(pOutFile, "]\n");
649
	vFPprintf(pOutFile, ">>\n");
650
	vFPprintf(pOutFile, "endobj\n");
651
 
652
	lXref = lFilePosition;
653
 
654
	vFPprintf(pOutFile, "xref\n");
655
	vFPprintf(pOutFile, "0 %d\n", iMaxLocationNumber + 1);
656
	vFPprintf(pOutFile, "0000000000 65535 f \n");
657
	for (iIndex = 1; iIndex <= iMaxLocationNumber; iIndex++) {
658
		vFPprintf(pOutFile, "%.10ld 00000 n \n", alLocation[iIndex]);
659
	}
660
 
661
	vFPprintf(pOutFile, "trailer\n");
662
	vFPprintf(pOutFile, "<<\n");
663
	vFPprintf(pOutFile, "/Size %d\n", iMaxLocationNumber + 1);
664
	vFPprintf(pOutFile, "/Root 1 0 R\n");
665
	vFPprintf(pOutFile, "/Info 2 0 R\n");
666
	vFPprintf(pOutFile, ">>\n");
667
 
668
	vFPprintf(pOutFile, "startxref\n");
669
	vFPprintf(pOutFile, "%ld\n", lXref);
670
	vFPprintf(pOutFile, "%%%%EOF\n");
671
 
672
	szProducer = NULL;
673
	aiPageObject = xfree(aiPageObject);
674
	alLocation = xfree(alLocation);
675
} /* end of vEpiloguePDF */
676
 
677
/*
678
 * vPrintPalette - print a pdf color space (palette)
679
 */
680
static void
681
vPrintPalette(FILE *pOutFile, const imagedata_type *pImg)
682
{
683
	int	iIndex;
684
 
685
	fail(pOutFile == NULL);
686
	fail(pImg == NULL);
687
	fail(pImg->iColorsUsed < 2);
688
	fail(pImg->iColorsUsed > 256);
689
 
690
	vFPprintf(pOutFile, "\t/ColorSpace [ /Indexed\n");
691
	vFPprintf(pOutFile, "\t/Device%s %d\n",
692
		pImg->bColorImage ? "RGB" : "Gray", pImg->iColorsUsed - 1);
693
	vFPprintf(pOutFile, "<");
694
	for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
695
		vFPprintf(pOutFile, "%02x",
696
				(unsigned int)pImg->aucPalette[iIndex][0]);
697
		if (pImg->bColorImage) {
698
			vFPprintf(pOutFile, "%02x%02x",
699
				(unsigned int)pImg->aucPalette[iIndex][1],
700
				(unsigned int)pImg->aucPalette[iIndex][2]);
701
		}
702
		if (iIndex % 8 == 7) {
703
			vFPprintf(pOutFile, "\n");
704
		} else {
705
			vFPprintf(pOutFile, " ");
706
		}
707
	}
708
	vFPprintf(pOutFile, "> ]\n");
709
} /* end of vPrintPalette */
710
 
711
/*
712
 * vImageProloguePDF - perform the image initialization
713
 */
714
void
715
vImageProloguePDF(diagram_type *pDiag, const imagedata_type *pImg)
716
{
717
	FILE	*pOutFile;
718
 
719
	fail(pDiag == NULL);
720
	fail(pDiag->pOutFile == NULL);
721
	fail(pImg == NULL);
722
 
723
	if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
724
		return;
725
	}
726
 
727
	iImageCount++;
728
 
729
	DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
730
 
731
	pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
732
	vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
733
 
734
	pOutFile = pDiag->pOutFile;
735
 
736
	vFPprintf(pOutFile, "ET\n");
737
	vFPprintf(pOutFile, "q %% Image %03d\n", iImageCount);
738
	if (pImg->eImageType == imagetype_is_dib) {
739
		/* Scanning from left to right and bottom to top */
740
		vFPprintf(pOutFile, "%d 0 0 %d %.2f %.2f cm\n",
741
			pImg->iHorSizeScaled, -pImg->iVerSizeScaled,
742
			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
743
			dDrawUnits2Points(pDiag->lYtop) + pImg->iVerSizeScaled);
744
	} else {
745
		/* Scanning from left to right and top to bottom */
746
		vFPprintf(pOutFile, "%d 0 0 %d %.2f %.2f cm\n",
747
			pImg->iHorSizeScaled, pImg->iVerSizeScaled,
748
			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
749
			dDrawUnits2Points(pDiag->lYtop));
750
	}
751
	vFPprintf(pOutFile, "BI\n");
752
	vFPprintf(pOutFile, "\t/Width %d\n", pImg->iWidth);
753
	vFPprintf(pOutFile, "\t/Height %d\n", pImg->iHeight);
754
	switch (pImg->eImageType) {
755
	case imagetype_is_jpeg:
756
		switch (pImg->iComponents) {
757
		case 1:
758
			vFPprintf(pOutFile, "\t/ColorSpace /DeviceGray\n");
759
			break;
760
		case 3:
761
			vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
762
			break;
763
		case 4:
764
			vFPprintf(pOutFile, "\t/ColorSpace /DeviceCMYK\n");
765
			if (pImg->bAdobe) {
766
				/*
767
				 * Adobe-conforming CMYK file
768
				 * applying workaround for color inversion
769
				 */
770
				vFPprintf(pOutFile,
771
					"\t/Decode [1 0 1 0 1 0 1 0]\n");
772
			}
773
			break;
774
		default:
775
			DBG_DEC(pImg->iComponents);
776
			break;
777
		}
778
		vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
779
		vFPprintf(pOutFile,
780
			"\t/Filter [ /ASCII85Decode /DCTDecode ]\n");
781
		break;
782
	case imagetype_is_png:
783
		if (pImg->iComponents == 3 || pImg->iComponents == 4) {
784
			vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
785
			vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
786
		} else if (pImg->iColorsUsed > 0) {
787
			vPrintPalette(pOutFile, pImg);
788
			fail(pImg->uiBitsPerComponent > 8);
789
			vFPprintf(pOutFile, "\t/BitsPerComponent %u\n",
790
					pImg->uiBitsPerComponent);
791
		} else {
792
			vFPprintf(pOutFile, "\t/ColorSpace /DeviceGray\n");
793
			vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
794
		}
795
		vFPprintf(pOutFile,
796
			"\t/Filter [ /ASCII85Decode /FlateDecode ]\n");
797
		vFPprintf(pOutFile, "\t/DecodeParms [ null <<\n");
798
		vFPprintf(pOutFile, "\t\t/Predictor 10\n");
799
		vFPprintf(pOutFile, "\t\t/Colors %d\n", pImg->iComponents);
800
		vFPprintf(pOutFile, "\t\t/BitsPerComponent %u\n",
801
						pImg->uiBitsPerComponent);
802
		vFPprintf(pOutFile, "\t\t/Columns %d\n", pImg->iWidth);
803
		vFPprintf(pOutFile, "\t\t>> ]\n");
804
		break;
805
	case imagetype_is_dib:
806
		if (pImg->uiBitsPerComponent <= 8) {
807
			vPrintPalette(pOutFile, pImg);
808
		} else {
809
			vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
810
		}
811
		vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
812
		vFPprintf(pOutFile, "\t/Filter /ASCII85Decode\n");
813
		break;
814
	default:
815
		vFPprintf(pOutFile, "\t/ColorSpace /Device%s\n",
816
			pImg->bColorImage ? "RGB" : "Gray");
817
		vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
818
		vFPprintf(pOutFile, "\t/Filter /ASCIIHexDecode\n");
819
		break;
820
	}
821
	vFPprintf(pOutFile, "ID\n");
822
} /* end of vImageProloguePDF */
823
 
824
/*
825
 * vImageEpiloguePDF - clean up after the image
826
 */
827
void
828
vImageEpiloguePDF(diagram_type *pDiag)
829
{
830
	FILE	*pOutFile;
831
 
832
	fail(pDiag == NULL);
833
	fail(pDiag->pOutFile == NULL);
834
 
835
	pOutFile = pDiag->pOutFile;
836
 
837
	/* Correction for the image bytes */
838
	lFilePosition = ftell(pOutFile);
839
 
840
	vFPprintf(pOutFile, "EI\n");
841
	vFPprintf(pOutFile, "Q\n");
842
	vFPprintf(pOutFile, "BT\n");
843
 
844
	pDiag->lXleft = 0;
845
} /* end of vImageEpiloguePDF */
846
 
847
/*
848
 * bAddDummyImagePDF - add a dummy image
849
 *
850
 * return TRUE when successful, otherwise FALSE
851
 */
852
BOOL
853
bAddDummyImagePDF(diagram_type *pDiag, const imagedata_type *pImg)
854
{
855
	FILE	*pOutFile;
856
 
857
	fail(pDiag == NULL);
858
	fail(pDiag->pOutFile == NULL);
859
	fail(pImg == NULL);
860
 
861
	if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
862
		return FALSE;
863
	}
864
 
865
	iImageCount++;
866
 
867
	DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
868
 
869
	pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
870
	vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
871
 
872
	pOutFile = pDiag->pOutFile;
873
 
874
	vFPprintf(pOutFile, "ET\n");
875
	vFPprintf(pOutFile, "q %% Image %03d\n", iImageCount);
876
	vFPprintf(pOutFile, "\t1.0 w\n");
877
	vFPprintf(pOutFile, "\t0.3 G\n");
878
	vFPprintf(pOutFile, "\t%.2f %.2f %d %d re\n",
879
			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
880
			dDrawUnits2Points(pDiag->lYtop),
881
			pImg->iHorSizeScaled,
882
			pImg->iVerSizeScaled);
883
	vFPprintf(pOutFile, "\tS\n");
884
	vFPprintf(pOutFile, "Q\n");
885
	vFPprintf(pOutFile, "BT\n");
886
 
887
	pDiag->lXleft = 0;
888
 
889
	return TRUE;
890
} /* end of bAddDummyImagePDF */
891
 
892
/*
893
 * vAddFontsPDF - add the font information
894
 */
895
void
896
vAddFontsPDF(diagram_type *pDiag)
897
{
898
	FILE	*pOutFile;
899
	size_t	tIndex;
900
 
901
	fail(pDiag == NULL);
902
	fail(pDiag->pOutFile == NULL);
903
 
904
	pOutFile = pDiag->pOutFile;
905
 
906
	/* The font encoding */
907
	vSetLocation(4);
908
	vFPprintf(pOutFile, "4 0 obj\n");
909
	vFPprintf(pOutFile, "<<\n");
910
	vFPprintf(pOutFile, "/Type /Encoding\n");
911
	vFPprintf(pOutFile, "/BaseEncoding /StandardEncoding\n");
912
	vFPprintf(pOutFile, "/Differences [\n");
913
	switch (eEncoding) {
914
	case encoding_latin_1:
915
		for (tIndex = 0;
916
		     tIndex < elementsof(iso_8859_1);
917
		     tIndex++) {
918
			vFPprintf(pOutFile, "%s\n", iso_8859_1[tIndex]);
919
		}
920
		break;
921
	case encoding_latin_2:
922
		for (tIndex = 0;
923
		     tIndex < elementsof(iso_8859_2);
924
		     tIndex++) {
925
			vFPprintf(pOutFile, "%s\n", iso_8859_2[tIndex]);
926
		}
927
		break;
928
	case encoding_cyrillic:
929
		werr(1,
930
		"The combination PDF and Cyrillic is not supported");
931
		break;
932
	case encoding_utf_8:
933
		werr(1,
934
		"The combination PDF and UTF-8 is not supported");
935
		break;
936
	default:
937
		DBG_DEC(eEncoding);
938
		break;
939
	}
940
	vFPprintf(pOutFile, "]\n");
941
	vFPprintf(pOutFile, ">>\n");
942
	vFPprintf(pOutFile, "endobj\n");
943
 
944
	/* Twelve of the standard type 1 fonts */
945
	for (tIndex = 0; tIndex < 12; tIndex++) {
946
		vSetLocation(5 + tIndex);
947
		vFPprintf(pOutFile, "%u 0 obj\n", 5 + tIndex);
948
		vFPprintf(pOutFile, "<<\n");
949
		vFPprintf(pOutFile, "/Type /Font\n");
950
		vFPprintf(pOutFile, "/Subtype /Type1\n");
951
		vFPprintf(pOutFile, "/Name /F%u\n", 1 + tIndex);
952
		vFPprintf(pOutFile, "/BaseFont /%s\n",
953
						atFontname[tIndex].szPDFname);
954
		vFPprintf(pOutFile, "/Encoding 4 0 R\n");
955
		vFPprintf(pOutFile, ">>\n");
956
		vFPprintf(pOutFile, "endobj\n");
957
	}
958
 
959
	/* The Resources */
960
	vSetLocation(17);
961
	vFPprintf(pOutFile, "17 0 obj\n");
962
	vFPprintf(pOutFile, "<<\n");
963
	vFPprintf(pOutFile, "/ProcSet [ /PDF /Text ]\n");
964
	vFPprintf(pOutFile, "/Font <<\n");
965
	for (tIndex = 0; tIndex < 12; tIndex++) {
966
		vFPprintf(pOutFile, "\t/F%u %u 0 R\n", 1 + tIndex, 5 + tIndex);
967
	}
968
	vFPprintf(pOutFile, "\t>>\n");
969
	vFPprintf(pOutFile, ">>\n");
970
	vFPprintf(pOutFile, "endobj\n");
971
	vAddHeader(pDiag);
972
} /* end of vAddFontsPDF */
973
 
974
/*
975
 * vPrintPDF - print a PDF string
976
 */
977
static void
978
vPrintPDF(FILE *pFile, const char *szString, size_t tStringLength,
979
	USHORT usFontstyle)
980
{
981
	const UCHAR	*aucBytes;
982
	double	dMove;
983
	size_t	tCount;
984
 
985
	fail(szString == NULL);
986
 
987
	if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
988
		return;
989
	}
990
	DBG_DEC_C(usFontSizeCurr < MIN_FONT_SIZE, usFontSizeCurr);
991
 
992
	dMove = 0.0;
993
 
994
	/* Up for superscript */
995
	if (bIsSuperscript(usFontstyle) && usFontSizeCurr != 0) {
996
		dMove = (double)((usFontSizeCurr + 1) / 2) * 0.375;
997
		vFPprintf(pFile, "%.2f Ts\n", dMove);
998
	}
999
 
1000
	/* Down for subscript */
1001
	if (bIsSubscript(usFontstyle) && usFontSizeCurr != 0) {
1002
		dMove = (double)usFontSizeCurr * 0.125;
1003
		vFPprintf(pFile, "%.2f Ts\n", -dMove);
1004
	}
1005
 
1006
	/* Generate and print the PDF output */
1007
	aucBytes = (UCHAR *)szString;
1008
	vFPprintf(pFile, "(");
1009
	for (tCount = 0; tCount < tStringLength ; tCount++) {
1010
		switch (aucBytes[tCount]) {
1011
		case '(':
1012
		case ')':
1013
		case '\\':
1014
			vFPprintf(pFile, "\\%c", szString[tCount]);
1015
			break;
1016
		default:
1017
			if (aucBytes[tCount] < 0x20 ||
1018
			    aucBytes[tCount] == 0x7f ||
1019
			    (aucBytes[tCount] >= 0x81 &&
1020
			     aucBytes[tCount] < 0x8c)) {
1021
				DBG_HEX(aucBytes[tCount]);
1022
				vFPprintf(pFile, " ");
1023
			} else if (aucBytes[tCount] >= 0x80) {
1024
				vFPprintf(pFile, "\\%03o",
1025
						(UINT)aucBytes[tCount]);
1026
			} else {
1027
				vFPprintf(pFile, "%c", szString[tCount]);
1028
			}
1029
			break;
1030
		}
1031
	}
1032
	vFPprintf(pFile, ") Tj\n");
1033
 
1034
	/* Undo the superscript/subscript move */
1035
	if (dMove != 0.0) {
1036
		vFPprintf(pFile, "0 Ts\n");
1037
	}
1038
} /* end of vPrintPDF */
1039
 
1040
/*
1041
 * vSetColor - move to the specified color
1042
 */
1043
static void
1044
vSetColor(FILE *pFile, UCHAR ucFontColor)
1045
{
1046
	ULONG	ulTmp, ulRed, ulGreen, ulBlue;
1047
 
1048
	ulTmp = ulColor2Color(ucFontColor);
1049
	ulRed   = (ulTmp & 0x0000ff00) >> 8;
1050
	ulGreen = (ulTmp & 0x00ff0000) >> 16;
1051
	ulBlue  = (ulTmp & 0xff000000) >> 24;
1052
	vFPprintf(pFile, "%.3f %.3f %.3f rg\n",
1053
			ulRed / 255.0, ulGreen / 255.0, ulBlue / 255.0);
1054
} /* end of vSetColor */
1055
 
1056
/*
1057
 * vMove2NextLinePDF - move to the next line
1058
 */
1059
void
1060
vMove2NextLinePDF(diagram_type *pDiag, USHORT usFontSize)
1061
{
1062
	fail(pDiag == NULL);
1063
	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1064
 
1065
	pDiag->lYtop -= lComputeLeading(usFontSize);
1066
} /* end of vMove2NextLinePDF */
1067
 
1068
/*
1069
 * vSubstringPDF - print a sub string
1070
 */
1071
void
1072
vSubstringPDF(diagram_type *pDiag,
1073
	char *szString, size_t tStringLength, long lStringWidth,
1074
	UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
1075
	USHORT usFontSize, USHORT usMaxFontSize)
1076
{
1077
	size_t	tFontIndex;
1078
 
1079
	fail(pDiag == NULL || szString == NULL);
1080
	fail(pDiag->pOutFile == NULL);
1081
	fail(pDiag->lXleft < 0);
1082
	fail(tStringLength != strlen(szString));
1083
	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1084
	fail(usMaxFontSize < MIN_FONT_SIZE || usMaxFontSize > MAX_FONT_SIZE);
1085
	fail(usFontSize > usMaxFontSize);
1086
 
1087
	if (szString[0] == '\0' || tStringLength == 0) {
1088
		return;
1089
	}
1090
 
1091
	vMoveTo(pDiag, lComputeLeading(usMaxFontSize));
1092
	if (tFontRef != tFontRefCurr || usFontSize != usFontSizeCurr) {
1093
		tFontIndex = tGetFontIndex(tFontRef);
1094
		vFPprintf(pDiag->pOutFile, "/F%u %.1f Tf\n",
1095
			 1 + tFontIndex, (double)usFontSize / 2.0);
1096
		tFontRefCurr = tFontRef;
1097
		usFontSizeCurr = usFontSize;
1098
	}
1099
	if ((int)ucFontColor != iFontColorCurr) {
1100
		vSetColor(pDiag->pOutFile, ucFontColor);
1101
		iFontColorCurr = (int)ucFontColor;
1102
	}
1103
	vPrintPDF(pDiag->pOutFile, szString, tStringLength, usFontstyle);
1104
	pDiag->lXleft += lStringWidth;
1105
} /* end of vSubstringPDF */
1106
 
1107
/*
1108
 * Create an start of paragraph by moving the y-top mark
1109
 */
1110
void
1111
vStartOfParagraphPDF(diagram_type *pDiag, long lBeforeIndentation)
1112
{
1113
	fail(pDiag == NULL);
1114
	fail(lBeforeIndentation < 0);
1115
 
1116
	pDiag->lXleft = 0;
1117
	pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
1118
} /* end of vStartOfParagraphPDF */
1119
 
1120
/*
1121
 * Create an end of paragraph by moving the y-top mark
1122
 */
1123
void
1124
vEndOfParagraphPDF(diagram_type *pDiag,
1125
	USHORT usFontSize, long lAfterIndentation)
1126
{
1127
	fail(pDiag == NULL);
1128
	fail(pDiag->pOutFile == NULL);
1129
	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1130
	fail(lAfterIndentation < 0);
1131
 
1132
	if (pDiag->lXleft > 0) {
1133
		/* To the start of the line */
1134
		vMove2NextLinePDF(pDiag, usFontSize);
1135
	}
1136
 
1137
	pDiag->lXleft = 0;
1138
	pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
1139
} /* end of vEndOfParagraphPDF */
1140
 
1141
/*
1142
 * Create an end of page
1143
 */
1144
void
1145
vEndOfPagePDF(diagram_type *pDiag, BOOL bNewSection)
1146
{
1147
	vMove2NextPage(pDiag, bNewSection);
1148
} /* end of vEndOfPagePDF */