1 /*
2  * Copyright � 1992, 1993, 1999, 2000, 2001 Free Software Foundation, Inc.
3  *
4  * $Id: print.c,v 1.33 2001/02/13 23:38:06 danny Exp $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this software; see the file COPYING.  If not, write to
18  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 /*
22  * This is Oleo's general print driver.
23  *
24  * It calls PostScript, PCL, or other modules in order to print to
25  * specific hardware.
26  *
27  * In this file, all dimensions are to be specified in points,
28  * which are a measurement 1/72 of an inch (roughly 1/3 of a
29  * millimeter).
30  *
31  * Mainly, this file contains the function print_region_cmd().
32  *
33  * The functionality is :
34  *	figure out total width,height of the region to be printed
35  *	based on the width,height of the cells, not the cell contents
36  *	determine number of pages to print from the total width,height
37  *	run through the whole region (left to right and top to bottom),
38  *		beginning a new page when necessary
39  *	(allow for overlapping cells)
40  *	(use the indicated font)
41  */
42 
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 
47 #ifdef	WITH_DMALLOC
48 #include <dmalloc.h>
49 #endif
50 
51 #include <stdio.h>
52 #include <ctype.h>
53 #include <stdlib.h>
54 
55 #include "display.h"
56 #include "font.h"
57 #include "global.h"
58 #include "cmd.h"
59 #include "io-generic.h"
60 #include "io-abstract.h"
61 #include "io-utils.h"
62 #include "lists.h"
63 
64 #include "print.h"
65 #include "afm.h"
66 
67 /*
68  * Add an include line for new printer types here
69  */
70 #include "pcl.h"
71 #include "postscript.h"
72 #include "epson.h"
73 #include "prtext.h"
74 
75 /*
76  * Add a pointer to the printer type structure here
77  */
78 
79 static struct PrintDriver *Drivers[] = {
80 	&PostScriptPrintDriver,
81 	&PCLPrintDriver,
82 #if 0
83 	&EpsonStylusColorPrintDriver,
84 #endif
85 	&TextPrintDriver,
86 	NULL
87 };
88 
89 /* That should be all you need to do for adding printer types.  */
90 
91 static int NumPrintDrivers = (sizeof(Drivers) / sizeof(struct PrintDriver *)) - 1;
92 
93 /*
94  * Default page dimensions
95  */
96 float default_pswid = 612;
97 float default_pshgt = 792;
98 
99 /*
100  * Default font
101  */
102 static char	*default_font_family = "CGTimes",
103 		*default_font_slant = NULL;
104 static int	default_font_size = 10;
105 
106 static struct page_size size_table[] =
107 {
108   { "letter",       612,  792     }, /* (8.5 x 11  in.)   */
109   { "landscape",    792,  612     }, /* (11 x 8.5  in.)   */
110   { "tabloid",      792,  1224    }, /* (11 x 17  in.)    */
111   { "ledger",       1224, 792     }, /* (17 x 11  in.)    */
112   { "legal",        612,  1008    }, /* (8.5 x 14  in.)   */
113   { "statement",    396,  612     }, /* (5.5 x 8.5 in.)   */
114   { "executive",    540,  720     }, /* (7.5 x 10  in.)   */
115   { "a3",           842,  1190    },
116   { "a4",           595,  842     },
117   { "latex-a4",     523,  770     }, /* A4 - 1in margins all round */
118   { "a5",           420,  595     },
119   { "b4",           729,  1032    },
120   { "b5",           516,  729     },
121   { "folio",        612,  936     }, /* (8.5 x 13  in.)   */
122   { "quarto",       610,  780     }
123 };
124 
125 struct page_size *
find_size(char * size,int len)126 find_size( char * size, int len )
127 {
128   int i;
129   struct page_size *p = size_table;
130 
131   for (i = 0;
132        i < sizeof(size_table)/sizeof(struct page_size);
133        i++, p++)
134     if (strincmp (size, p->name, len) == 0 )
135       return p;
136   return 0;
137 }
138 
139 int
PrintGetNumPageSizes(void)140 PrintGetNumPageSizes(void)
141 {
142 	return sizeof(size_table) / sizeof(struct page_size);
143 }
144 
145 char *
PrintGetPageName(int index)146 PrintGetPageName(int index)
147 {
148 	if (index < 0 ||
149 		index > (sizeof(size_table) / sizeof(struct page_size)))
150 	    return NULL;
151 	return size_table[index].name;
152 }
153 
154 void
PrintSetType(char * format)155 PrintSetType(char *format)
156 {
157 	int	i;
158 
159 	for (i=0; i<NumPrintDrivers; i++)
160 		if (strcmp(Drivers[i]->name, format) == 0) {
161 			Global->CurrentPrintDriver = Drivers[i];
162 			return;
163 		}
164 }
165 
166 /* Allow Motif interface to query supported printers */
167 char *
PrintGetType(int i)168 PrintGetType(int i)
169 {
170 	if (i < 0 || i >= NumPrintDrivers)
171 		return NULL;
172 	return Drivers[i]->name;
173 }
174 
175 void
PrintSetPageSize(float wid,float ht)176 PrintSetPageSize(float wid, float ht)
177 {
178 	default_pswid = wid;
179 	default_pshgt = ht;
180 }
181 
182 void
PrintSetPage(char * page)183 PrintSetPage(char *page)
184 {
185 	int	i;
186 
187 	for (i=0; i < (sizeof(size_table) / sizeof(struct page_size)); i++)
188 		if (strcmp(size_table[i].name, page) == 0) {
189 			default_pswid = size_table[i].wid;
190 			default_pshgt = size_table[i].hgt;
191 
192 			return;
193 		}
194 	/* This should never happen */
195       io_error_msg("PrintSetPage: Bad page size %s.", page);
196 }
197 
198 /*
199  * Front end to PostScript printing :
200  *	set_page_size_cmd
201  *	psprint_region_cmd
202  */
203 
204 void
set_page_size_cmd(char * whole_str)205 set_page_size_cmd (char * whole_str)
206 {
207 	char * str = whole_str;
208 	float neww;
209 	float newh;
210 
211 	while (*str && isspace(*str))
212 		++str;
213 	if (!isdigit (*str) && *str != '.') {
214 		char * end = str;
215 		struct page_size * ps;
216 
217 		while (*end && !isspace(*end))
218 			++end;
219 		ps = find_size (str, end - str);
220 		if (ps) {
221 			default_pswid = ps->wid;
222 			default_pshgt = ps->hgt;
223 			return;
224 		}
225 		io_error_msg("Bad page size (should look like `8.5 x 11' or `21.6 x 28c'): %s.",
226 			whole_str);
227 		return;
228 	}
229 	neww = atof (str);
230 	while (*str && isdigit(*str))
231 		++str;
232 	if (*str == '.') {
233 		++str;
234 		while (isdigit (*str))
235 			++str;
236 	}
237 	while (*str && isspace(*str))
238 		++str;
239 	if (*str == 'x') {
240 		++str;
241 		while (*str && isspace(*str))
242 			++str;
243 	}
244 	if (!isdigit (*str) && *str != '.') {
245 		io_error_msg("Bad page size (should look like `8.5 x 11' or `21.6 x 28c'): %s.",
246 			whole_str);
247 		return;
248 	}
249 	newh = atof (str);
250 	while (*str && isdigit(*str))
251 		++str;
252 	if (*str == '.') {
253 		++str;
254 		while (*str && isdigit (*str))
255 			++str;
256 	}
257 	while (*str && isspace(*str))
258 		++str;
259 	if (*str == 'c') {
260 		neww *= .3937;
261 		newh *= .3937;
262 	}
263 	if (*str != 'p') {
264 		default_pswid = neww * 72;
265 		default_pshgt = newh * 72;
266 	}
267 }
268 
269 void
print_region_cmd(struct rng * print,FILE * fp)270 print_region_cmd (struct rng *print, FILE *fp)
271 {
272 	CELLREF rr, cc;
273 	CELL *cp;
274 	char *ptr;
275 	int w;
276 	int spaces;
277 	CELLREF c_lo, c_hi;
278 	int	print_width, print_height, totht, totwid,
279 		ht, npages, next, current_size,
280 		xpoints, xspaces, xpointsafter;
281 	char	pg[32];
282 	char	*title = NULL;
283 
284 	/* Font heights */
285 	int	*heights = NULL, i;
286 
287 #if 0
288 	Global->zoom = 0.5;
289 #endif
290 
291 	/* Figure out page width and height */
292 	print_width = default_pswid;
293 	print_height = default_pshgt;
294 
295 	/* Set default font */
296 	AfmSetFont(default_font_family, default_font_slant, Global->zoom * default_font_size);
297 
298 	/* Figure out #pages */
299 		/* Depends on all fonts used, but also on zoom options chosen */
300 		/* Sometimes preset (zoom -> 1 page),
301 		 * sometimes need to scan the whole range */
302 		/* FIX ME */
303 	totht = totwid = 0;
304 
305 	heights = calloc(print->hr - print->lr + 1, sizeof(int));
306 
307 	for (rr = print->lr, i=0; rr <= print->hr; rr++, i++) {
308 		/* Find largest font on the row */
309 		current_size = 0;
310 		for (cc = print->lc; cc <= print->hc; cc++) {
311 			cp = find_cell(rr, cc);
312 
313 			if (cp && cp->cell_font && cp->cell_font->names) {
314 				if (current_size < cp->cell_font->scale * Global->zoom
315 								* default_font_size) {
316 					current_size = Global->zoom *
317 						cp->cell_font->scale * default_font_size;
318 
319 					AfmSetFont(cp->cell_font->names->ps_name,
320 						default_font_slant,
321 						current_size);
322 				}
323 			}
324 		}
325 		heights[i] += get_height(rr) * AfmFontHeight();
326 		totht += heights[i] + Global->interline * Global->zoom;
327 	}
328 	for (cc = print->lc; cc <= print->hc; cc++) {
329 		totwid += get_width(cc) * AfmFontWidth();;
330 	}
331 
332 	npages = ((print_height - 1 + totht) / print_height)
333 		* ((print_width - 1 + totwid) / print_width);
334 #if 0
335 	fprintf(stderr, PACKAGE " : printing %d pages (totht %d prht %d, totwid %d prwid %d\n",
336 		npages, totht, print_height, totwid, print_width);
337 #endif
338 
339 	/* Build title */
340 	if (FileGetCurrentFileName()) {
341 		title = (char *)malloc(strlen(PACKAGE) + 20 +
342 			strlen(FileGetCurrentFileName()));
343 		sprintf(title, "%s : '%s'", PACKAGE, FileGetCurrentFileName());
344 	} else {
345 		title = (char *)malloc(strlen(PACKAGE) + 20);
346 		sprintf(title, "%s : (no current file)", PACKAGE);
347 	}
348 
349 	/* Start Printing */
350 	Global->CurrentPrintDriver->job_header(title, npages, fp);
351 	Global->CurrentPrintDriver->paper_size(print_width, print_height, fp);
352 	Global->CurrentPrintDriver->set_border(20.0, 20.0, fp);
353 	Global->CurrentPrintDriver->font(default_font_family, default_font_slant,
354 		Global->zoom * default_font_size, fp);
355 
356 	/* Adapted from txt_print_region */
357 	npages = 1;
358 	for (c_lo = print->lc, c_hi = 0; c_hi != print->hc; c_lo = c_hi + 1) {
359 		w = 0;
360 
361 		/* Figure out which columns we can print */
362 		cc = c_lo;
363 
364 		for (w = get_width(cc) * AfmFontWidth();
365 			w <= print_width && cc <= print->hc;
366 			w += get_width(++cc) * AfmFontWidth())
367 		    ;
368 		if (cc != c_lo)
369 			--cc;
370 		c_hi = cc;		/* The last column to print on the current page */
371 
372 		totht = 0;		/* Start counting height taken up on a page */
373 		for (rr = print->lr; rr <= print->hr; rr++) {
374 			/*
375 			* Print a line
376 			*/
377 			if (totht == 0) {
378 				sprintf(pg, "page %d", npages);
379 				Global->CurrentPrintDriver->page_header(pg, fp);
380 				npages++;
381 			}
382 
383 			xpoints = xspaces = 0;	/* FIX ME */
384 			xpointsafter = 0;
385 
386 			/* Add height of next line, not this line */
387 			if (rr != print->hr) {
388 				ht = heights[rr - print->lr];
389 			} else {
390 				;	/* Don't pass array boundary */
391 			}
392 
393 			spaces = 0;
394 			for (cc = c_lo; cc <= c_hi; cc++) {
395 				next = 0;
396 				w = get_width(cc);	/* in spaces */
397 				if (!w) {
398 					xpoints += 10 * Global->zoom;
399 					continue;
400 				}
401 				cp = find_cell(rr, cc);
402 
403 				/* Font */
404 				if (cp && cp->cell_font && cp->cell_font->names) {
405 					current_size = cp->cell_font->scale * default_font_size
406 						* Global->zoom;
407 
408 					if (current_size == 0)
409 						current_size = default_font_size * Global->zoom;
410 
411 					Global->CurrentPrintDriver->font(
412 						cp->cell_font->names->ps_name,
413 						default_font_slant,			/* FIX ME */
414 						current_size,
415 						fp);
416 					AfmSetFont(cp->cell_font->names->ps_name,
417 						default_font_slant,
418 						current_size);
419 				} else {
420 					Global->CurrentPrintDriver->font(default_font_family,
421 						default_font_slant,
422 						default_font_size * Global->zoom,
423 						fp);
424 					AfmSetFont(default_font_family, default_font_slant,
425 						default_font_size * Global->zoom);
426 					current_size = default_font_size * Global->zoom;
427 				}
428 
429 				w = w * current_size;
430 
431 				/*
432 				 * Overlapping cells
433 				 * - figure out whether the text fits the current cell
434 				 * if not :
435 				 * - run over the cells to our immediate right until a non-empty
436 				 *	cell is encountered
437 				 * - determine the width of the empty area in the process
438 				 * - pass this width to the Field()'s second parameter instead
439 				 *	of simply the cell width
440 				 */
441 				ptr = print_cell (cp);
442 #if 0
443 			{ j = GET_JST(cp);
444 				fprintf(stderr, "PrintCell(%d,%d,%s,%s)\n", rr, cc, ptr,
445 					j == JST_DEF ? "JST_DEF" :
446 					j == JST_LFT ? "JST_LFT" :
447 					j == JST_RGT ? "JST_RGT" :
448 					j == JST_CNT ? "JST_CNT" : "??"
449 				);
450 			}
451 #endif
452 				if (AfmStringWidth(ptr) > w)
453 				{
454 					int	i, wtot;
455 
456 					wtot = w;
457 					for (i=cc+1; i<c_hi; i++) {
458 						struct cell *cp = find_cell (rr, i);
459 						if (!cp || GET_FORMAT(cp) == FMT_HID ||
460 								GET_TYP(cp) == 0) {
461 							wtot += get_width(i) * current_size;
462 							xpointsafter += 10 * Global->zoom;
463 							next = i+1;
464 						} else {
465 							i = c_hi;
466 							/* break;	*/
467 						}
468 					}
469 					w = wtot;
470 				}
471 
472 				/*
473 				* Now just print the damn field
474 				*/
475 				cp = find_cell (rr, cc);	/* precaution */
476 
477 				/* Printer doesn't justify */
478 				{
479 					char	*s;
480 					int	sw;
481 
482 					/*
483 					* Madness because we can't always write in the result of
484 					* print_cell. If it's e.g. #NON_NUMBER this is a string in
485 					* a constant array which GCC allocates in read-only memory.
486 					*/
487 					ptr = print_cell (cp);
488 					s = strdup(ptr);
489 					sw = AfmStringWidth(s);
490 					if (sw > w)
491 						if (w > 1) s[w-1] = 0;
492 					/* FIX ME */
493 
494 					switch (GET_JST(cp)) {
495 					case JST_RGT:
496 						Global->CurrentPrintDriver->field(ptr, w, 1,
497 							xpoints + w - sw, xspaces, fp);
498 						break;
499 					case JST_LFT:	/* ??? */
500 						Global->CurrentPrintDriver->field(ptr, w, 1,
501 							xpoints, xspaces, fp);
502 						break;
503 					case JST_CNT:	/* ??? */
504 						Global->CurrentPrintDriver->field(ptr, w, 1,
505 							xpoints + (w - sw) / 2, xspaces, fp);
506 						break;
507 					case JST_DEF:	/* ??? */
508 					default:	/* ??? */
509 						Global->CurrentPrintDriver->field(ptr, w, 1,
510 							xpoints, 0, fp);
511 						break;
512 					}
513 					free(s);
514 
515 					xpoints += w + (10 + xpointsafter) * Global->zoom;
516 					xpointsafter = 0;
517 				}
518 
519 				if (next)
520 					cc = next-1;
521 			}
522 			Global->CurrentPrintDriver->newline(ht + Global->zoom * Global->interline, fp);
523 			totht += ht + Global->interline * Global->zoom;
524 
525 			if (totht + Global->BottomBorderHeight * Global->zoom >= print_height) {
526 				totht = 0;
527 
528 				sprintf(pg, "page %d", npages);
529 				Global->CurrentPrintDriver->page_footer(pg, fp);
530 			}
531 		}	/* Rows on a page */
532 
533 		if (totht != 0) {
534 			totht = 0;
535 			sprintf(pg, "page %d", npages);
536 			Global->CurrentPrintDriver->page_footer(pg, fp);
537 		}
538 	}
539 
540 	if (totht != 0) {
541 	    sprintf(pg, "end page %d", npages);
542 	    Global->CurrentPrintDriver->page_footer(pg, fp);
543 	}
544 	Global->CurrentPrintDriver->job_trailer(npages-1, fp);
545 
546 	free(heights);
547 }
548 
549 void
PrintInit(void)550 PrintInit(void)
551 {
552 	Global->interline = 4;
553 	Global->TopBorderHeight = 0;
554 	Global->BottomBorderHeight = 0;
555 	Global->LeftBorderWidth = 0;
556 	Global->RightBorderWidth = 0;
557 }
558 
559 void
PrintSetInterline(int i)560 PrintSetInterline(int i)
561 {
562 	Global->interline = i;
563 }
564 
565 void
PrintSetEncoding(char * encoding)566 PrintSetEncoding(char *encoding)
567 {
568 	AfmSetEncoding(encoding);
569 	Global->CurrentPrintDriver->set_encoding(encoding);
570 }
571