Skip to content

Commit 5f3abad

Browse files
committed
pdf_io: add partial parsing of 'config' special
In upstream dvipdfmx the `dvidpfmx:config` DVI special can be used to pass arguments to dvipdfmx. This has seen some use in XeTeX packages. For example, the ubiqitous package "hyperref" uses: \special{dvipdfmx:config C 0x0010} This is normally parsed by dvipdfmx as command line arguments, i.e. as if xdvipdfmx was ran as: xdvipdfmx -C 0x0010 The `C` option is a bitset of compatibility flags. In this case hyperref needs the option `OPT_PDFDOC_NO_DEST_REMOVE`, which makes dvipdfmx handle PDF destinations differently (I didn't check thoroughly how). The `opt_flags` global variable used to hold these bitflags and the `dvipdfmx:config` special could be used to set them. tectonic-typesetting#92 removed that option. While passing arbitrary command line arguments to dvidpfmx is probably not what we want, I definitely know, that we at least need the compatibility flags to work, and there is probably no other way packages can set them. The code that does the option parsing is mostly port from the 'C' option parsing from dvipdfmx's `read_config_special` and `do_args_second_pass`. IMHO the way `opt_flags` gets modified is undefined behaviour and does other weird things with negative values, but the purpose of this commit is to increase compatibility with upstream, not to fix things (which should preferably be done upstream IMO). Like with other options, instead of having a global variable, the pointer to the value in `dvipdfmx_main` is passed around instead. While at it, I also added `z` and `g` options which also seem to be used by LaTeX, so this should be enough for a while. Hopefully fixes tectonic-typesetting#904.
1 parent 34afff0 commit 5f3abad

File tree

3 files changed

+96
-15
lines changed

3 files changed

+96
-15
lines changed

crates/engine_xdvipdfmx/xdvipdfmx/dvipdfmx.c

+21-12
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,14 @@ typedef struct page_range
6666
int last;
6767
} PageRange;
6868

69+
/* Compatibility options */
6970
#define OPT_TPIC_TRANSPARENT_FILL (1 << 1)
7071
#define OPT_CIDFONT_FIXEDPITCH (1 << 2)
7172
#define OPT_FONTMAP_FIRST_MATCH (1 << 3)
7273
#define OPT_PDFDOC_NO_DEST_REMOVE (1 << 4)
7374
#define OPT_PDFOBJ_NO_PREDICTOR (1 << 5)
7475
#define OPT_PDFOBJ_NO_OBJSTM (1 << 6)
7576

76-
static int pdf_version_major = 1;
77-
static int pdf_version_minor = 5;
78-
static int compression_level = 9;
79-
80-
static double annot_grow_x = 0.0;
81-
static double annot_grow_y = 0.0;
8277
static char ignore_colors = 0;
8378
static int bookmark_open = 0;
8479
static double mag = 1.0;
@@ -248,10 +243,18 @@ do_dvi_pages (void)
248243
xo = x_offset; yo = y_offset;
249244
dvi_scan_specials(page_no,
250245
&w, &h, &xo, &yo, &lm,
246+
/* No PDF version */
247+
NULL, NULL,
248+
/* No compression */
249+
NULL,
250+
/* No annotation grow */
251+
NULL, NULL,
251252
/* No need for encryption options */
252-
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
253+
NULL, NULL, NULL, NULL, NULL,
253254
/* No trailer IDs */
254-
NULL, NULL, NULL);
255+
NULL, NULL, NULL,
256+
/* No opt_flags */
257+
NULL);
255258
if (lm != landscape_mode) { /* already swapped for the first page */
256259
SWAP(w, h);
257260
landscape_mode = lm;
@@ -369,8 +372,12 @@ dvipdfmx_main (
369372
* code bits. */
370373

371374
select_paper(paperspec);
372-
annot_grow_x = 0;
373-
annot_grow_y = 0;
375+
376+
int pdf_version_major = 1;
377+
int pdf_version_minor = 5;
378+
int compression_level = 9;
379+
double annot_grow_x = 0;
380+
double annot_grow_y = 0;
374381
bookmark_open = 0;
375382
key_bits = 40;
376383
permission = 0x003C;
@@ -397,8 +404,10 @@ dvipdfmx_main (
397404
&paper_width, &paper_height,
398405
&x_offset, &y_offset, &landscape_mode,
399406
&pdf_version_major, &pdf_version_minor,
407+
&compression_level,
408+
&annot_grow_x, &annot_grow_y,
400409
&do_encryption, &key_bits, &permission, oplain, uplain,
401-
&has_id, id1, id2);
410+
&has_id, id1, id2, &opt_flags);
402411
}
403412

