1/*
2 * "$Id: print-papers.c,v 1.41 2008/07/13 18:05:16 rlk Exp $"
3 *
4 *   Print plug-in driver utility functions for the GIMP.
5 *
6 *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
7 *	Robert Krawitz (rlk@alum.mit.edu)
8 *
9 *   This program is free software; you can redistribute it and/or modify it
10 *   under the terms of the GNU General Public License as published by the Free
11 *   Software Foundation; either version 2 of the License, or (at your option)
12 *   any later version.
13 *
14 *   This program is distributed in the hope that it will be useful, but
15 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 *   for more details.
18 *
19 *   You should have received a copy of the GNU General Public License
20 *   along with this program; if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/*
25 * This file must include only standard C header files.  The core code must
26 * compile on generic platforms that don't support glib, gimp, gtk, etc.
27 */
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <gutenprint/gutenprint.h>
33#include "gutenprint-internal.h"
34#include <gutenprint/gutenprint-intl-internal.h>
35#include <math.h>
36#ifdef HAVE_LIMITS_H
37#include <limits.h>
38#endif
39#include <string.h>
40#include <stdlib.h>
41
42static stp_list_t *paper_list = NULL;
43
44static void
45stpi_paper_freefunc(void *item)
46{
47  stp_papersize_t *paper = (stp_papersize_t *) (item);
48  STP_SAFE_FREE(paper->name);
49  STP_SAFE_FREE(paper->text);
50  STP_SAFE_FREE(paper->comment);
51  STP_SAFE_FREE(paper);
52}
53
54static const char *
55stpi_paper_namefunc(const void *item)
56{
57  const stp_papersize_t *paper = (const stp_papersize_t *) (item);
58  return paper->name;
59}
60
61static const char *
62stpi_paper_long_namefunc(const void *item)
63{
64  const stp_papersize_t *paper = (const stp_papersize_t *) (item);
65  return paper->text;
66}
67
68static int
69stpi_paper_list_init(void)
70{
71  if (paper_list)
72    stp_list_destroy(paper_list);
73  paper_list = stp_list_create();
74  stp_list_set_freefunc(paper_list, stpi_paper_freefunc);
75  stp_list_set_namefunc(paper_list, stpi_paper_namefunc);
76  stp_list_set_long_namefunc(paper_list, stpi_paper_long_namefunc);
77  /* stp_list_set_sortfunc(stpi_paper_sortfunc); */
78
79  return 0;
80}
81
82static inline void
83check_paperlist(void)
84{
85  if (paper_list == NULL)
86    {
87      stp_xml_parse_file_named("papers.xml");
88      if (paper_list == NULL)
89	{
90	  stp_erprintf("No papers found: is STP_MODULE_PATH correct?\n");
91	  stpi_paper_list_init();
92	}
93    }
94}
95
96static int
97stpi_paper_create(stp_papersize_t *p)
98{
99  stp_list_item_t *paper_item;
100
101  if (paper_list == NULL)
102    {
103      stpi_paper_list_init();
104      stp_deprintf(STP_DBG_PAPER,
105		   "stpi_paper_create(): initialising paper_list...\n");
106    }
107
108  /* Check the paper does not already exist */
109  paper_item = stp_list_get_start(paper_list);
110  while (paper_item)
111    {
112      const stp_papersize_t *ep =
113	(const stp_papersize_t *) stp_list_item_get_data(paper_item);
114      if (ep && !strcmp(p->name, ep->name))
115	{
116	  stpi_paper_freefunc(p);
117	  return 1;
118	}
119      paper_item = stp_list_item_next(paper_item);
120    }
121
122  /* Add paper to list */
123  stp_list_item_create(paper_list, NULL, (void *) p);
124
125  return 0;
126}
127
128int
129stp_known_papersizes(void)
130{
131  check_paperlist();
132  return stp_list_get_length(paper_list);
133}
134
135const stp_papersize_t *
136stp_get_papersize_by_name(const char *name)
137{
138  stp_list_item_t *paper;
139
140  check_paperlist();
141  paper = stp_list_get_item_by_name(paper_list, name);
142  if (!paper)
143    return NULL;
144  else
145    return (const stp_papersize_t *) stp_list_item_get_data(paper);
146}
147
148const stp_papersize_t *
149stp_get_papersize_by_index(int idx)
150{
151  stp_list_item_t *paper;
152
153  check_paperlist();
154  paper = stp_list_get_item_by_index(paper_list, idx);
155  if (!paper)
156    return NULL;
157  else
158    return (const stp_papersize_t *) stp_list_item_get_data(paper);
159}
160
161static int
162paper_size_mismatch(int l, int w, const stp_papersize_t *val)
163{
164  int hdiff = abs(l - (int) val->height);
165  int vdiff = abs(w - (int) val->width);
166  return hdiff > vdiff ? hdiff : vdiff;
167}
168
169const stp_papersize_t *
170stp_get_papersize_by_size(int l, int w)
171{
172  int score = INT_MAX;
173  const stp_papersize_t *ref = NULL;
174  const stp_papersize_t *val = NULL;
175  int i;
176  int sizes = stp_known_papersizes();
177  for (i = 0; i < sizes; i++)
178    {
179      val = stp_get_papersize_by_index(i);
180
181      if (val->width == w && val->height == l)
182	{
183	  if (val->top == 0 && val->left == 0 &&
184	      val->bottom == 0 && val->right == 0)
185	    return val;
186	  else
187	    ref = val;
188	}
189      else
190	{
191	  int myscore = paper_size_mismatch(l, w, val);
192	  if (myscore < score && myscore < 5)
193	    {
194	      ref = val;
195	      score = myscore;
196	    }
197	}
198    }
199  return ref;
200}
201
202const stp_papersize_t *
203stp_get_papersize_by_size_exact(int l, int w)
204{
205  const stp_papersize_t *ref = NULL;
206  const stp_papersize_t *val = NULL;
207  int i;
208  int sizes = stp_known_papersizes();
209  for (i = 0; i < sizes; i++)
210    {
211      val = stp_get_papersize_by_index(i);
212
213      if (val->width == w && val->height == l)
214	{
215	  if (val->top == 0 && val->left == 0 &&
216	      val->bottom == 0 && val->right == 0)
217	    return val;
218	  else
219	    ref = val;
220	}
221    }
222  return ref;
223}
224
225void
226stp_default_media_size(const stp_vars_t *v,	/* I */
227		       int  *width,		/* O - Width in points */
228		       int  *height) 		/* O - Height in points */
229{
230  if (stp_get_page_width(v) > 0 && stp_get_page_height(v) > 0)
231    {
232      *width = stp_get_page_width(v);
233      *height = stp_get_page_height(v);
234    }
235  else
236    {
237      const char *page_size = stp_get_string_parameter(v, "PageSize");
238      const stp_papersize_t *papersize = NULL;
239      if (page_size)
240	papersize = stp_get_papersize_by_name(page_size);
241      if (!papersize)
242	{
243	  *width = 1;
244	  *height = 1;
245	}
246      else
247	{
248	  *width = papersize->width;
249	  *height = papersize->height;
250	}
251      if (*width == 0)
252	*width = 612;
253      if (*height == 0)
254	*height = 792;
255    }
256}
257
258/*
259 * Process the <paper> node.
260 */
261static stp_papersize_t *
262stp_xml_process_paper(stp_mxml_node_t *paper) /* The paper node */
263{
264  stp_mxml_node_t *prop;                              /* Temporary node pointer */
265  const char *stmp;                                /* Temporary string */
266  /* props[] (unused) is the correct tag sequence */
267  /*  const char *props[] =
268    {
269      "name",
270      "description",
271      "width",
272      "height",
273      "left",
274      "right",
275      "bottom",
276      "top",
277      "unit",
278      "type",
279      NULL
280      };*/
281  stp_papersize_t *outpaper;   /* Generated paper */
282  int
283    id = 0,			/* Check id is present */
284    name = 0,			/* Check name is present */
285    height = 0,			/* Check height is present */
286    width = 0,			/* Check width is present */
287    left = 0,			/* Check left is present */
288    right = 0,			/* Check right is present */
289    bottom = 0,			/* Check bottom is present */
290    top = 0,			/* Check top is present */
291    unit = 0;			/* Check unit is present */
292
293  if (stp_get_debug_level() & STP_DBG_XML)
294    {
295      stmp = stp_mxmlElementGetAttr(paper, (const char*) "name");
296      stp_erprintf("stp_xml_process_paper: name: %s\n", stmp);
297    }
298
299  outpaper = stp_zalloc(sizeof(stp_papersize_t));
300  if (!outpaper)
301    return NULL;
302
303  outpaper->name = stp_strdup(stp_mxmlElementGetAttr(paper, "name"));
304
305  outpaper->top = 0;
306  outpaper->left = 0;
307  outpaper->bottom = 0;
308  outpaper->right = 0;
309  outpaper->paper_size_type = PAPERSIZE_TYPE_STANDARD;
310  if (outpaper->name)
311    id = 1;
312
313  prop = paper->child;
314  while(prop)
315    {
316      if (prop->type == STP_MXML_ELEMENT)
317	{
318	  const char *prop_name = prop->value.element.name;
319
320	  if (!strcmp(prop_name, "description"))
321	    {
322	      outpaper->text = stp_strdup(stp_mxmlElementGetAttr(prop, "value"));
323	      name = 1;
324	    }
325	  if (!strcmp(prop_name, "comment"))
326	    outpaper->comment = stp_strdup(stp_mxmlElementGetAttr(prop, "value"));
327	  if (!strcmp(prop_name, "width"))
328	    {
329	      stmp = stp_mxmlElementGetAttr(prop, "value");
330	      if (stmp)
331		{
332		  outpaper->width = stp_xmlstrtoul(stmp);
333		  width = 1;
334		}
335	    }
336	  if (!strcmp(prop_name, "height"))
337	    {
338	      stmp = stp_mxmlElementGetAttr(prop, "value");
339	      if (stmp)
340		{
341		  outpaper->height = stp_xmlstrtoul(stmp);
342		  height = 1;
343		}
344	    }
345	  if (!strcmp(prop_name, "left"))
346	    {
347	      stmp = stp_mxmlElementGetAttr(prop, "value");
348	      outpaper->left = stp_xmlstrtoul(stmp);
349	      left = 1;
350	    }
351	  if (!strcmp(prop_name, "right"))
352	    {
353	      stmp = stp_mxmlElementGetAttr(prop, "value");
354	      outpaper->right = stp_xmlstrtoul(stmp);
355	      right = 1;
356	    }
357	  if (!strcmp(prop_name, "bottom"))
358	    {
359	      stmp = stp_mxmlElementGetAttr(prop, "value");
360	      outpaper->bottom = stp_xmlstrtoul(stmp);
361	      bottom = 1;
362	    }
363	  if (!strcmp(prop_name, "top"))
364	    {
365	      stmp = stp_mxmlElementGetAttr(prop, "value");
366	      outpaper->top = stp_xmlstrtoul(stmp);
367	      top = 1;
368	    }
369	  if (!strcmp(prop_name, "unit"))
370	    {
371	      stmp = stp_mxmlElementGetAttr(prop, "value");
372	      if (stmp)
373		{
374		  if (!strcmp(stmp, "english"))
375		    outpaper->paper_unit = PAPERSIZE_ENGLISH_STANDARD;
376		  else if (!strcmp(stmp, "english-extended"))
377		    outpaper->paper_unit = PAPERSIZE_ENGLISH_EXTENDED;
378		  else if (!strcmp(stmp, "metric"))
379		    outpaper->paper_unit = PAPERSIZE_METRIC_STANDARD;
380		  else if (!strcmp(stmp, "metric-extended"))
381		    outpaper->paper_unit = PAPERSIZE_METRIC_EXTENDED;
382		  /* Default unit */
383		  else
384		    outpaper->paper_unit = PAPERSIZE_METRIC_EXTENDED;
385		  unit = 1;
386		}
387	    }
388	  if (!strcmp(prop_name, "type"))
389	    {
390	      stmp = stp_mxmlElementGetAttr(prop, "value");
391	      if (stmp)
392		{
393		  if (!strcmp(stmp, "envelope"))
394		    outpaper->paper_size_type = PAPERSIZE_TYPE_ENVELOPE;
395		  else
396		    outpaper->paper_size_type = PAPERSIZE_TYPE_STANDARD;
397		}
398	    }
399	}
400      prop = prop->next;
401    }
402  if (id && name && width && height && unit) /* Margins and type are optional */
403    return outpaper;
404  stp_free(outpaper);
405  outpaper = NULL;
406  return NULL;
407}
408
409/*
410 * Parse the <paperdef> node.
411 */
412static int
413stp_xml_process_paperdef(stp_mxml_node_t *paperdef, const char *file) /* The paperdef node */
414{
415  stp_mxml_node_t *paper;                           /* paper node pointer */
416  stp_papersize_t *outpaper;         /* Generated paper */
417
418  paper = paperdef->child;
419  while (paper)
420    {
421      if (paper->type == STP_MXML_ELEMENT)
422	{
423	  const char *paper_name = paper->value.element.name;
424	  if (!strcmp(paper_name, "paper"))
425	    {
426	      outpaper = stp_xml_process_paper(paper);
427	      if (outpaper)
428		stpi_paper_create(outpaper);
429	    }
430	}
431      paper = paper->next;
432    }
433  return 1;
434}
435
436void
437stpi_init_paper(void)
438{
439  stp_register_xml_parser("paperdef", stp_xml_process_paperdef);
440}
441