[NTG-pdftex] vf font expansion bug

The Thanh Han hanthethanh at gmail.com
Wed Mar 25 14:06:42 CET 2020


Hi Karl,

it seems the primary problem is that pdftex tries to set font expansion
parameters for a font without checking if the font has been
successfully loaded (hence it modifies null_font which is totally wrong).

Please find the proposed patch attached. I have tested it against your test
files (thanks again for making things easy to reproduce).

Regards,
Thanh




On Wed, Mar 25, 2020 at 11:34 AM The Thanh Han <hanthethanh at gmail.com>
wrote:

> Hi Karl,
>
> many thanks for the analysis and the proposed patch. I will take a close
> look and get back soon.
>
> Regards,
> Thanh
>
>
> On Tue, Mar 24, 2020 at 10:29 PM Karl Berry <karl at freefriends.org> wrote:
>
>> Hello Thanh (please ack :), and everyone else - Robert (cc'd) recently
>> reported an "interesting" pdftex bug related to font expansion of vf
>> files on the tex-live list. For the record, his original report is here:
>>   https://tug.org/pipermail/tex-live/2020-March/045099.html
>> but I'll quote as needed to make this email self-contained. Sorry, it's
>> unavoidably long.
>>
>> I have a proposed fix (at the end) and am hoping for some kind of
>> confirmation that it makes sense. (I am definitely not planning to
>> make any change here for TL20. It's not that urgent, and testing is
>> needed.)
>>
>> So, Robert found a case where pdftex mixes up two expanded fonts, when
>> virtual fonts are involved. Here is a test file vfexp.tex, slightly
>> modified from his original so it will run with -ini:
>>
>>
>> -----------------------------------------------------------------------------
>> \catcode`\{=1 \catcode`\}=2 \pdfoutput=1 \nonstopmode \hbadness=10000
>> \vsize=20pc \hsize=30pt \parfillskip=0pt plus1fil
>> \font\1=cmr10
>> \font\2=bchr8t
>> %\font\2=bchr8r
>> \pdfmapfile{}
>> \pdfmapline{+cmr10 CMR10 <cmr10.pfb}
>> \pdfmapline{+bchr8r CharterBT-Roman " TeXBase1Encoding ReEncodeFont "
>> <8r.enc <bchr8a.pfb}
>> \pdfmapline{+bchr8r+20 CharterBT-Roman " 1.020 ExtendFont
>> TeXBase1Encoding ReEncodeFont " <8r.enc <bchr8a.pfb}
>> \pdfmapline{+bchr8r-20 CharterBT-Roman " 0.980 ExtendFont
>> TeXBase1Encoding ReEncodeFont " <8r.enc <bchr8a.pfb}
>> \pdffontexpand\1 100 100 5 %autoexpand
>> \pdffontexpand\2 20  20 20
>> \pdfadjustspacing=2
>> \1 ABC
>>
>> \2 This is a paragraph with font expansion.
>> \end
>>
>> -----------------------------------------------------------------------------
>>
>> bchr8t is a virtual font (otherwise the problem does not happen, per the
>> commented-out \font\2 above), and we are not using autoexpand here (bug
>> also goes away with autoexpand), and so Robert has actual tfm files for
>> bchr8[rt][+-]20.tfm. (I'll also attach an archive with all files to
>> reproduce.)
>>
>> Here are the errors from running (avoiding useless mktextfm calls)
>>   env TEXFONTS=.: MKTEXTFM=0 pdftex -ini -file-line-error vfexp.tex
>> now:
>> ./vfexp.tex:12:! Font \csname\endcsname=cmr10+100 at 10.0pt not loadable:
>> Metric (TFM) file no
>> ./vfexp.tex:12:! Font \csname\endcsname=cmr10-100 at 10.0pt not loadable:
>> Metric (TFM) file no
>> ./vfexp.tex:17:! Font \csname\endcsname=bchr8r+20-100 at 10.0pt not
>> loadable: Metric (TFM) fil
>> ./vfexp.tex:17:! Font \csname\endcsname=bchr8r-20-100 at 10.0pt not
>> loadable: Metric (TFM) fil
>>
>> The first two, about failing to make cmr10+100 and cmr10-100 at the
>> first \pdffontexpand, are expected.  (Robert, to answer one of your
>> questions: although you're right that those fonts will never be used,
>> and the doc is not exactly clear on this point [I'll try to improve it],
>> the reality is that pdftex immediately tries to make fonts for the
>> stretch/shrink limit when it processes \pdffontexpand. I don't think
>> this could/should be changed.)
>>
>> At the second \pdffontexpand line, it finds bchr8t.vf, and hence
>> bchr8r.tfm, and and the +20/-20.tfm files. All that is fine.
>>
>> But then, when pdftex is generating the output (pdf_hlist_out, etc.), it
>> needs to use the expanded bchr8r. The necessary tfms all exist (included
>> in the attached) but it erroneously uses the max shrink (-100) from the
>> cmr10 font \1, and tries to make the nonsensical bchr8r+20-100.
>>
>> I don't have any particular familiarity with this part of the code, but
>> tracing through the execution in the debugger, it seems the bug is
>> in vf_def_font, which calls set_expand_params (which makes the fonts)
>> with this call:
>>          set_expand_params(k, pdf_font_auto_expand[f],
>>                            pdf_font_expand_ratio[pdf_font_stretch[f]],
>>                            -pdf_font_expand_ratio[pdf_font_shrink[f]],
>>                            pdf_font_step[f], pdf_font_expand_ratio[f]);
>>
>> The problem is that pdf_font_stretch[f] (and _shrink[f]) are both zero
>> at this point. These are references to another font, i.e.,
>> null_font. But the zeroth entry of pdf_font_expand_ratio is not the zero
>> for null_font, but the -100 for the specified cmr10 (which doesn't make
>> sense to me, but I took it as given).
>>
>> FWIW, here are the various arrays at the critical point:
>> (gdb) ppool fontname[0]
>> $91 = "nullfont"
>> (gdb) ppool fontname[1]
>> $92 = "cmr10"
>> (gdb) ppool fontname[2]
>> $93 = "bchr8t"
>> (gdb) ppool fontname[3]
>> $94 = "bchr8t+20"
>> (gdb) ppool fontname[4]
>> $95 = "bchr8t-20"
>> (gdb) p pdffontstretch[0]@5
>> $96 = {0, 0, 3, 0, 0}
>> (gdb) p pdffontshrink[0]@5
>> $97 = {0, 0, 4, 0, 0}
>> (gdb) p pdffontexpandratio[0]@5
>> $98 = {-100, 0, 0, 20, -20}
>>
>> In other places in the code, e.g., check_expand_pars, there is an
>> explicit check for pdf_font_stretch and _shrink being null_font (= 0),
>> so I added the same explicit checks to vf_def_font, which seemed to
>> solve the problem. pdffonts reports the expanded/shrunken fonts used:
>> $ pdffonts vfexp.pdf
>> name                                 type              emb sub uni object
>> ID
>> ------------------------------------ ----------------- --- --- ---
>> ---------
>> QBBONQ+CMR10                         Type 1            yes yes no
>>  4  0
>> DCAQPT+CharterBT-Roman-Extend_1020   Type 1            yes yes no
>>  5  0
>> OXEYKB+CharterBT-Roman-Extend_980    Type 1            yes yes no
>>  6  0
>>
>> The same call to set_expand_params is in vf_expand_local_fonts, so
>> if the above is right, the same fix would be needed there. I could not
>> easily figure out how to exercise that code, though. Something like a vf
>> that refers to another vf?
>>
>> I'll append the full patch I have.
>> Thanh, anyone else, confirm/deny/comments?
>>
>> Robert, if you're willing, I could send you a new binary (x86_64-linux?)
>> for you to try. I presume your microtype work has more tests that could
>> go some way toward ensuring there's no unexpected side effect.
>>
>> Thanks,
>> Karl
>>
>> --- pdftex.web  (revision 822)
>> +++ pdftex.web  (working copy)
>> @@ -17519,13 +17519,21 @@
>>  procedure vf_expand_local_fonts(f: internal_font_number);
>>  var lf: internal_font_number;
>>      k: integer;
>> +    shrink_limit, stretch_limit: integer;
>>  begin
>>      pdfassert(pdf_font_type[f] = virtual_font_type);
>>      for k := 0 to vf_local_font_num[f] - 1 do begin
>>          lf := vf_i_fnts[vf_default_font[f] + k];
>> +       {Find stretch and shrink values, if any.}
>> +        if pdf_font_stretch[f] = null_font then stretch_limit := 0
>> +        else stretch_limit := pdf_font_expand_ratio[pdf_font_stretch[f]];
>> +       {Ditto for shrink.}
>> +        if pdf_font_shrink[f] = null_font then shrink_limit := 0
>> +        else shrink_limit := pdf_font_expand_ratio[pdf_font_stretch[f]];
>> +       {Now make the font(s) for |lf|.}
>>          set_expand_params(lf, pdf_font_auto_expand[f],
>> -                          pdf_font_expand_ratio[pdf_font_stretch[f]],
>> -                          -pdf_font_expand_ratio[pdf_font_shrink[f]],
>> +                          stretch_limit,
>> +                          -shrink_limit,
>>                            pdf_font_step[f], pdf_font_expand_ratio[f]);
>>          if pdf_font_type[lf] = virtual_font_type then
>>              vf_expand_local_fonts(lf);
>> @@ -17962,6 +17970,7 @@ vf_def_font
>>      s: str_number;
>>      ds, fs: scaled;
>>      cs: four_quarters;
>> +    stretch_limit, shrink_limit: integer;
>>  begin
>>      cs.b0 := vf_byte; cs.b1 := vf_byte; cs.b2 := vf_byte; cs.b3 :=
>> vf_byte;
>>      fs := store_scaled_f(vf_read_signed(4), font_size[f]);
>> @@ -17992,9 +18001,16 @@
>>              vf_local_font_warning(f, k, "design size mismatch");
>>      end;
>>      if (pdf_font_step[f] <> 0) then
>> +       {Find stretch and shrink values, if any.}
>> +        if pdf_font_stretch[f] = null_font then stretch_limit := 0
>> +        else stretch_limit := pdf_font_expand_ratio[pdf_font_stretch[f]];
>> +       {Ditto for shrink.}
>> +        if pdf_font_shrink[f] = null_font then shrink_limit := 0
>> +        else shrink_limit := pdf_font_expand_ratio[pdf_font_stretch[f]];
>> +       {Now make the font(s) for |k|.}
>>          set_expand_params(k, pdf_font_auto_expand[f],
>> -                          pdf_font_expand_ratio[pdf_font_stretch[f]],
>> -                          -pdf_font_expand_ratio[pdf_font_shrink[f]],
>> +                          stretch_limit,
>> +                          -shrink_limit,
>>                            pdf_font_step[f], pdf_font_expand_ratio[f]);
>>      vf_def_font := k;
>>  end;
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.ntg.nl/pipermail/ntg-pdftex/attachments/20200325/d3b5a050/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: bugfix__vf_font_expansion.patch
Type: application/octet-stream
Size: 1460 bytes
Desc: not available
URL: <http://mailman.ntg.nl/pipermail/ntg-pdftex/attachments/20200325/d3b5a050/attachment.obj>


More information about the ntg-pdftex mailing list