/* Internal state. */
struct render_params *params;
+ double font_scale;
int char_width, char_height;
char *command_name;
char *title;
}
/* rgb(r,g,b) */
- if (sscanf (s, "rgb (%"SCNi8" , %"SCNi8" , %"SCNi8" ) %n",
+ if (sscanf (s, "rgb (%"SCNi8" , %"SCNi8" , %"SCNi8") %n",
&r, &g, &b, &len) == 3
&& !s[len])
{
}
/* rgba(r,g,b,a), ignoring a. */
- if (sscanf (s, "rgba (%"SCNi8" , %"SCNi8" , %"SCNi8", %*f ) %n",
+ if (sscanf (s, "rgba (%"SCNi8" , %"SCNi8" , %"SCNi8", %*f) %n",
&r, &g, &b, &len) == 3
&& !s[len])
{
}
static struct xr_driver *
-xr_allocate (const char *name, int device_type, struct string_map *o)
+xr_allocate (const char *name, int device_type, struct string_map *o,
+ double font_scale)
{
struct xr_driver *xr = xzalloc (sizeof *xr);
struct output_driver *d = &xr->driver;
string_map_init (&xr->heading_vars);
+ /* This is a nasty kluge for an issue that does not make sense. On any
+ surface other than a screen (e.g. for output to PDF or PS or SVG), the
+ fonts are way too big by default. A "9-point" font seems to appear about
+ 16 points tall. We use a scale factor for these surfaces to help, but the
+ underlying issue is a mystery. */
+ xr->font_scale = font_scale;
+
apply_options (xr, o);
return xr;
cairo_status_t status;
double width_pt, length_pt;
- xr = xr_allocate (file_name, device_type, o);
+ xr = xr_allocate (file_name, device_type, o, 72.0 / 128.0);
width_pt = xr_to_pt (xr->width + xr->left_margin + xr->right_margin);
length_pt = xr_to_pt (xr->length + xr->top_margin + xr->bottom_margin);
cairo_surface_finish (xr->surface);
cairo_status_t status = cairo_status (xr->cairo);
if (status != CAIRO_STATUS_SUCCESS)
- msg (ME, _("error drawing output for %s driver: %s"),
- output_driver_get_name (driver),
- cairo_status_to_string (status));
+ fprintf (stderr, _("error drawing output for %s driver: %s"),
+ output_driver_get_name (driver),
+ cairo_status_to_string (status));
cairo_surface_destroy (xr->surface);
cairo_destroy (xr->cairo);
}
static void
-add_attr_with_start (PangoAttrList *list, PangoAttribute *attr, guint start_index)
+add_attr (PangoAttrList *list, PangoAttribute *attr,
+ guint start_index, guint end_index)
{
attr->start_index = start_index;
+ attr->end_index = end_index;
pango_attr_list_insert (list, attr);
}
static void
-markup_escape (const char *in, struct string *out)
-{
- for (int c = *in++; c; c = *in++)
- switch (c)
- {
- case '&':
- ds_put_cstr (out, "&");
- break;
- case '<':
- ds_put_cstr (out, "<");
- break;
- case '>':
- ds_put_cstr (out, ">");
- break;
- default:
- ds_put_byte (out, c);
- break;
- }
+markup_escape (struct string *out, unsigned int options,
+ const char *in, size_t len)
+{
+ if (!(options & TAB_MARKUP))
+ {
+ ds_put_substring (out, ss_buffer (in, len == -1 ? strlen (in) : len));
+ return;
+ }
+
+ while (len-- > 0)
+ {
+ int c = *in++;
+ switch (c)
+ {
+ case 0:
+ return;
+ case '&':
+ ds_put_cstr (out, "&");
+ break;
+ case '<':
+ ds_put_cstr (out, "<");
+ break;
+ case '>':
+ ds_put_cstr (out, ">");
+ break;
+ default:
+ ds_put_byte (out, c);
+ break;
+ }
+ }
}
static int
{
PangoFontDescription *desc = parse_font (
font_style->typeface,
- font_style->size ? font_style->size * 1000 * 72 / 128 : 10000,
+ font_style->size ? font_style->size * 1000 * xr->font_scale : 10000,
font_style->bold, font_style->italic);
if (desc)
{
}
struct string tmp = DS_EMPTY_INITIALIZER;
+ PangoAttrList *attrs = NULL;
/* Deal with an oddity of the Unicode line-breaking algorithm (or perhaps in
Pango's implementation of it): it will break after a period or a comma
happen with grouping like 1,234,567.89 or 1.234.567,89 because if groups
are present then there will always be a digit on both sides of every
period and comma. */
- if (options & TAB_ROTATE || bb[H][1] != INT_MAX)
+ if (options & TAB_MARKUP)
+ {
+ PangoAttrList *new_attrs;
+ char *new_text;
+ if (pango_parse_markup (text, -1, 0, &new_attrs, &new_text, NULL, NULL))
+ {
+ attrs = new_attrs;
+ tmp.ss = ss_cstr (new_text);
+ tmp.capacity = tmp.ss.length;
+ }
+ else
+ {
+ /* XXX should we report the error? */
+ ds_put_cstr (&tmp, text);
+ }
+ }
+ else if (options & TAB_ROTATE || bb[H][1] != INT_MAX)
{
const char *decimal = text + strcspn (text, ".,");
if (decimal[0]
&& (decimal == text || !c_isdigit (decimal[-1])))
{
ds_extend (&tmp, strlen (text) + 16);
- ds_put_substring (&tmp, ss_buffer (text, decimal - text + 1));
+ markup_escape (&tmp, options, text, decimal - text + 1);
ds_put_unichar (&tmp, 0x2060 /* U+2060 WORD JOINER */);
- ds_put_cstr (&tmp, decimal + 1);
+ markup_escape (&tmp, options, decimal + 1, -1);
}
}
- if (cell->n_footnotes)
+ if (font_style->underline)
{
- int footnote_adjustment;
- if (cell->n_footnotes == 1 && halign == TABLE_HALIGN_RIGHT)
- {
- const char *marker = cell->footnotes[0]->marker;
- pango_layout_set_text (font->layout, marker, strlen (marker));
-
- PangoAttrList *attrs = pango_attr_list_new ();
- pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL));
- pango_attr_list_insert (attrs, pango_attr_rise_new (3000));
- pango_layout_set_attributes (font->layout, attrs);
- pango_attr_list_unref (attrs);
-
- int w = get_layout_dimension (font->layout, X);
- int right_margin = px_to_xr (cell_style->margin[X][R]);
- footnote_adjustment = MIN (w, right_margin);
-
- pango_layout_set_attributes (font->layout, NULL);
- }
- else
- footnote_adjustment = px_to_xr (cell_style->margin[X][R]);
-
- if (R)
- bb[X][R] += footnote_adjustment;
- else
- bb[X][R] -= footnote_adjustment;
+ if (!attrs)
+ attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_underline_new (
+ PANGO_UNDERLINE_SINGLE));
+ }
+ if (cell->n_footnotes || cell->n_subscripts || cell->superscript)
+ {
+ /* If we haven't already put TEXT into tmp, do it now. */
if (ds_is_empty (&tmp))
{
ds_extend (&tmp, strlen (text) + 16);
- ds_put_cstr (&tmp, text);
+ markup_escape (&tmp, options, text, -1);
+ }
+
+ size_t subscript_ofs = ds_length (&tmp);
+ for (size_t i = 0; i < cell->n_subscripts; i++)
+ {
+ if (i)
+ ds_put_byte (&tmp, ',');
+ ds_put_cstr (&tmp, cell->subscripts[i]);
}
- size_t initial_length = ds_length (&tmp);
+ size_t superscript_ofs = ds_length (&tmp);
+ if (cell->superscript)
+ ds_put_cstr (&tmp, cell->superscript);
+
+ size_t footnote_ofs = ds_length (&tmp);
for (size_t i = 0; i < cell->n_footnotes; i++)
{
if (i)
ds_put_byte (&tmp, ',');
+ ds_put_cstr (&tmp, cell->footnotes[i]->marker);
+ }
- const char *marker = cell->footnotes[i]->marker;
- if (options & TAB_MARKUP)
- markup_escape (marker, &tmp);
- else
- ds_put_cstr (&tmp, marker);
+ /* Allow footnote markers to occupy the right margin. That way, numbers
+ in the column are still aligned. */
+ if (cell->n_footnotes && halign == TABLE_HALIGN_RIGHT)
+ {
+ /* Measure the width of the footnote marker, so we know how much we
+ need to make room for. */
+ pango_layout_set_text (font->layout, ds_cstr (&tmp) + footnote_ofs,
+ ds_length (&tmp) - footnote_ofs);
+
+ PangoAttrList *fn_attrs = pango_attr_list_new ();
+ pango_attr_list_insert (
+ fn_attrs, pango_attr_scale_new (PANGO_SCALE_SMALL));
+ pango_attr_list_insert (fn_attrs, pango_attr_rise_new (3000));
+ pango_layout_set_attributes (font->layout, fn_attrs);
+ pango_attr_list_unref (fn_attrs);
+ int footnote_width = get_layout_dimension (font->layout, X);
+
+ /* Bound the adjustment by the width of the right margin. */
+ int right_margin = px_to_xr (cell_style->margin[X][R]);
+ int footnote_adjustment = MIN (footnote_width, right_margin);
+
+ /* Adjust the bounding box. */
+ if (options & TAB_ROTATE)
+ footnote_adjustment = -footnote_adjustment;
+ bb[X][R] += footnote_adjustment;
+
+ /* Clean up. */
+ pango_layout_set_attributes (font->layout, NULL);
}
- if (options & TAB_MARKUP)
- pango_layout_set_markup (font->layout,
- ds_cstr (&tmp), ds_length (&tmp));
- else
- pango_layout_set_text (font->layout, ds_cstr (&tmp), ds_length (&tmp));
-
- PangoAttrList *attrs = pango_attr_list_new ();
- if (font_style->underline)
- pango_attr_list_insert (attrs, pango_attr_underline_new (
- PANGO_UNDERLINE_SINGLE));
- add_attr_with_start (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL), initial_length);
- add_attr_with_start (attrs, pango_attr_rise_new (3000), initial_length);
- add_attr_with_start (
- attrs, pango_attr_font_desc_new (font->desc), initial_length);
+ /* Set attributes. */
+ if (!attrs)
+ attrs = pango_attr_list_new ();
+ add_attr (attrs, pango_attr_font_desc_new (font->desc), subscript_ofs,
+ PANGO_ATTR_INDEX_TO_TEXT_END);
+ add_attr (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL),
+ subscript_ofs, PANGO_ATTR_INDEX_TO_TEXT_END);
+ if (cell->n_subscripts)
+ add_attr (attrs, pango_attr_rise_new (-3000), subscript_ofs,
+ superscript_ofs - subscript_ofs);
+ if (cell->superscript || cell->n_footnotes)
+ add_attr (attrs, pango_attr_rise_new (3000), superscript_ofs,
+ PANGO_ATTR_INDEX_TO_TEXT_END);
+ }
+
+ /* Set the attributes, if any. */
+ if (attrs)
+ {
pango_layout_set_attributes (font->layout, attrs);
pango_attr_list_unref (attrs);
}
- else
- {
- const char *content = ds_is_empty (&tmp) ? text : ds_cstr (&tmp);
- if (options & TAB_MARKUP)
- pango_layout_set_markup (font->layout, content, -1);
- else
- pango_layout_set_text (font->layout, content, -1);
- if (font_style->underline)
- {
- PangoAttrList *attrs = pango_attr_list_new ();
- pango_attr_list_insert (attrs, pango_attr_underline_new (
- PANGO_UNDERLINE_SINGLE));
- pango_layout_set_attributes (font->layout, attrs);
- pango_attr_list_unref (attrs);
- }
- }
+ /* Set the text. */
+ if (ds_is_empty (&tmp))
+ pango_layout_set_text (font->layout, text, -1);
+ else
+ pango_layout_set_text (font->layout, ds_cstr (&tmp), ds_length (&tmp));
ds_destroy (&tmp);
pango_layout_set_alignment (font->layout,
struct xr_driver *
xr_driver_create (cairo_t *cairo, struct string_map *options)
{
- struct xr_driver *xr = xr_allocate ("cairo", 0, options);
+ struct xr_driver *xr = xr_allocate ("cairo", 0, options, 1.0);
xr_set_cairo (xr, cairo);
return xr;
}