Submitted By: Douglas R. Reno Date: 2025-05-20 Initial Package Version: 20250308 Upstream Status: Applied Origin: Upstream (branch2025) Description: This patch fixes three known issues with the initial release of texlive2025. This includes a fix for a bug where LuaTeX did not typeset integrals correctly, for a bug where xdvipdfmx crashed on certain PDF inclusions, and for a bug where pdftex output overlapping text with ptmr8r and other fonts. The patch was a bit tricky to obtain. The Texlive source tree assumes you're in the Build/source directory, so those paths had to be modified so that they corresponded to the source release, and then binary files had to be removed. This does break one test, which will be documented in the book. I ran Ken's test suite though and all appears to work as intended. diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/ChangeLog texlive-20250308-source/texk/dvipdfm-x/ChangeLog --- texlive-20250308-source.orig/texk/dvipdfm-x/ChangeLog 2025-05-20 14:39:30.372565438 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/ChangeLog 2025-05-20 14:54:07.799983332 -0500 @@ -1,3 +1,45 @@ +2025-04-10 Karl Berry + + * configure.ac: version 20250410. + +2025-04-09 Karl Berry + + * pdfobj.c (pdf_get_object): fix possible seg fault in + object stream parsing. Report and patch from Shuqiao Zhang: + https://tug.org/pipermail/tex-live/2025-April/051444.html + + * xdvipdfm-pdf.test: new test, for this (pdfobj) and the page + Group (pdfgroup) fix from Clerk ma. + * Makefile.am (tests): add it. + * tests/xdvipdfm-pdfobj.xdv, + * tests/xdvipdfm-pdfgroup.dvi: new test input files. + * tests/rpki-ecosystem.drawio.pdf, + * tests/xdvipdfm-pdfgroup-0318.pdf: inclusion files for the tests. + +2025-03-17 Clerk Ma + + * epdf.c (pdf_include_page): check for the page Group being NULL + before dereferencing it. (r74687) + +2025-03-17 TANAKA Takuji + + * vf.c: Store combining characters in vitual fonts with indices + and save memories to fix issue reported by gbb 60166. + https://okumuralab.org/tex/mod/forum/discuss.php?d=3903 + * configure.ac: version 20250317. + +2025-03-14 Max Chernoff + + * pdffont.c: Switch to using only A-Z in the tag since numerical + digits are invalid per the PDF spec. Thanks to Yukimasa Morimi, + https://tug.org/pipermail/dvipdfmx/2025-March/000370.html + +2025-03-13 Max Chernoff + + * dvipdfmx.c, dvipdfmx.h, pdffont.c: Use deterministic font names. + Report from Paulo Ney de Souza, + https://tug.org/pipermail/dvipdfmx/2025-March/000353.html + 2025-03-07 Karl Berry * TL'25 release. diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/configure texlive-20250308-source/texk/dvipdfm-x/configure --- texlive-20250308-source.orig/texk/dvipdfm-x/configure 2025-05-20 14:39:30.374565432 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/configure 2025-05-20 14:54:07.801983319 -0500 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for dvipdfm-x (TeX Live) 20250205. +# Generated by GNU Autoconf 2.72 for dvipdfm-x (TeX Live) 20250410. # # Report bugs to . # @@ -614,8 +614,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='dvipdfm-x (TeX Live)' PACKAGE_TARNAME='dvipdfm-x--tex-live-' -PACKAGE_VERSION='20250205' -PACKAGE_STRING='dvipdfm-x (TeX Live) 20250205' +PACKAGE_VERSION='20250410' +PACKAGE_STRING='dvipdfm-x (TeX Live) 20250410' PACKAGE_BUGREPORT='dvipdfmx@tug.org' PACKAGE_URL='' @@ -1387,7 +1387,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures dvipdfm-x (TeX Live) 20250205 to adapt to many kinds of systems. +'configure' configures dvipdfm-x (TeX Live) 20250410 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1459,7 +1459,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dvipdfm-x (TeX Live) 20250205:";; + short | recursive ) echo "Configuration of dvipdfm-x (TeX Live) 20250410:";; esac cat <<\_ACEOF @@ -1590,7 +1590,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dvipdfm-x (TeX Live) configure 20250205 +dvipdfm-x (TeX Live) configure 20250410 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -2371,7 +2371,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dvipdfm-x (TeX Live) $as_me 20250205, which was +It was created by dvipdfm-x (TeX Live) $as_me 20250410, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -9263,7 +9263,7 @@ fi # Define the identity of the package. PACKAGE='dvipdfm-x--tex-live-' - VERSION='20250205' + VERSION='20250410' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -16931,7 +16931,7 @@ Usage: $0 [OPTIONS] Report bugs to ." lt_cl_version="\ -dvipdfm-x (TeX Live) config.lt 20250205 +dvipdfm-x (TeX Live) config.lt 20250410 configured by $0, generated by GNU Autoconf 2.72. Copyright (C) 2024 Free Software Foundation, Inc. @@ -18885,7 +18885,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_wri # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by dvipdfm-x (TeX Live) $as_me 20250205, which was +This file was extended by dvipdfm-x (TeX Live) $as_me 20250410, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -18957,7 +18957,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -dvipdfm-x (TeX Live) config.status 20250205 +dvipdfm-x (TeX Live) config.status 20250410 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/configure.ac texlive-20250308-source/texk/dvipdfm-x/configure.ac --- texlive-20250308-source.orig/texk/dvipdfm-x/configure.ac 2025-05-20 14:39:30.374565432 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/configure.ac 2025-05-20 14:54:07.801983319 -0500 @@ -8,7 +8,7 @@ dnl This file is free software; the co dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl -AC_INIT([dvipdfm-x (TeX Live)], [20250205], [dvipdfmx@tug.org]) +AC_INIT([dvipdfm-x (TeX Live)], [20250410], [dvipdfmx@tug.org]) AC_PREREQ([2.65]) AC_CONFIG_SRCDIR([agl.c]) AC_CONFIG_AUX_DIR([../../build-aux]) diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/dvipdfmx.c texlive-20250308-source/texk/dvipdfm-x/dvipdfmx.c --- texlive-20250308-source.orig/texk/dvipdfm-x/dvipdfmx.c 2025-05-20 14:39:30.374565432 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/dvipdfmx.c 2025-05-20 14:54:07.802983313 -0500 @@ -127,7 +127,7 @@ static int translate_origin = 0; static int has_paper_option = 0; /* Input and output filenames */ -static char *dvi_filename = NULL, *pdf_filename = NULL; +char *dvi_filename = NULL, *pdf_filename = NULL; static void read_config_file (const char *config); diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/dvipdfmx.h texlive-20250308-source/texk/dvipdfm-x/dvipdfmx.h --- texlive-20250308-source.orig/texk/dvipdfm-x/dvipdfmx.h 2025-05-20 14:39:30.375565428 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/dvipdfmx.h 2025-05-20 14:54:07.802983313 -0500 @@ -26,6 +26,7 @@ #define _DVIPDFMX_H_ extern const char *my_name; +extern char *dvi_filename, *pdf_filename; extern int extractbb(int argc, char *argv[]); extern void read_config_special(const char **start, const char *end); diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/epdf.c texlive-20250308-source/texk/dvipdfm-x/epdf.c --- texlive-20250308-source.orig/texk/dvipdfm-x/epdf.c 2025-05-20 14:39:30.375565428 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/epdf.c 2025-05-20 14:54:07.802983313 -0500 @@ -119,7 +119,7 @@ pdf_include_page (pdf_ximage *xim xform_info info; pdf_obj *contents = NULL, *catalog; pdf_obj *page = NULL, *resources = NULL, *markinfo = NULL; - pdf_obj *group = NULL; + pdf_obj *group = NULL, *group_obj = NULL; pf = pdf_open(ident, image_file); if (!pf) @@ -155,7 +155,9 @@ pdf_include_page (pdf_ximage *xim /* * Handle page's Group */ - group = pdf_deref_obj(pdf_lookup_dict(page, "Group")); + group_obj = pdf_lookup_dict(page, "Group"); + if (group_obj) + group = pdf_import_object(group_obj); /* * Handle page content stream. */ diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/Makefile.am texlive-20250308-source/texk/dvipdfm-x/Makefile.am --- texlive-20250308-source.orig/texk/dvipdfm-x/Makefile.am 2025-05-20 14:39:30.372565438 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/Makefile.am 2025-05-20 14:54:07.799983332 -0500 @@ -1,7 +1,7 @@ ## $Id: Makefile.am 73682 2025-02-02 08:04:50Z ymorimi $ ## Makefile.am for the TeX Live subdirectory texk/dvipdfm-x/ ## -## Copyright 2015-2024 Karl Berry +## Copyright 2015-2025 Karl Berry ## Copyright 2009-2015 Peter Breitenlohner ## You may freely use, modify and/or distribute this file. ## @@ -243,13 +243,15 @@ DISTCLEANFILES = config.force ## Tests ## TESTS = xdvipdfmx.test xdvipdfm-ann.test xdvipdfm-bad.test xdvipdfm-bb.test -TESTS += xdvipdfm-bkm.test xdvipdfm-psz.test xdvipdfm-ptx.test xdvipdfm-res.test +TESTS += xdvipdfm-bkm.test xdvipdfm-pdf.test xdvipdfm-psz.test +TESTS += xdvipdfm-ptx.test xdvipdfm-res.test TESTS += xdvipdfm-rev.test xdvipdfm-ttc.test TESTS += dvipdfmx-upjf.test dvipdfmx-upjf2.test dvipdfmx-upjf3.test dvipdfmx-incl.test TESTS += dvipdfmx-lmr0.test dvipdfmx-lmr1.test TESTS += dvipdfmx-ttf0.test xdvipdfmx.log xdvipdfm-ann.log xdvipdfm-bad.log xdvipdfm-bb.log \ - xdvipdfm-bkm.log xdvipdfm-psz.log xdvipdfm-ptx.log xdvipdfm-res.log \ + xdvipdfm-bkm.log xdvipdfm-pdf.log xdvipdfm-psz.log \ + xdvipdfm-ptx.log xdvipdfm-res.log \ xdvipdfm-rev.log xdvipdfm-ttc.log \ dvipdfmx-upjf.log dvipdfmx-upjf2.log dvipdfmx-upjf3.log dvipdfmx-incl.log \ dvipdfmx-lmr0.log dvipdfmx-lmr1.log \ @@ -279,6 +281,9 @@ DISTCLEANFILES += pic*.* ## xdvipdfm-bkm.test EXTRA_DIST += tests/bookm.dvi tests/bookm.tex DISTCLEANFILES += bookm*.pdf +## xdvipdfm-pdf.test +EXTRA_DIST += tests/xdvipdfm-pdf.xdv tests/rpki-ecosystem.drawio.pdf +DISTCLEANFILES += xdvipdfm-pdf*.pdf ## xdvipdfm-psz.test EXTRA_DIST += tests/paper.dvi tests/paper.tex DISTCLEANFILES += paper*.pdf diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/Makefile.in texlive-20250308-source/texk/dvipdfm-x/Makefile.in --- texlive-20250308-source.orig/texk/dvipdfm-x/Makefile.in 2025-05-20 14:39:30.372565438 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/Makefile.in 2025-05-20 14:54:07.800983325 -0500 @@ -828,16 +828,16 @@ dist_mapdata_DATA = data/cid-x.map cmapdatadir = $(datarootdir)/texmf-dist/fonts/cmap/dvipdfmx dist_cmapdata_DATA = data/EUC-UCS2 DISTCLEANFILES = config.force image*.pdf xbmc*.pdf annot*.pdf pic*.* \ - bookm*.pdf paper*.pdf ptex*.pdf resrc*.pdf reverse.pdf \ - ttc*.pdf upjf.vf upjv.vf upjf-*.ofm upjv-*.ofm upjf-*.tfm \ - upjf_*.pdf upjf1_*.pdf upjf2_*.pdf upjf3_*.pdf multi_incl.pdf \ - lmr0-*.pdf cprm*.pdf + bookm*.pdf xdvipdfm-pdf*.pdf paper*.pdf ptex*.pdf resrc*.pdf \ + reverse.pdf ttc*.pdf upjf.vf upjv.vf upjf-*.ofm upjv-*.ofm \ + upjf-*.tfm upjf_*.pdf upjf1_*.pdf upjf2_*.pdf upjf3_*.pdf \ + multi_incl.pdf lmr0-*.pdf cprm*.pdf TESTS = xdvipdfmx.test xdvipdfm-ann.test xdvipdfm-bad.test \ - xdvipdfm-bb.test xdvipdfm-bkm.test xdvipdfm-psz.test \ - xdvipdfm-ptx.test xdvipdfm-res.test xdvipdfm-rev.test \ - xdvipdfm-ttc.test dvipdfmx-upjf.test dvipdfmx-upjf2.test \ - dvipdfmx-upjf3.test dvipdfmx-incl.test dvipdfmx-lmr0.test \ - dvipdfmx-lmr1.test dvipdfmx-ttf0.test + xdvipdfm-bb.test xdvipdfm-bkm.test xdvipdfm-pdf.test \ + xdvipdfm-psz.test xdvipdfm-ptx.test xdvipdfm-res.test \ + xdvipdfm-rev.test xdvipdfm-ttc.test dvipdfmx-upjf.test \ + dvipdfmx-upjf2.test dvipdfmx-upjf3.test dvipdfmx-incl.test \ + dvipdfmx-lmr0.test dvipdfmx-lmr1.test dvipdfmx-ttf0.test EXTRA_DIST = $(TESTS) tests/dvipdfmx.cfg tests/psfonts.map \ tests/cmr10.pfb tests/cmr10.tfm tests/image.dvi \ tests/image.tex tests/xbmc.dvi tests/xbmc.tex \ @@ -851,6 +851,7 @@ EXTRA_DIST = $(TESTS) tests/dvipdfmx.cfg tests/picjpeg.xbb tests/image.png tests/picpng.bb \ tests/picpng.xbb tests/image.pdf tests/picpdf.bb \ tests/picpdf.xbb tests/bookm.dvi tests/bookm.tex \ + tests/xdvipdfm-pdf.xdv tests/rpki-ecosystem.drawio.pdf \ tests/paper.dvi tests/paper.tex tests/ptex.dvi tests/resrc.dvi \ tests/resrc.tex tests/reverse.dvi tests/ttc.dvi tests/ttc.tex \ tests/test.ttc tests/upjf.dvi tests/upjf.tex tests/upjf.map \ @@ -2056,7 +2057,8 @@ config.force: $(ZLIB_DEPEND) $(LIBPNG_DE @ZLIB_RULE@ @LIBPAPER_RULE@ xdvipdfmx.log xdvipdfm-ann.log xdvipdfm-bad.log xdvipdfm-bb.log \ - xdvipdfm-bkm.log xdvipdfm-psz.log xdvipdfm-ptx.log xdvipdfm-res.log \ + xdvipdfm-bkm.log xdvipdfm-pdf.log xdvipdfm-psz.log \ + xdvipdfm-ptx.log xdvipdfm-res.log \ xdvipdfm-rev.log xdvipdfm-ttc.log \ dvipdfmx-upjf.log dvipdfmx-upjf2.log dvipdfmx-upjf3.log dvipdfmx-incl.log \ dvipdfmx-lmr0.log dvipdfmx-lmr1.log \ diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/pdffont.c texlive-20250308-source/texk/dvipdfm-x/pdffont.c --- texlive-20250308-source.orig/texk/dvipdfm-x/pdffont.c 2025-05-20 14:39:30.381565408 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/pdffont.c 2025-05-20 14:54:07.802983313 -0500 @@ -31,6 +31,7 @@ #include "mem.h" #include "dpxconf.h" +#include "dpxcrypt.h" #include "dpxfile.h" #include "dpxutil.h" @@ -51,6 +52,8 @@ #include "type0.h" #include "tt_cmap.h" +#include "dvipdfmx.h" + #include "pdffont.h" #define MREC_HAS_TOUNICODE(m) ((m) && (m)->opt.tounicode) @@ -61,14 +64,68 @@ pdf_font_set_dpi (int font_dpi) PKFont_set_dpi(font_dpi); } +static union { + char p[sizeof(int)]; + int* i; +} unique_tag_count; + +/* This function used to be implemented as + * + * for (i = 0; i < 6; i++) { + * ch = rand() % 26; + * tag[i] = ch + 'A'; + * } + * tag[6] = '\0'; + * + * but this meant that the tag would change on every run, producing a + * non-deterministic PDF file. You could work around this by setting + * `SOURCE_DATE_EPOCH` in the environment (since the current time is used to + * seed `rand`), but that requires extra effort. Instead, we use an MD5 hash of + * the input (dvi) filename, the output (pdf) filename, and a counter that + * increments on each call to this function. This produces a deterministic tag + * for each document, provided that the input filename, the output filename, and + * the order/number of fonts remains the same. + * + * Why do we need this function in the first place? Well, since we are + * subsetting the fonts, this means that the "LM Roman 10" font in one document + * will not be the same as the "LM Roman 10" font in another document. This can + * cause problems when older/buggy PDF processors merge or embed multiple + * documents, since it's invalid to have two fonts with the same name and + * neither font is a strict subset/superset of the other. + * + * pdfTeX and LuaTeX solve this by hashing over the subsetting hash table, but + * this only works there since they only generate the PDF font name _after_ + * creating the subset. (x)dvipdfmx generates the PDF font name as (almost) the + * very first step when including a font, so we couldn't use this method without + * extensive refactoring. + * + * The pdfTeX and LuaTeX methods guarantee that multiple incompatible subsets + * will never have the same name (barring hash collisions), and the prior `rand` + * method had the same guarantee (barring an _extremely_ unlikely RNG + * collision). This new method isn't quite as good since if the input and output + * are both pipes, then both filenames will be `NULL` and the tag will only + * depend on the counter. But I think that most PDF processors these days will + * properly check for font name collisions, so this is probably good enough. + */ void pdf_font_make_uniqueTag (char *tag) { - int i; - char ch; + MD5_CONTEXT state; + unsigned char digest[16]; + int i, ch; + + unique_tag_count.i++; + + MD5_init(&state); + if (dvi_filename) + MD5_write(&state, dvi_filename, strlen(dvi_filename)); + if (pdf_filename) + MD5_write(&state, pdf_filename, strlen(pdf_filename)); + MD5_write(&state, unique_tag_count.p, sizeof(unique_tag_count)); + MD5_final(digest, &state); for (i = 0; i < 6; i++) { - ch = rand() % 26; + ch = digest[i] % 26; tag[i] = ch + 'A'; } tag[6] = '\0'; diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/pdfobj.c texlive-20250308-source/texk/dvipdfm-x/pdfobj.c --- texlive-20250308-source.orig/texk/dvipdfm-x/pdfobj.c 2025-05-20 14:39:30.381565408 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/pdfobj.c 2025-05-20 14:54:07.802983313 -0500 @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2025 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -3646,7 +3646,8 @@ pdf_get_object (pdf_file *pf, uint32_t o length = pdf_stream_length(objstm); p = (const char *) pdf_stream_dataptr(objstm) + first + data[2*index+1]; - q = p + (index == n-1 ? length : first+data[2*index+3]); + q = (const char *) pdf_stream_dataptr(objstm) + + (index == n-1 ? length : first+data[2*index+3]); result = parse_pdf_object(&p, q, pf); if (!result) goto error; diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/tests/xdvipdfm-pdfgroup.tex texlive-20250308-source/texk/dvipdfm-x/tests/xdvipdfm-pdfgroup.tex --- texlive-20250308-source.orig/texk/dvipdfm-x/tests/xdvipdfm-pdfgroup.tex 1969-12-31 18:00:00.000000000 -0600 +++ texlive-20250308-source/texk/dvipdfm-x/tests/xdvipdfm-pdfgroup.tex 2025-05-20 14:54:07.802983313 -0500 @@ -0,0 +1,8 @@ +% $Id: xdvipdfm-pdfgroup.tex 74908 2025-04-10 22:20:35Z karl $ +% Public domain. Test input file for xdvipdfm-pdf(group) test. +% latex, dvipdfmx +\documentclass[dvipdfmx]{article} +\usepackage{graphicx} +\begin{document} +\includegraphics[width=4cm]{xdvipdfm-pdfgroup-0318.pdf} +\end{document} diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/vf.c texlive-20250308-source/texk/dvipdfm-x/vf.c --- texlive-20250308-source.orig/texk/dvipdfm-x/vf.c 2025-05-20 14:39:30.384565398 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/vf.c 2025-05-20 14:54:07.802983313 -0500 @@ -47,6 +47,8 @@ #define TEXPT2PT (72.0/72.27) #define FW2PT (TEXPT2PT/((double)(FIX_WORD_BASE))) +#define CHAR_INDEX_MIN 0x40000 + struct font_def { int32_t font_id /* id used internally in vf file */; uint32_t checksum, size, design_size; @@ -65,6 +67,7 @@ struct vf unsigned char **ch_pkt, message_flag; uint32_t *pkt_len; unsigned num_chars; + uint32_t *idx_to_char, max_idx; }; struct vf *vf_fonts = NULL; @@ -111,12 +114,21 @@ static void resize_one_vf_font (struct v { unsigned i; if (size > (a_vf->num_chars)) { - size = MAX (size, a_vf->num_chars+256); + if (size > 0x40000) + size = MAX (size+0x1000, a_vf->num_chars+0x40000); + else if (size > 0x8000) + size = MAX (size+0x1000, a_vf->num_chars+0x8000); + else if (size > 0x1000) + size = MAX (size+0x100, a_vf->num_chars+0x1000); + else + size = MAX (size, a_vf->num_chars+256); a_vf->ch_pkt = RENEW (a_vf->ch_pkt, size, unsigned char *); a_vf->pkt_len = RENEW (a_vf->pkt_len, size, uint32_t); + a_vf->idx_to_char = RENEW (a_vf->idx_to_char, size, uint32_t); for (i=a_vf->num_chars; ich_pkt)[i] = NULL; (a_vf->pkt_len)[i] = 0; + (a_vf->idx_to_char)[i] = -1; } a_vf->num_chars = size; } @@ -126,20 +138,35 @@ static void read_a_char_def(FILE *vf_fil uint32_t ch) { unsigned char *pkt; + uint32_t idx; + #ifdef DEBUG fprintf (stderr, "read_a_char_def: len=%u, ch=%u\n", pkt_len, ch); #endif + idx = ch; + if (ch >= CHAR_INDEX_MIN) { + if (vf_fonts[thisfont].max_idx==0) + vf_fonts[thisfont].max_idx = CHAR_INDEX_MIN; + idx = vf_fonts[thisfont].max_idx; + } /* Resize and initialize character arrays if necessary */ - if (ch >= vf_fonts[thisfont].num_chars) { - resize_one_vf_font (vf_fonts+thisfont, ch+1); + if (idx >= vf_fonts[thisfont].num_chars) + resize_one_vf_font (vf_fonts+thisfont, idx+1); + if (ch >= CHAR_INDEX_MIN) { + if (idx > CHAR_INDEX_MIN && (vf_fonts[thisfont].idx_to_char)[idx-1] >= ch) { + fprintf (stderr, "Unexpected character code: %x, index: %x\n", ch, idx); + ERROR ("Unexpected character code in vf file\n"); + } + (vf_fonts[thisfont].idx_to_char)[idx] = ch; + vf_fonts[thisfont].max_idx++; } if (pkt_len > 0) { pkt = NEW (pkt_len, unsigned char); if (fread (pkt, 1, pkt_len, vf_file) != pkt_len) ERROR ("VF file ended prematurely."); - (vf_fonts[thisfont].ch_pkt)[ch] = pkt; + (vf_fonts[thisfont].ch_pkt)[idx] = pkt; } - (vf_fonts[thisfont].pkt_len)[ch] = pkt_len; + (vf_fonts[thisfont].pkt_len)[idx] = pkt_len; return; } @@ -278,6 +305,8 @@ int vf_locate_font (const char *tex_name vf_fonts[thisfont].num_chars = 0; vf_fonts[thisfont].ch_pkt = NULL; vf_fonts[thisfont].pkt_len = NULL; + vf_fonts[thisfont].idx_to_char = NULL; + vf_fonts[thisfont].max_idx = 0; } read_header(vf_file, thisfont); process_vf_file (vf_file, thisfont); @@ -406,16 +435,30 @@ void vf_set_char(int32_t ch, int vf_font unsigned char *start, *end; spt_t ptsize; int default_font = -1; + int32_t idx; + idx = ch; + if (ch >= CHAR_INDEX_MIN) { + int32_t j, k, mid, ch0; + idx = -1; + j=CHAR_INDEX_MIN; k=vf_fonts[vf_font].max_idx; + while (j < k) { + mid = j + (k - j) / 2; + ch0 = (vf_fonts[vf_font].idx_to_char)[mid]; + if (ch0 < ch) j = mid+1; + else if (ch0 > ch) k = mid; + else { idx = mid; break; } + } + } if (vf_font < num_vf_fonts) { /* Initialize to the first font or -1 if undefined */ ptsize = vf_fonts[vf_font].ptsize; if (vf_fonts[vf_font].num_dev_fonts > 0) default_font = ((vf_fonts[vf_font].dev_fonts)[0]).dev_id; dvi_vf_init (default_font); - if (ch >= vf_fonts[vf_font].num_chars || - !(start = (vf_fonts[vf_font].ch_pkt)[ch])) { + if (idx >= vf_fonts[vf_font].num_chars || idx < 0 || + !(start = (vf_fonts[vf_font].ch_pkt)[idx])) { int is_jfm = tfm_is_jfm(vf_fonts[vf_font].dev_fonts[0].tfm_id); - if (is_jfm && + if (is_jfm && ch < CHAR_INDEX_MIN && ch <= JFM_LASTCHAR && dpx_conf.compat_mode != dpx_mode_xdv_mode) { /* fallback multibyte character for (u)pTeX */ if (dpx_conf.verbose_level == 1) @@ -437,7 +480,7 @@ void vf_set_char(int32_t ch, int vf_font fprintf (stderr, "Tried to set a nonexistent character in a virtual font"); start = end = NULL; } else { - end = start + (vf_fonts[vf_font].pkt_len)[ch]; + end = start + (vf_fonts[vf_font].pkt_len)[idx]; } while (start && start < end) { opcode = *(start++); @@ -555,6 +598,8 @@ void vf_close_all_fonts(void) } if (vf_fonts[i].pkt_len) RELEASE (vf_fonts[i].pkt_len); + if (vf_fonts[i].idx_to_char) + RELEASE (vf_fonts[i].idx_to_char); if (vf_fonts[i].tex_name) RELEASE (vf_fonts[i].tex_name); /* Release each font record */ diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/xdvipdfm-pdf.test texlive-20250308-source/texk/dvipdfm-x/xdvipdfm-pdf.test --- texlive-20250308-source.orig/texk/dvipdfm-x/xdvipdfm-pdf.test 1969-12-31 18:00:00.000000000 -0600 +++ texlive-20250308-source/texk/dvipdfm-x/xdvipdfm-pdf.test 2025-05-20 14:54:07.803983307 -0500 @@ -0,0 +1,54 @@ +#! /bin/sh -vx +# $Id: xdvipdfm-pdf.test 74908 2025-04-10 22:20:35Z karl $ +# Copyright 2025 Karl Berry +# You may freely use, modify and/or distribute this file. +# PDF parsing reports. + +BinDir=${BinDir:-.} +ExeExt=${ExeExt:-} +_xdvipdfmx=$BinDir/xdvipdfmx$ExeExt + +TEXMFCNF=$srcdir/../kpathsea +TFMFONTS="$srcdir/tests;$srcdir/data" +T1FONTS="$srcdir/tests;$srcdir/data" +TEXFONTMAPS="$srcdir/tests;$srcdir/data" +DVIPDFMXINPUTS="$srcdir/tests;$srcdir/data" +TEXPICTS=$srcdir/tests +export TEXMFCNF TFMFONTS T1FONTS TEXFONTMAPS DVIPDFMXINPUTS TEXPICTS + +failed= + +# xdvipdfm-pdfobj: Object stream parsing bug. Original report from +# Shuqiao Zhang, +# https://tug.org/pipermail/tex-live/2025-April/051444.html +# Unfortunately the bug is not reliably reproducible, as Zhang explains +# in https://tug.org/pipermail/tex-live/2025-April/051447.html. + +# xdvipdfm-pdfgroup: Page group bug. Report and fix from Clerk Ma, +# ca. 19 Mar 2025. + +for testfile in xdvipdfm-pdfobj.xdv xdvipdfm-pdfgroup.dvi; do + testin=$srcdir/tests/$testfile + testout=$testfile.pdf + # + # The pdfobj.xdv test includes a .pdf file, referenced as ./ in the + # .xdv, so have to copy it into the working directory. + cp $srcdir/tests/rpki-ecosystem.drawio.pdf . || exit 1 + # + # By the way, the pdfgroup.dvi test includes the file + # xdvipdfm-pdfgroup-0318.pdf, but since that reference doesn't use + # "./", it can be found in srcdir/tests via TEXPICTS above. + # + cmd="$_xdvipdfmx $testin -o $testout" + echo "*** $cmd" + if $cmd && test -s $testout; then + echo "$testfile test OK" + else + failed="$failed $testfile" + fi +done + +test -z "$failed" && exit 0 +echo +echo "failed tests:$failed" +exit 1 diff -Naurp texlive-20250308-source.orig/texk/dvipdfm-x/xdvipdfm-psz.test texlive-20250308-source/texk/dvipdfm-x/xdvipdfm-psz.test --- texlive-20250308-source.orig/texk/dvipdfm-x/xdvipdfm-psz.test 2025-05-20 14:39:30.384565398 -0500 +++ texlive-20250308-source/texk/dvipdfm-x/xdvipdfm-psz.test 2025-05-20 14:54:07.803983307 -0500 @@ -18,14 +18,16 @@ export TEXMFCNF TFMFONTS T1FONTS TEXFONT failed= -echo "*** xdvipdfmx -v -m 1.0 -o paper2.pdf paper2m.pdf" && echo \ - && $_xdvipdfmx -v -m 1.4 -o - $srcdir/tests/paper >paper2m.pdf \ - && echo && echo "xdvipdfmx-paper-mag tests OK" && echo \ +echo "*** xdvipdfmx -v -m 1.4 -o paper2m.pdf paper" \ + && $_xdvipdfmx -v -m 1.4 -o paper2m.pdf $srcdir/tests/paper \ + && test -s paper2m.pdf \ + && echo "xdvipdfmx-paper-mag tests OK" && echo \ || failed="$failed xdvipdfmx-paper-mag" test -z "$failed" && exit 0 diff -Naurp texlive-20250308-source.orig/texk/web2c/doc/luatex/luatex-math.tex texlive-20250308-source/texk/web2c/doc/luatex/luatex-math.tex --- texlive-20250308-source.orig/texk/web2c/doc/luatex/luatex-math.tex 2025-05-20 14:39:30.553564827 -0500 +++ texlive-20250308-source/texk/web2c/doc/luatex/luatex-math.tex 2025-05-20 14:50:57.053154749 -0500 @@ -1,4 +1,4 @@ -% language=uk engine=luatex runpath=texruns:manuals/luatex +% language=us engine=luatex runpath=texruns:manuals/luatex \environment luatex-style @@ -835,31 +835,58 @@ experimenting. \topicindex {math+italics} -The \lpr {mathitalicsmode} parameter can be set to~1 to force italic correction -before noads that represent some more complex structure (read: everything that is -not an ord, bin, rel, open, close, punct or inner). A value of~2 will enforce the -old school font code path for all italics. We show a Cambria example. - -\starttexdefinition Whatever #1 - \NC \type{\mathitalicsmode = #1} - \NC \mathitalicsmode#1\ruledhbox{$\left|T^1\right|$} - \NC \mathitalicsmode#1\ruledhbox{$\left|T\right|$} - \NC \mathitalicsmode#1\ruledhbox{$T+1$} - \NC \mathitalicsmode#1\ruledhbox{$T{1\over2}$} - \NC \mathitalicsmode#1\ruledhbox{$T\sqrt{1}$} - \NC \NR -\stoptexdefinition - -\start - \switchtobodyfont[cambria] - \starttabulate[|c|c|c|c|c|c|] - \Whatever{0}% - \Whatever{1}% - \stoptabulate -\stop - -This kind of parameters relate to the fact that italic correction in \OPENTYPE\ -math is bound to fuzzy rules. So, control is the solution. +The \lpr {mathitalicsmode} parameter was introduced to deal with the difference +in applying italic correction in traditional and \OPENTYPE\ math fonts. There are +\OPENTYPE\ fonts out there that have italic correction and assume them to be +applied like traditional \TEX\ fonts. This parameter takes several values: + +When set to zero, you get what was decided when the two code paths (traditional +and \OPENTYPE) were introduced. + +Values larger than zero will add the italic correction between simple noads (it +checks some classes so you might pay attention to for instance punctuation +classes assigned). + +When set to zero or one, italics are independent, so we separate width from +italic, while values larger than one combine both in the width but later +selectively has to get rid of it (depending on code path). + +A value larger than two will backtrack italics for large operators, because there +italic correction is used for anchoring scripts (limits and no limits). In fact, +\OPENTYPE\ uses italics either between characters or for this purpose but as +mentioned fonts are sort of messy here. + +We tested our version of plain \TEX\ and recommend to use the value of three to +get the best average results. More about this italic correction dilemma in +rendering math can be found in articles (in for instance \TUGBOAT) and various +documents in the \CONTEXT\ distribution, especially those that discuss the +upgraded math engine in \LUAMETATEX. + +% The \lpr {mathitalicsmode} parameter can be set to~1 to force italic correction +% before noads that represent some more complex structure (read: everything that is +% not an ord, bin, rel, open, close, punct or inner). A value of~2 will enforce the +% old school font code path for all italics. We show a Cambria example. +% +% \starttexdefinition Whatever #1 +% \NC \type{\mathitalicsmode = #1} +% \NC \mathitalicsmode#1\ruledhbox{$\left|T^1\right|$} +% \NC \mathitalicsmode#1\ruledhbox{$\left|T\right|$} +% \NC \mathitalicsmode#1\ruledhbox{$T+1$} +% \NC \mathitalicsmode#1\ruledhbox{$T{1\over2}$} +% \NC \mathitalicsmode#1\ruledhbox{$T\sqrt{1}$} +% \NC \NR +% \stoptexdefinition +% +% \start +% \switchtobodyfont[cambria] +% \starttabulate[|c|c|c|c|c|c|] +% \Whatever{0}% +% \Whatever{1}% +% \stoptabulate +% \stop +% +% This kind of parameters relate to the fact that italic correction in \OPENTYPE\ +% math is bound to fuzzy rules. So, control is the solution. \subsection {Script and kerning} @@ -1630,26 +1657,31 @@ explicitly set the style in the content \subsection {Math options with \lpr {mathoption}} -The logic in the math engine is rather complex and there are often no universal -solutions (read: what works out well for one font, fails for another). Therefore -some variations in the implementation are driven by parameters (modes). In -addition there is a new primitive \lpr {mathoption} which will be used for -testing. Don't rely on any option to be there in a production version as they are -meant for development. - -This option was introduced for testing purposes when the math engine got split -code paths and it forces the engine to treat new fonts as old ones with respect -to italic correction etc. There are no guarantees given with respect to the final -result and unexpected side effects are not seen as bugs as they relate to font -properties. There is currently only one option: +This command is now obsolete and triggers an error message. It was only meant +for experiments. -\startbuffer -\mathoption old 1 -\stopbuffer +% % even more obsolete: -The \type {oldmath} boolean flag in the \LUA\ font table is the official way to -force old treatment as it's bound to fonts. Like with all options we may -temporarily introduce with this command this feature is not meant for production. +% The logic in the math engine is rather complex and there are often no universal +% solutions (read: what works out well for one font, fails for another). Therefore +% some variations in the implementation are driven by parameters (modes). In +% addition there is a new primitive \lpr {mathoption} which will be used for +% testing. Don't rely on any option to be there in a production version as they are +% meant for development. +% +% This option was introduced for testing purposes when the math engine got split +% code paths and it forces the engine to treat new fonts as old ones with respect +% to italic correction etc. There are no guarantees given with respect to the final +% result and unexpected side effects are not seen as bugs as they relate to font +% properties. There is currently only one option: +% +% \startbuffer +% \mathoption old 1 +% \stopbuffer +% +% The \type {oldmath} boolean flag in the \LUA\ font table is the official way to +% force old treatment as it's bound to fonts. Like with all options we may +% temporarily introduce with this command this feature is not meant for production. % % obsolete: % diff -Naurp texlive-20250308-source.orig/texk/web2c/luatexdir/luatex.c texlive-20250308-source/texk/web2c/luatexdir/luatex.c --- texlive-20250308-source.orig/texk/web2c/luatexdir/luatex.c 2025-05-20 14:39:30.590564702 -0500 +++ texlive-20250308-source/texk/web2c/luatexdir/luatex.c 2025-05-20 14:53:05.235373451 -0500 @@ -32,9 +32,9 @@ stick to "0" upto "9" so users can expect a number represented as string. */ -int luatex_version = 121; +int luatex_version = 122; int luatex_revision = '0'; -const char *luatex_version_string = "1.21.0"; +const char *luatex_version_string = "1.22.0"; const char *engine_name = my_name; #include diff -Naurp texlive-20250308-source.orig/texk/web2c/luatexdir/luatex_svnversion.h texlive-20250308-source/texk/web2c/luatexdir/luatex_svnversion.h --- texlive-20250308-source.orig/texk/web2c/luatexdir/luatex_svnversion.h 2025-05-20 14:39:30.590564702 -0500 +++ texlive-20250308-source/texk/web2c/luatexdir/luatex_svnversion.h 2025-05-20 14:52:35.076559581 -0500 @@ -1,4 +1,4 @@ #ifndef luatex_svn_revision_h #define luatex_svn_revision_h -#define luatex_svn_revision 7667 +#define luatex_svn_revision 7673 #endif diff -Naurp texlive-20250308-source.orig/texk/web2c/luatexdir/tex/mlist.c texlive-20250308-source/texk/web2c/luatexdir/tex/mlist.c --- texlive-20250308-source.orig/texk/web2c/luatexdir/tex/mlist.c 2025-05-20 14:39:30.600564668 -0500 +++ texlive-20250308-source/texk/web2c/luatexdir/tex/mlist.c 2025-05-20 14:52:05.341741765 -0500 @@ -1602,7 +1602,7 @@ static pointer do_delimiter(pointer q, p shape i.e. they are end points in a variant list or a base character. It took two decades to run into an example (HH & MS). */ - if (is_new_mathfont(z)) { + if (is_new_mathfont(g)) { goto FOUND; } else if (char_tag(g, y) != ext_tag) { goto FOUND; diff -Naurp texlive-20250308-source.orig/texk/web2c/pdftexdir/ChangeLog texlive-20250308-source/texk/web2c/pdftexdir/ChangeLog --- texlive-20250308-source.orig/texk/web2c/pdftexdir/ChangeLog 2025-05-20 14:39:30.631564563 -0500 +++ texlive-20250308-source/texk/web2c/pdftexdir/ChangeLog 2025-05-20 14:56:00.141270984 -0500 @@ -1,3 +1,27 @@ +2025-05-17 Karl Berry + + * NEWS, + * pdftex_version.h, + * pdftex.web (pdftex_revision, pdftex_version_string): + version [1.40.]28 for post-TL25 fix. + +2025-05-15 Thanh Han The + + * pdftex.web (adv_char_width): remove dd parameter; call + divide_scaled by the hardwired 4, instead of dd. + (pdf_init_font): also check that the width of character 32 is >one_bp + for the pdf_font_has_space_char value. + (pdf_begin_string, output_one_char): change adv_char_width calls + similarly. + This is to fix overlapping text in ptmr8r and other fonts, + reported by Ulrike 01 May 2025 10:23:07. + Test: 40-overlapping-text-with-pdfinterwordspaceon. + (pdftex r963) + +2025-04-17 Karl Berry + + * pdftex.web (bool): rename variable to booltemp, kowtowing to C23. + 2025-03-07 Karl Berry * TL'25 release. diff -Naurp texlive-20250308-source.orig/texk/web2c/pdftexdir/NEWS texlive-20250308-source/texk/web2c/pdftexdir/NEWS --- texlive-20250308-source.orig/texk/web2c/pdftexdir/NEWS 2025-05-20 14:39:30.631564563 -0500 +++ texlive-20250308-source/texk/web2c/pdftexdir/NEWS 2025-05-20 14:56:00.141270984 -0500 @@ -1,3 +1,8 @@ +pdfTeX 3.141592653-2.6-1.40.28 (TeX Live 2025 post-release) (17 May March 2025) +- bugfixes: + - fix overlapping text in ptmr8r and other fonts. + +----------------------------------------------------------------------------- pdfTeX 3.141592653-2.6-1.40.27 (TeX Live 2025) (7 March 2025) - changes: - new primitive \pdfptexuseunderscore: if positive or diff -Naurp texlive-20250308-source.orig/texk/web2c/pdftexdir/pdftex_version.h texlive-20250308-source/texk/web2c/pdftexdir/pdftex_version.h --- texlive-20250308-source.orig/texk/web2c/pdftexdir/pdftex_version.h 2025-05-20 14:39:30.634564553 -0500 +++ texlive-20250308-source/texk/web2c/pdftexdir/pdftex_version.h 2025-05-20 14:56:00.145270958 -0500 @@ -1 +1 @@ -#define PDFTEX_VERSION "1.40.27" +#define PDFTEX_VERSION "1.40.28" diff -Naurp texlive-20250308-source.orig/texk/web2c/pdftexdir/pdftex.web texlive-20250308-source/texk/web2c/pdftexdir/pdftex.web --- texlive-20250308-source.orig/texk/web2c/pdftexdir/pdftex.web 2025-05-20 14:39:30.634564553 -0500 +++ texlive-20250308-source/texk/web2c/pdftexdir/pdftex.web 2025-05-20 14:56:00.144270965 -0500 @@ -1,4 +1,4 @@ -% Copyright 1996-2024 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, +% Copyright 1996-2025 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, % % This file is part of pdfTeX. @@ -307,8 +307,8 @@ known as `\eTeX'. {printed when \eTeX\ starts} @# @d pdftex_version==140 { \.{\\pdftexversion} } -@d pdftex_revision=="27" { \.{\\pdftexrevision} } -@d pdftex_version_string=='-1.40.27' {current \pdfTeX\ version} +@d pdftex_revision=="28" { \.{\\pdftexrevision} } +@d pdftex_version_string=='-1.40.28' {current \pdfTeX\ version} @# @d pdfTeX_banner=='This is pdfTeX, Version 3.141592653',eTeX_version_string,pdftex_version_string {printed when \pdfTeX\ starts} @@ -10959,7 +10959,7 @@ p, q: pointer; @!save_scanner_status:small_number; {|scanner_status| upon entry} @!save_def_ref: pointer; {|def_ref| upon entry, important if inside `\.{\\message}'} @!save_warning_index: pointer; -@!bool: boolean; {temp boolean} +@!booltemp: boolean; {temp boolean} @!i: integer; {first temp integer} @!j: integer; {second temp integer} @!b:pool_pointer; {base of temporary string} @@ -11159,7 +11159,7 @@ pdf_mdfive_sum_code: save_warning_index := warning_index; save_def_ref := def_ref; save_cur_string; - bool := scan_keyword("file"); + booltemp := scan_keyword("file"); scan_pdf_ext_toks; s := tokens_to_string(def_ref); delete_token_ref(def_ref); @@ -11167,7 +11167,7 @@ pdf_mdfive_sum_code: warning_index := save_warning_index; scanner_status := save_scanner_status; b := pool_ptr; - getmd5sum(s, bool); + getmd5sum(s, booltemp); link(garbage) := str_toks(b); flush_str(s); ins_list(link(temp_head)); @@ -11230,7 +11230,7 @@ pdf_match_code: save_def_ref := def_ref; save_cur_string; {scan for icase} - bool := scan_keyword("icase"); + booltemp := scan_keyword("icase"); {scan for subcount} i := -1; {default for subcount} if scan_keyword("subcount") then begin @@ -11247,7 +11247,7 @@ pdf_match_code: warning_index := save_warning_index; scanner_status := save_scanner_status; b := pool_ptr; - matchstrings(s, t, i, bool); + matchstrings(s, t, i, booltemp); link(garbage) := str_toks(b); flush_str(t); flush_str(s); @@ -11286,7 +11286,7 @@ pdf_strcmp_code: end; pdf_colorstack_init_code: begin - bool := scan_keyword("page"); + booltemp := scan_keyword("page"); if scan_keyword("direct") then cur_val := direct_always else @@ -11304,7 +11304,7 @@ pdf_colorstack_init_code: def_ref := save_def_ref; warning_index := save_warning_index; scanner_status := save_scanner_status; - cur_val := newcolorstack(s, cur_val, bool); + cur_val := newcolorstack(s, cur_val, booltemp); flush_str(s); cur_val_level := int_val; if cur_val < 0 then begin @@ -15794,7 +15794,7 @@ accuracy. @!scaled_out: integer; {amount of |scaled| that was taken out in |divide_scaled|} @!init_pdf_output: boolean; -@!adv_char_width_s: integer; {to save result of calculation done in |adv_char_width| } +@!adv_char_width_s: integer; {to save result of calculation done in |adv_char_width|} @!adv_char_width_s_out: scaled; @ @= @@ -15809,6 +15809,9 @@ init_pdf_output := false; @ The following function divides |s| by |m|. |dd| is number of decimal digits. +The result is $r = (s/m) \times 10^{dd}$, and the remainder after +the division is $s - |scaled_out|$ + @= function divide_scaled(s, m: scaled; dd: integer): scaled; @@ -15893,7 +15896,7 @@ For PK fonts things are more complicated as we have to deal with scaling bitmaps as well. @p -procedure adv_char_width(f: internal_font_number; c: eight_bits; dd: eight_bits); +procedure adv_char_width(f: internal_font_number; c: eight_bits); {update |pdf_delta_h| by character width |w| from font |f|} var w, s_out: scaled; s: integer; @@ -15901,21 +15904,21 @@ begin w := char_width(f)(char_info(f)(c)); if isscalable(f) then begin if pdf_cur_Tm_a = 0 then begin - s := divide_scaled(w, pdf_font_size[f], dd); + s := divide_scaled(w, pdf_font_size[f], 4); s_out := scaled_out; pdf_delta_h := pdf_delta_h + s_out; end else begin s := divide_scaled(round_xn_over_d(w, 1000, 1000 + pdf_cur_Tm_a), pdf_font_size[f], - dd); + 4); s_out := round_xn_over_d(round_xn_over_d(pdf_font_size[f], abs(s), 10000), 1000 + pdf_cur_Tm_a, 1000); if s < 0 then s_out := -s_out; pdf_delta_h := pdf_delta_h + s_out; end; - adv_char_width_s := s; + adv_char_width_s := round(s/10); adv_char_width_s_out := s_out; end else pdf_delta_h := pdf_delta_h + get_pk_char_width(f, w); @@ -16151,7 +16154,7 @@ begin {create a new font object for |f|} pdf_create_obj(obj_type_font, f); - pdf_font_has_space_char[f] := hasspacechar(f); + pdf_font_has_space_char[f] := hasspacechar(f) and (char_width(f)(char_info(f)(32)) > one_bp); pdf_use_font(f, obj_ptr); end; @@ -16295,7 +16298,7 @@ begin {insert a real space char from the font when possible} if pdf_font_has_space_char[f] and pdf_doing_string then begin pdf_out(" "); - adv_char_width(f, 32, 4); { to get |adv_char_width_s| and |adv_char_width_s_out|} + adv_char_width(f, 32); { update |pdf_delta_h|, get |adv_char_width_s| and |adv_char_width_s_out|} s := s - adv_char_width_s; s_out := s_out - adv_char_width_s_out; pdf_mark_char(f, 32); @@ -16346,7 +16349,7 @@ begin pdf_read_dummy_font; pdf_begin_string(pdf_dummy_font); pdf_print(" "); - adv_char_width(pdf_dummy_font, 32, 4); + adv_char_width(pdf_dummy_font, 32); pdf_end_string_nl; gen_faked_interword_space := s; @@ -18431,7 +18434,7 @@ end; else begin pdf_begin_string(f); pdf_print_char(f, #); - adv_char_width(f, #, 4); + adv_char_width(f, #); end; end