404413
/*kpse_init_prog("", font_dpi, NULL, NULL);
@@ -518,4 +527,4 @@ tt_engine_xdvipdfmx_main(
518527

519528
ttbc_global_engine_exit();
520529
return rv;
521-
}
530+
}

crates/pdf_io/pdf_io/dpx-dvi.c

+71-2
Original file line numberDiff line numberDiff line change
@@ -2490,12 +2490,75 @@ scan_special_trailerid (unsigned char *id1, unsigned char *id2,
24902490
return error;
24912491
}
24922492

2493+
static void
2494+
scan_special_config (const char **start, const char *end, int *opt_flags,
2495+
int *compression_level,
2496+
double *annot_grow_x, double *annot_grow_y)
2497+
{
2498+
skip_white(start, end);
2499+
if (*start >= end)
2500+
return;
2501+
2502+
char *option = parse_ident(start, end);
2503+
if (!option)
2504+
return;
2505+
2506+
char *arg = NULL;
2507+
skip_white(start, end);
2508+
if (*start < end) {
2509+
if (**start == '"')
2510+
arg = parse_c_string(start, end);
2511+
else
2512+
arg = parse_ident(start, end);
2513+
}
2514+
2515+
if (streq_ptr(option, "C") && arg && opt_flags) {
2516+
char *num_end;
2517+
int flags = (unsigned) strtol(arg, &num_end, 0);
2518+
if (num_end == arg)
2519+
dpx_warning("Invalid dvipdfmx compatibility flag: '%s'", arg);
2520+
else if (flags < 0)
2521+
*opt_flags = -flags;
2522+
else
2523+
*opt_flags |= flags;
2524+
} else if (streq_ptr(option, "z") && arg && compression_level) {
2525+
*compression_level = atoi(arg);
2526+
} else if (streq_ptr(option, "g") && arg && annot_grow_x && annot_grow_y) {
2527+
const char *comma = strchr(arg, ',');
2528+
const char *arg_ptr = arg; /* dpx_until_read_length changes the pointer */
2529+
const char *arg_end = arg + strlen(arg);
2530+
int error;
2531+
if (comma) {
2532+
error = dpx_util_read_length(annot_grow_x, 1.0, &arg_ptr, comma);
2533+
arg_ptr = comma + 1;
2534+
if (!error)
2535+
error = dpx_util_read_length(annot_grow_y, 1.0, &arg_ptr, arg_end);
2536+
} else {
2537+
error = dpx_util_read_length(annot_grow_x, 1.0, &arg_ptr, arg_end);
2538+
if (!error)
2539+
*annot_grow_y = *annot_grow_x;
2540+
}
2541+
if (error) {
2542+
dpx_warning("Error reading argument for \"-g\" option: %s", arg);
2543+
}
2544+
} else {
2545+
dpx_warning("Tectonic doesn't support '%s' config special"
2546+
" or the argument is missing", option);
2547+
}
2548+
2549+
free(arg);
2550+
free(option);
2551+
}
2552+
24932553
static int
24942554
scan_special (double *wd, double *ht, double *xo, double *yo, int *lm,
24952555
int *majorversion, int *minorversion,
2556+
int *compression_level,
2557+
double *annot_grow_x, double *annot_grow_y,
24962558
int *enable_encryption, int *key_bits, int32_t *permission,
24972559
char *opassword, char *upassword,
24982560
int *has_id, unsigned char *id1, unsigned char *id2,
2561+
int *opt_flags,
24992562
const char *buf, uint32_t size)
25002563
{
25012564
char *q;
@@ -2626,7 +2689,7 @@ scan_special (double *wd, double *ht, double *xo, double *yo, int *lm,
26262689
*enable_encryption = 1;
26272690
error = scan_special_encrypt(key_bits, permission, opassword, upassword, &p, endptr);
26282691
} else if (ns_dvipdfmx && streq_ptr(q, "config")) {
2629-
dpx_warning("Tectonic does not support `config' special. Ignored.");
2692+
scan_special_config(&p, endptr, opt_flags, compression_level, annot_grow_x, annot_grow_y);
26302693
} else if (has_id && id1 && id2 && ns_pdf && !strcmp(q, "trailerid")) {
26312694
error = scan_special_trailerid(id1, id2, &p, endptr);
26322695
if (error) {
@@ -2648,9 +2711,12 @@ dvi_scan_specials (int page_no,
26482711
double *page_width, double *page_height,
26492712
double *x_offset, double *y_offset, int *landscape,
26502713
int *majorversion, int *minorversion,
2714+
int *compression_level,
2715+
double *annot_grow_x, double *annot_grow_y,
26512716
int *do_enc, int *key_bits, int32_t *permission,
26522717
char *owner_pw, char *user_pw,
2653-
int *has_id, unsigned char *id1, unsigned char *id2)
2718+
int *has_id, unsigned char *id1, unsigned char *id2,
2719+
int *opt_flags)
26542720
{
26552721
uint32_t offset;
26562722
unsigned char opcode;
@@ -2694,8 +2760,11 @@ dvi_scan_specials (int page_no,
26942760
_tt_abort("Reading DVI file failed!");
26952761
if (scan_special(page_width, page_height, x_offset, y_offset, landscape,
26962762
majorversion, minorversion,
2763+
compression_level,
2764+
annot_grow_x, annot_grow_y,
26972765
do_enc, key_bits, permission, owner_pw, user_pw,
26982766
has_id, id1, id2,
2767+
opt_flags,
26992768
buf, size))
27002769
dpx_warning("Reading special command failed: \"%.*s\"", size, buf);
27012770
#undef buf

crates/pdf_io/pdf_io/dpx-dvi.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,11 @@ void dvi_scan_specials (int page_no,
7575
double *width, double *height,
7676
double *x_offset, double *y_offset, int *landscape,
7777
int *majorversion, int *minorversion,
78+
int *compression_level,
79+
double *annot_grow_x, double *annot_grow_y,
7880
int *do_enc, int *keybits, int32_t *perm,
79-
char *opasswd, char *upasswd, int *has_id, unsigned char *id1, unsigned char *id2);
81+
char *opasswd, char *upasswd, int *has_id, unsigned char *id1, unsigned char *id2,
82+
int *opt_flags);
8083
unsigned int dvi_locate_font (const char *name, spt_t ptsize);
8184

8285
/* link or nolink:

0 commit comments

Comments
 (0)