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