output: Use page_setup for parsing cairo page setup.
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 8 Feb 2023 22:28:54 +0000 (14:28 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 10 Feb 2023 17:56:14 +0000 (09:56 -0800)
This will make it easier to add page_setup support to the SPV driver.

src/language/tests/paper-size.c
src/output/cairo.c
src/output/measure.c
src/output/measure.h
src/output/options.c
src/output/options.h
src/output/page-setup.c
src/output/page-setup.h

index 0322f5728b80209a165a55693afdc42da4364e63..bccc60f7945bdbc3d5e7de82e02b886286145187 100644 (file)
@@ -29,7 +29,7 @@ int
 cmd_debug_paper_size (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   const char *paper_size;
-  int h, v;
+  double h, v;
 
   if (!lex_force_string (lexer))
     return CMD_FAILURE;
@@ -37,9 +37,7 @@ cmd_debug_paper_size (struct lexer *lexer, struct dataset *ds UNUSED)
 
   printf ("\"%s\" => ", paper_size);
   if (measure_paper (paper_size, &h, &v))
-    printf ("%.1f x %.1f in, %.0f x %.0f mm\n",
-            h / 72000., v / 72000.,
-            h / (72000 / 25.4), v / (72000 / 25.4));
+    printf ("%.1f x %.1f in, %.0f x %.0f mm\n", h, v, h * 25.4, v * 25.4);
   else
     printf ("error\n");
   lex_get (lexer);
index 8ef2b095363b0945040de06eaf5f8d31dd09c8ba..bdc500e54b2e9c8d37aa9e28c440b5d643369ea5 100644 (file)
@@ -182,35 +182,34 @@ parse_font_option (struct driver_options *options,
   return desc;
 }
 
+/* Scale INCHES into inch/(72 * XR_POINT). */
+static int
+scale (double inches)
+{
+  return inches * 72 * XR_POINT + 0.5;
+}
+
 static struct xr_driver *
 xr_allocate (const char *name, int device_type,
              enum xr_output_type output_type, struct driver_options *o)
 {
-  /* Scale factor from inch/72000 to inch/(72 * XR_POINT). */
-  const double scale = XR_POINT / 1000.;
-
-  int paper[TABLE_N_AXES];
-  parse_paper_size (opt (o, "paper-size", ""), &paper[H], &paper[V]);
-  for (int a = 0; a < TABLE_N_AXES; a++)
-    paper[a] *= scale;
-
-  int margins[TABLE_N_AXES][2];
-  margins[H][0] = parse_dimension (opt (o, "left-margin", ".5in")) * scale;
-  margins[H][1] = parse_dimension (opt (o, "right-margin", ".5in")) * scale;
-  margins[V][0] = parse_dimension (opt (o, "top-margin", ".5in")) * scale;
-  margins[V][1] = parse_dimension (opt (o, "bottom-margin", ".5in")) * scale;
+  struct page_setup *ps = page_setup_parse (o);
 
   int size[TABLE_N_AXES];
   for (int a = 0; a < TABLE_N_AXES; a++)
-    size[a] = paper[a] - margins[a][0] - margins[a][1];
+    size[a] = scale (ps->paper[a] - ps->margins[a][0] - ps->margins[a][1]);
 
   int min_break[TABLE_N_AXES];
-  min_break[H] = parse_dimension (opt (o, "min-hbreak", NULL)) * scale;
-  min_break[V] = parse_dimension (opt (o, "min-vbreak", NULL)) * scale;
+  min_break[H] = scale (parse_dimension (opt (o, "min-hbreak", NULL)));
+  min_break[V] = scale (parse_dimension (opt (o, "min-vbreak", NULL)));
   for (int a = 0; a < TABLE_N_AXES; a++)
     if (min_break[a] <= 0)
       min_break[a] = size[a] / 2;
 
+  int object_spacing = scale (ps->object_spacing);
+  if (object_spacing <= 0)
+    object_spacing = scale (12.0 / 72.0);
+
   int font_size = parse_int (opt (o, "font-size", "10000"), 1000, 1000000);
   PangoFontDescription *font = parse_font_option (
     o, "prop-font", "Sans Serif", font_size, false, false);
@@ -219,11 +218,6 @@ xr_allocate (const char *name, int device_type,
 
   bool systemcolors = parse_boolean (opt (o, "systemcolors", "false"));
 
-  int object_spacing
-    = parse_dimension (opt (o, "object-spacing", NULL)) * scale;
-  if (object_spacing <= 0)
-    object_spacing = XR_POINT * 12;
-
   const char *default_resolution = (output_type == XR_PNG ? "96" : "72");
   int font_resolution = parse_int (opt (o, "font-resolution",
                                         default_resolution), 10, 1000);
@@ -243,8 +237,8 @@ xr_allocate (const char *name, int device_type,
     .ref_cnt = 1,
 
     .margins = {
-      [H] = { margins[H][0], margins[H][1], },
-      [V] = { margins[V][0], margins[V][1], },
+      [H] = { scale (ps->margins[H][0]), scale (ps->margins[H][1]) },
+      [V] = { scale (ps->margins[V][0]), scale (ps->margins[V][1]) },
     },
 
     .initial_page_number = 1,
@@ -276,6 +270,8 @@ xr_allocate (const char *name, int device_type,
     .trim = trim,
   };
 
+  page_setup_destroy (ps);
+
   return xr;
 }
 
index 65d9fdddf28934e1e0172027d7b3a46ca14d424b..1ae1d31fa17ac3c2156dfa44bd23b3fb343d1fb2 100644 (file)
 #define _(msgid) gettext (msgid)
 
 static double parse_unit (const char *);
-static bool parse_paper_size (const char *, int *h, int *v);
-static bool get_standard_paper_size (struct substring name, int *h, int *v);
-static bool read_paper_conf (const char *file_name, int *h, int *v);
-static bool get_default_paper_size (int *h, int *v);
-
-/* Determines the size of a dimensional measurement and returns
-   the size in units of 1/72000".  Units are assumed to be
-   millimeters unless otherwise specified.  Returns -1 on
-   error. */
-int
+static bool parse_paper_size (const char *, double *h, double *v);
+static bool get_standard_paper_size (struct substring name,
+                                     double *h, double *v);
+static bool read_paper_conf (const char *file_name, double *h, double *v);
+static bool get_default_paper_size (double *h, double *v);
+
+/* Determines the size of a dimensional measurement and returns the size in
+   inches.  Units are assumed to be millimeters unless otherwise specified.
+   Returns -1 on error. */
+double
 measure_dimension (const char *dimen)
 {
-  double raw, factor;
-  char *tail;
-
   /* Number. */
-  raw = c_strtod (dimen, &tail);
+  char *tail;
+  double raw = c_strtod (dimen, &tail);
   if (raw < 0.0)
     goto syntax_error;
 
   /* Unit. */
-  factor = parse_unit (tail);
+  double factor = parse_unit (tail);
   if (factor == 0.0)
     goto syntax_error;
 
@@ -69,13 +67,12 @@ syntax_error:
   return -1;
 }
 
-/* Stores the dimensions, in 1/72000" units, of paper identified
-   by SIZE into *H and *V.  SIZE can be the name of a kind of
-   paper ("a4", "letter", ...) or a pair of dimensions
-   ("210x297", "8.5x11in", ...).  Returns true on success, false
+/* Stores the dimensions, in inches, of paper identified by SIZE into *H and
+   *V.  SIZE can be the name of a kind of paper ("a4", "letter", ...) or a pair
+   of dimensions ("210x297", "8.5x11in", ...).  Returns true on success, false
    on failure.  On failure, *H and *V are set for A4 paper. */
 bool
-measure_paper (const char *size, int *h, int *v)
+measure_paper (const char *size, double *h, double *v)
 {
   struct substring s;
   bool ok;
@@ -104,16 +101,15 @@ measure_paper (const char *size, int *h, int *v)
   /* Default to A4 on error. */
   if (!ok)
     {
-      *h = 210 * (72000 / 25.4);
-      *v = 297 * (72000 / 25.4);
+      *h = 210 / 25.4;
+      *v = 297 / 25.4;
     }
   return ok;
 }
 \f
-/* Parses UNIT as a dimensional unit.  Returns the multiplicative
-   factor needed to change a quantity measured in that unit into
-   1/72000" units.  If UNIT is empty, it is treated as
-   millimeters.  If the unit is unrecognized, returns 0. */
+/* Parses UNIT as a dimensional unit.  Returns the multiplicative factor needed
+   to change a quantity measured in that unit into inches.  If UNIT is empty,
+   it is treated as millimeters.  If the unit is unrecognized, returns 0. */
 static double
 parse_unit (const char *unit)
 {
@@ -125,12 +121,12 @@ parse_unit (const char *unit)
 
   static const struct unit units[] =
     {
-      {"pt", 72000 / 72},
-      {"pc", 72000 / 72 * 12.0},
-      {"in", 72000},
-      {"cm", 72000 / 2.54},
-      {"mm", 72000 / 25.4},
-      {"", 72000 / 25.4},
+      {"pt", 1.0 / 72.0},
+      {"pc", 12.0 / 72.0},
+      {"in", 1.0},
+      {"cm", 1.0 / 2.54},
+      {"mm", 1.0 / 25.4},
+      {"", 1.0 / 25.4},
     };
 
   const struct unit *p;
@@ -142,18 +138,15 @@ parse_unit (const char *unit)
   return 0.0;
 }
 
-/* Stores the dimensions in 1/72000" units of paper identified by
-   SIZE, which is of form `HORZ x VERT [UNIT]' where HORZ and
-   VERT are numbers and UNIT is an optional unit of measurement,
-   into *H and *V.  Return true on success. */
+/* Stores the dimensions, in inches, identified by SIZE, which is of form `HORZ
+   x VERT [UNIT]' where HORZ and VERT are numbers and UNIT is an optional unit
+   of measurement, into *H and *V.  Return true on success. */
 static bool
-parse_paper_size (const char *size, int *h, int *v)
+parse_paper_size (const char *size, double *h, double *v)
 {
-  double raw_h, raw_v, factor;
-  char *tail;
-
   /* Width. */
-  raw_h = c_strtod (size, &tail);
+  char *tail;
+  double raw_h = c_strtod (size, &tail);
   if (raw_h <= 0.0)
     return false;
 
@@ -161,22 +154,22 @@ parse_paper_size (const char *size, int *h, int *v)
   tail += strspn (tail, CC_SPACES "x,");
 
   /* Length. */
-  raw_v = c_strtod (tail, &tail);
+  double raw_v = c_strtod (tail, &tail);
   if (raw_v <= 0.0)
     return false;
 
   /* Unit. */
-  factor = parse_unit (tail);
+  double factor = parse_unit (tail);
   if (factor == 0.0)
     return false;
 
-  *h = raw_h * factor + .5;
-  *v = raw_v * factor + .5;
+  *h = raw_h * factor;
+  *v = raw_v * factor;
   return true;
 }
 
 static bool
-get_standard_paper_size (struct substring name, int *h, int *v)
+get_standard_paper_size (struct substring name, double *h, double *v)
 {
   static const char *sizes[][2] =
     {
@@ -235,11 +228,10 @@ get_standard_paper_size (struct substring name, int *h, int *v)
   return false;
 }
 
-/* Reads file FILE_NAME to find a paper size.  Stores the
-   dimensions, in 1/72000" units, into *H and *V.  Returns true
-   on success, false on failure. */
+/* Reads file FILE_NAME to find a paper size.  Stores the dimensions, in
+   inches, into *H and *V.  Returns true on success, false on failure. */
 static bool
-read_paper_conf (const char *file_name, int *h, int *v)
+read_paper_conf (const char *file_name, double *h, double *v)
 {
   struct string line = DS_EMPTY_INITIALIZER;
   int line_number = 0;
@@ -280,12 +272,11 @@ read_paper_conf (const char *file_name, int *h, int *v)
   return false;
 }
 
-/* The user didn't specify a paper size, so let's choose a
-   default based on his environment.  Stores the
-   dimensions, in 1/72000" units, into *H and *V.  Returns true
-   on success, false on failure. */
+/* The user didn't specify a paper size, so let's choose a default based on his
+   environment.  Stores the dimensions, in inches, into *H and *V.  Returns
+   true on success, false on failure. */
 static bool
-get_default_paper_size (int *h, int *v)
+get_default_paper_size (double *h, double *v)
 {
   /* libpaper in Debian (and other distributions?) allows the
      paper size to be specified in $PAPERSIZE or in a file
@@ -300,8 +291,8 @@ get_default_paper_size (int *h, int *v)
      The (int)(intptr_t) cast is for 64 Bit Systems where intptr_t
      translates to 64 Bit long int but the upper 32 Bits have wrong
      values. The result from nl_langinfo is integer (32 Bit) */
-  *h = (int)(intptr_t) nl_langinfo(_NL_PAPER_WIDTH) * (72000 / 25.4);
-  *v = (int)(intptr_t) nl_langinfo(_NL_PAPER_HEIGHT) * (72000 / 25.4);
+  *h = (int)(intptr_t) nl_langinfo(_NL_PAPER_WIDTH) / 25.4;
+  *v = (int)(intptr_t) nl_langinfo(_NL_PAPER_HEIGHT) / 25.4;
   if (*h > 0 && *v > 0)
      return true;
 #endif
index 4b6fab3805432539b0bc6b1a77d1b220e16db367..047f78c50dfd5d4a289411f897f902daa93a2186 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <stdbool.h>
 
-int measure_dimension (const char *dimen);
-bool measure_paper (const char *size, int *h, int *v);
+double measure_dimension (const char *dimen);
+bool measure_paper (const char *size, double *h, double *v);
 
 #endif /* output/measure.h */
index 227b132aa0d34932abeaba0b85250a7784b21688..52bfa81aad0661446277516c65140ca226179415 100644 (file)
@@ -57,10 +57,10 @@ driver_option_get (struct driver_options *options,
   };
 }
 
-/* Stores the paper size of the value of option O into *H and *V, in 1/72000"
-   units.  Any syntax accepted by measure_paper() may be used. */
+/* Stores the paper size of the value of option O into *H and *V, in inches.
+   Any syntax accepted by measure_paper() may be used. */
 void
-parse_paper_size (struct driver_option o, int *h, int *v)
+parse_paper_size (struct driver_option o, double *h, double *v)
 {
   if (!o.value || !measure_paper (o.value, h, v))
     measure_paper (o.default_value, h, v);
@@ -201,8 +201,8 @@ parse_int (struct driver_option o, int min_value, int max_value)
 }
 
 /* Parses O's value as a dimension, as understood by measure_dimension(), and
-   returns its length in units of 1/72000". */
-int
+   returns its length in inches. */
+double
 parse_dimension (struct driver_option o)
 {
   return (o.value ? measure_dimension (o.value)
index e8e675f8bc2b928dbad740625a02ada3a9cd3d73..115e296f3dd2a4a882df0d29803e7ee357a1d76c 100644 (file)
@@ -47,14 +47,14 @@ struct driver_option driver_option_get (struct driver_options *,
                                         const char *name,
                                         const char *default_value);
 
-void parse_paper_size (struct driver_option, int *h, int *v);
+void parse_paper_size (struct driver_option, double *h, double *v);
 bool parse_boolean (struct driver_option);
 
 int parse_enum (struct driver_option, ...) SENTINEL(0);
 #define parse_enum(...) parse_enum(__VA_ARGS__, NULL_SENTINEL)
 
 int parse_int (struct driver_option, int min_value, int max_value);
-int parse_dimension (struct driver_option);
+double parse_dimension (struct driver_option);
 char *parse_string (struct driver_option);
 char *parse_chart_file_name (struct driver_option);
 
index 4c9c99046433a982abef107299fb6702a2026eea..4c3ee8ec871420026aa7dc87363d1274fd0ad40c 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "output/options.h"
+
 #include "gl/xalloc.h"
 
 bool
@@ -95,3 +97,30 @@ page_setup_destroy (struct page_setup *ps)
       free (ps);
     }
 }
+
+static struct driver_option
+opt (struct driver_options *options, const char *key, const char *default_value)
+{
+  return driver_option_get (options, key, default_value);
+}
+
+struct page_setup *
+page_setup_parse (struct driver_options *o)
+{
+  struct page_setup *ps = xmalloc (sizeof *ps);
+  *ps = (struct page_setup) PAGE_SETUP_INITIALIZER;
+
+  enum { H = TABLE_HORZ, V = TABLE_VERT };
+  parse_paper_size (opt (o, "paper-size", ""), &ps->paper[H], &ps->paper[V]);
+
+  ps->margins[H][0] = parse_dimension (opt (o, "left-margin", ".5in"));
+  ps->margins[H][1] = parse_dimension (opt (o, "right-margin", ".5in"));
+  ps->margins[V][0] = parse_dimension (opt (o, "top-margin", ".5in"));
+  ps->margins[V][1] = parse_dimension (opt (o, "bottom-margin", ".5in"));
+
+  ps->object_spacing = parse_dimension (opt (o, "object-spacing", NULL));
+  if (ps->object_spacing <= 0)
+    ps->object_spacing = 12.0 / 72.0;
+
+  return ps;
+}
index 95405eff27bb8eff429eca5381ee177042857396..6f45db5b25446ca21548c8ba73599f8d0f444ad1 100644 (file)
@@ -25,6 +25,8 @@
 #include <stdbool.h>
 #include "table.h"
 
+struct driver_options;
+
 enum page_orientation
   {
     PAGE_PORTRAIT,
@@ -84,4 +86,6 @@ struct page_setup
 struct page_setup *page_setup_clone (const struct page_setup *);
 void page_setup_destroy (struct page_setup *);
 
+struct page_setup *page_setup_parse (struct driver_options *);
+
 #endif /* output/page-setup.h */