summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/pdftexdir/hz.ch
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/pdftexdir/hz.ch')
-rw-r--r--Build/source/texk/web2c/pdftexdir/hz.ch1935
1 files changed, 1935 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/pdftexdir/hz.ch b/Build/source/texk/web2c/pdftexdir/hz.ch
new file mode 100644
index 00000000000..d8ec58fb5e7
--- /dev/null
+++ b/Build/source/texk/web2c/pdftexdir/hz.ch
@@ -0,0 +1,1935 @@
+% WEB change file containing HZ extensions for pdfTeX
+%
+% Copyright (c) 1996-2002 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org>
+%
+% This file is part of pdfTeX.
+%
+% pdfTeX is free software; you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation; either version 2 of the License, or
+% (at your option) any later version.
+%
+% pdfTeX is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with pdfTeX; if not, write to the Free Software
+% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+%
+% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/hz.ch#15 $
+
+@x [155] - margin kerning
+@d acc_kern=2 {|subtype| of kern nodes from accents}
+@y
+@d acc_kern=2 {|subtype| of kern nodes from accents}
+
+@# {memory structure for marginal kerns}
+@d margin_kern_node = 40
+@d margin_kern_node_size = 3
+@d margin_char(#) == info(# + 2)
+
+@# {|subtype| of marginal kerns}
+@d left_side == 0
+@d right_side == 1
+
+@# {base for lp/rp/ef codes starts from 2:
+ 0 for |hyphen_char|,
+ 1 for |skew_char|}
+@d lp_code_base == 2
+@d rp_code_base == 3
+@d ef_code_base == 4
+
+@d max_hlist_stack = 512 {maximum fill level for |hlist_stack|}
+{maybe good if larger than |2 * max_quarterword|, so that box nesting level would overflow first}
+@z
+
+@x [183] - margin kerning
+ kern_node: @<Display kern |p|@>;
+@y
+ margin_kern_node: begin
+ print_esc("kern");
+ print_scaled(width(p));
+ if subtype(p) = left_side then
+ print(" (left margin)")
+ else
+ print(" (right margin)");
+ end;
+ kern_node: @<Display kern |p|@>;
+@z
+
+@x [202] - margin kerning
+ kern_node,math_node,penalty_node: do_nothing;
+@y
+ kern_node,math_node,penalty_node: do_nothing;
+ margin_kern_node: begin
+ free_avail(margin_char(p));
+ free_node(p, margin_kern_node_size);
+ goto done;
+ end;
+@z
+
+@x [206] - margin kerning
+kern_node,math_node,penalty_node: begin r:=get_node(small_node_size);
+ words:=small_node_size;
+ end;
+@y
+kern_node,math_node,penalty_node: begin r:=get_node(small_node_size);
+ words:=small_node_size;
+ end;
+margin_kern_node: begin
+ r := get_node(margin_kern_node_size);
+ fast_get_avail(margin_char(r));
+ font(margin_char(r)) := font(margin_char(p));
+ character(margin_char(r)) := character(margin_char(p));
+ words := small_node_size;
+ end;
+@z
+
+@x [236]
+@d pdf_int_pars=pdftex_first_integer_code + 17 {total number of \pdfTeX's integer parameters}
+@y
+@d pdf_adjust_spacing_code = pdftex_first_integer_code + 17 {level of spacing adjusting}
+@d pdf_protrude_chars_code = pdftex_first_integer_code + 18 {protrude chars at left/right edge of paragraphs}
+@d pdf_tracing_fonts_code = pdftex_first_integer_code + 19 {level of font detail in log}
+@d pdf_int_pars=pdftex_first_integer_code + 20 {total number of \pdfTeX's integer parameters}
+@z
+
+@x [236]
+@d error_context_lines==int_par(error_context_lines_code)
+@y
+@d error_context_lines==int_par(error_context_lines_code)
+@#
+@d pdf_adjust_spacing == int_par(pdf_adjust_spacing_code)
+@d pdf_protrude_chars == int_par(pdf_protrude_chars_code)
+@d pdf_tracing_fonts == int_par(pdf_tracing_fonts_code)
+@z
+
+@x [237]
+error_context_lines_code:print_esc("errorcontextlines");
+@y
+error_context_lines_code:print_esc("errorcontextlines");
+@#
+pdf_adjust_spacing_code: print_esc("pdfadjustspacing");
+pdf_protrude_chars_code: print_esc("pdfprotrudechars");
+pdf_tracing_fonts_code: print_esc("pdftracingfonts");
+@z
+
+@x [238]
+primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/
+@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@>
+@y
+primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/
+@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@>
+primitive("pdfadjustspacing",assign_int,int_base+pdf_adjust_spacing_code);@/
+@!@:pdf_adjust_spacing_}{\.{\\pdfadjustspacing} primitive@>
+primitive("pdfprotrudechars",assign_int,int_base+pdf_protrude_chars_code);@/
+@!@:pdf_protrude_chars_}{\.{\\pdfprotrudechars} primitive@>
+primitive("pdftracingfonts",assign_int,int_base+pdf_tracing_fonts_code);@/
+@!@:pdf_tracing_fonts_}{\.{\\pdftracingfonts} primitive@>
+@z
+
+@x [267] - displaying fonts
+@<Print the font identifier for |font(p)|@>=
+print_esc(font_id_text(font(p)))
+@y
+@<Print the font identifier for |font(p)|@>=
+begin
+ print_esc(font_id_text(font(p)));
+ if pdf_tracing_fonts > 0 then begin
+ print(" (");
+ print(font_name[font(p)]);
+ if font_size[font(p)] <> font_dsize[font(p)] then begin
+ print("@@");
+ print_scaled(font_size[font(p)]);
+ print("pt");
+ end;
+ print(")");
+ end else
+ if pdf_font_expand_ratio[font(p)] <> 0 then begin
+ print(" (");
+ if pdf_font_expand_ratio[font(p)] > 0 then
+ print("+");
+ print_int(pdf_font_expand_ratio[font(p)]);
+ print(")");
+ end;
+end
+@z
+
+@x [413] - font expansion
+var m:halfword; {|chr_code| part of the operand token}
+@y
+var m:halfword; {|chr_code| part of the operand token}
+ n, k: integer; {accumulators}
+@z
+
+@x [426] - font expansion, margin kerning
+begin scan_font_ident;
+if m=0 then scanned_result(hyphen_char[cur_val])(int_val)
+else scanned_result(skew_char[cur_val])(int_val);
+@y
+begin scan_font_ident;
+if m=0 then scanned_result(hyphen_char[cur_val])(int_val)
+else if m=1 then scanned_result(skew_char[cur_val])(int_val)
+else begin
+ n := cur_val;
+ scan_char_num;
+ k := cur_val;
+ case m of
+ lp_code_base: scanned_result(get_lp_code(n, k))(int_val);
+ rp_code_base: scanned_result(get_rp_code(n, k))(int_val);
+ ef_code_base: scanned_result(get_ef_code(n, k))(int_val);
+ end;
+end;
+@z
+
+@x [468]
+@d pdftex_convert_codes = pdftex_first_expand_code + 9 {end of \pdfTeX's command codes}
+@y
+@d left_margin_kern_code = pdftex_first_expand_code + 9 {command code for \.{\\leftmarginkern}}
+@d right_margin_kern_code = pdftex_first_expand_code + 10 {command code for \.{\\rightmarginkern}}
+@d pdftex_convert_codes = pdftex_first_expand_code + 11 {end of \pdfTeX's command codes}
+@z
+
+@x [468]
+primitive("pdfpageref",convert,pdf_page_ref_code);@/
+@!@:pdf_page_ref_}{\.{\\pdfpageref} primitive@>
+@y
+primitive("pdfpageref",convert,pdf_page_ref_code);@/
+@!@:pdf_page_ref_}{\.{\\pdfpageref} primitive@>
+primitive("leftmarginkern",convert,left_margin_kern_code);@/
+@!@:left_margin_kern_}{\.{\\leftmarginkern} primitive@>
+primitive("rightmarginkern",convert,right_margin_kern_code);@/
+@!@:right_margin_kern_}{\.{\\rightmarginkern} primitive@>
+@z
+
+@x [469]
+ pdf_page_ref_code: print_esc("pdfpageref");
+@y
+ pdf_page_ref_code: print_esc("pdfpageref");
+ left_margin_kern_code: print_esc("leftmarginkern");
+ right_margin_kern_code: print_esc("rightmarginkern");
+@z
+
+@x [470]
+var old_setting:0..max_selector; {holds |selector| setting}
+@y
+var old_setting:0..max_selector; {holds |selector| setting}
+p, q: pointer;
+@z
+
+@x [471]
+pdf_page_ref_code: begin
+ scan_int;
+ if cur_val <= 0 then
+ pdf_error("pageref", "invalid page number");
+end;
+@y
+pdf_page_ref_code: begin
+ scan_int;
+ if cur_val <= 0 then
+ pdf_error("pageref", "invalid page number");
+end;
+left_margin_kern_code, right_margin_kern_code: begin
+ scan_int;
+ if (box(cur_val) = null) or (type(box(cur_val)) <> hlist_node) then
+ pdf_error("marginkern", "a non-empty hbox expected")
+end;
+@z
+
+@x [472]
+pdf_page_ref_code: print_int(get_obj(obj_type_page, cur_val, false));
+@y
+pdf_page_ref_code: print_int(get_obj(obj_type_page, cur_val, false));
+left_margin_kern_code: begin
+ p := list_ptr(box(cur_val));
+ if (p <> null) and (not is_char_node(p)) and
+ (type(p) = glue_node) and (subtype(p) = left_skip_code + 1) then
+ p := link(p);
+ if (p <> null) and (not is_char_node(p)) and
+ (type(p) = margin_kern_node) and (subtype(p) = left_side) then
+ print_scaled(width(p))
+ else
+ print("0");
+ print("pt");
+end;
+right_margin_kern_code: begin
+ q := list_ptr(box(cur_val));
+ p := null;
+ if q <> null then begin
+ p := prev_rightmost(q, null);
+ if (p <> null) and (not is_char_node(p)) and
+ (type(p) = glue_node) and (subtype(p) = right_skip_code + 1) then
+ p := prev_rightmost(q, p);
+ end;
+ if (p <> null) and (not is_char_node(p)) and
+ (type(p) = margin_kern_node) and (subtype(p) = right_side) then
+ print_scaled(width(p))
+ else
+ print("0");
+ print("pt");
+end;
+@z
+
+@x [622] - margin kerning
+glue_node: @<Move right or output leaders@>;
+@y
+glue_node: @<Move right or output leaders@>;
+margin_kern_node,
+@z
+
+
+@x [???] - font expansion
+@!tmp_f: internal_font_number; {for use with |pdf_init_font|}
+
+@y
+@!tmp_f: internal_font_number; {for use with |pdf_init_font|}
+@ Here come some subroutines to deal with expanded fonts for HZ-algorithm.
+
+@p
+function init_font_base(v: integer): integer;
+var i, j: integer;
+begin
+ i := pdf_get_mem(256);
+ for j := 0 to 255 do
+ pdf_mem[i + j] := v;
+ init_font_base := i;
+end;
+
+procedure set_lp_code(f: internal_font_number; c: eight_bits; i: integer);
+begin
+ if pdf_font_lp_base[f] = 0 then
+ pdf_font_lp_base[f] := init_font_base(0);
+ pdf_mem[pdf_font_lp_base[f] + c] := fix_int(i, -1000, 1000);
+end;
+
+procedure set_rp_code(f: internal_font_number; c: eight_bits; i: integer);
+begin
+ if pdf_font_rp_base[f] = 0 then
+ pdf_font_rp_base[f] := init_font_base(0);
+ pdf_mem[pdf_font_rp_base[f] + c] := fix_int(i, -1000, 1000);
+end;
+
+procedure set_ef_code(f: internal_font_number; c: eight_bits; i: integer);
+begin
+ if pdf_font_ef_base[f] = 0 then
+ pdf_font_ef_base[f] := init_font_base(1000);
+ pdf_mem[pdf_font_ef_base[f] + c] := fix_int(i, 0, 1000);
+end;
+
+function expand_font_name(f: internal_font_number; e: integer): str_number;
+var old_setting:0..max_selector; {holds |selector| setting}
+begin
+ old_setting:=selector; selector:=new_string;
+ print(font_name[f]);
+ if e > 0 then
+ print("+"); {minus sign will be printed by |print_int|}
+ print_int(e);
+ selector:=old_setting;
+ expand_font_name := make_string;
+end;
+
+function auto_expand_font(f: internal_font_number; e: integer): internal_font_number;
+{creates an expanded font from the base font; doesn't load expanded tfm at all}
+var k: internal_font_number;
+ nw, nk, ni, i, j: integer;
+begin
+ k := font_ptr + 1;
+ incr(font_ptr);
+ if (font_ptr >= font_max) then
+ overflow("maximum internal font number (font_max)", font_max);
+ font_name[k] := expand_font_name(f, e);
+ font_area[k] := font_area[f];
+ font_id_text(k) := font_id_text(f);
+ hyphen_char[k] := hyphen_char[f];
+ skew_char[k] := skew_char[f];
+ font_bchar[k] := font_bchar[f];
+ font_false_bchar[k] := font_false_bchar[f];
+ font_bc[k] := font_bc[f];
+ font_ec[k] := font_ec[f];
+ font_size[k] := font_size[f];
+ font_dsize[k] := font_dsize[f];
+ font_params[k] := font_params[f];
+ font_glue[k] := font_glue[f];
+ bchar_label[k] := bchar_label[f];
+
+ char_base[k] := char_base[f];
+ height_base[k] := height_base[f];
+ depth_base[k] := depth_base[f];
+ lig_kern_base[k] := lig_kern_base[f];
+ exten_base[k] := exten_base[f];
+ param_base[k] := param_base[f];
+
+ nw := height_base[f] - width_base[f];
+ ni := lig_kern_base[f] - italic_base[f];
+ nk := exten_base[f] - (kern_base[f] + kern_base_offset);
+ if (fmem_ptr + nw + ni + nk >= font_mem_size) then
+ overflow("number of words of font memory (font_mem_size)", font_mem_size);
+ width_base[k] := fmem_ptr;
+ italic_base[k] := width_base[k] + nw;
+ kern_base[k] := italic_base[k] + ni - kern_base_offset;
+ fmem_ptr := fmem_ptr + nw + ni + nk;
+
+ for i := 0 to nw - 1 do
+ font_info[width_base[k] + i].sc :=
+ round_xn_over_d(font_info[width_base[f] + i].sc, 1000 + e, 1000);
+ for i := 0 to ni - 1 do
+ font_info[italic_base[k] + i].sc :=
+ round_xn_over_d(font_info[italic_base[f] + i].sc, 1000 + e, 1000);
+ for i := 0 to nk - 1 do
+ font_info[kern_base[k] + kern_base_offset + i].sc :=
+ round_xn_over_d(font_info[kern_base[f] + kern_base_offset + i].sc, 1000 + e, 1000);
+
+ auto_expand_font := k;
+end;
+
+procedure set_expand_param(k, f: internal_font_number; e: integer);
+var i, j: integer;
+begin
+ if pdf_font_rp_base[f] = 0 then
+ pdf_font_rp_base[f] := init_font_base(0);
+ if pdf_font_lp_base[f] = 0 then
+ pdf_font_lp_base[f] := init_font_base(0);
+ if pdf_font_ef_base[f] = 0 then
+ pdf_font_ef_base[f] := init_font_base(1000);
+ pdf_font_expand_ratio[k] := e;
+ pdf_font_step[k] := pdf_font_step[f];
+ pdf_font_auto_expand[k] := pdf_font_auto_expand[f];
+ pdf_font_blink[k] := f; {???}
+ pdf_font_lp_base[k] := pdf_font_lp_base[f];
+ pdf_font_rp_base[k] := pdf_font_rp_base[f];
+ pdf_font_ef_base[k] := pdf_font_ef_base[f];
+end;
+
+function tfm_lookup(s: str_number; fs: scaled): internal_font_number;
+{looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s|}
+var k: internal_font_number;
+begin
+ if fs <> 0 then begin
+ for k := font_base + 1 to font_ptr do
+ if str_eq_str(font_name[k], s) and (font_size[k] = fs) then begin
+ flush_str(s);
+ tfm_lookup := k;
+ return;
+ end;
+ end
+ else begin
+ for k := font_base + 1 to font_ptr do
+ if str_eq_str(font_name[k], s) then begin
+ flush_str(s);
+ tfm_lookup := k;
+ return;
+ end;
+ end;
+ tfm_lookup := null_font;
+end;
+
+function load_expand_font(f: internal_font_number; e: integer): internal_font_number;
+{loads font |f| expanded by |e| thousandths into font memory; |e| is nonzero
+and is a multiple of |pdf_font_step[f]|}
+label found;
+var s: str_number; {font name}
+ k: internal_font_number;
+begin
+ s := expand_font_name(f, e);
+ k := tfm_lookup(s, font_size[f]);
+ if k = null_font then begin
+ if pdf_font_auto_expand[f] then
+ k := auto_expand_font(f, e)
+ else
+ k := read_font_info(null_cs, s, "", font_size[f]);
+ end;
+ set_expand_param(k, f, e);
+ load_expand_font := k;
+end;
+
+function auto_expand_vf(f: internal_font_number): boolean;
+{check for a virtual auto-expanded font}
+var save_f, bf, lf, k: internal_font_number;
+ e: integer;
+begin
+ auto_expand_vf := false;
+ if (not pdf_font_auto_expand[f]) or (pdf_font_blink[f] = null_font) then
+ return; {not an auto-expanded font}
+ bf := pdf_font_blink[f];
+ if pdf_font_type[bf] = new_font_type then {we must process the base font first}
+ begin
+ save_f := tmp_f;
+ tmp_f := bf;
+ do_vf;
+ tmp_f := save_f;
+ end;
+
+ if pdf_font_type[bf] <> virtual_font_type then
+ return; {not a virtual font}
+
+ e := pdf_font_expand_ratio[f];
+ for k := 0 to vf_local_font_num[bf] - 1 do begin
+ lf := vf_default_font[bf] + k;
+ vf_e_fnts[vf_nf] := vf_e_fnts[lf];
+ vf_i_fnts[vf_nf] := auto_expand_font(vf_i_fnts[lf], e);
+ set_expand_param(vf_i_fnts[vf_nf], vf_i_fnts[lf], e);
+ incr(vf_nf);
+ end;
+ vf_packet_base[f] := vf_packet_base[bf];
+ vf_local_font_num[f] := vf_local_font_num[bf];
+ vf_default_font[f] := vf_nf - vf_local_font_num[f];
+
+ pdf_font_type[f] := virtual_font_type;
+ auto_expand_vf := true;
+end;
+
+function fix_expand_value(f: internal_font_number; e: integer): integer;
+{return the multiple of |pdf_font_step[f]| that is nearest to |e|}
+var step: integer;
+ max_expand: integer;
+ neg: boolean;
+begin
+ fix_expand_value := 0;
+ if e = 0 then
+ return;
+ if e < 0 then begin
+ e := -e;
+ neg := true;
+ max_expand := -pdf_font_expand_ratio[pdf_font_shrink[f]];
+ end
+ else begin
+ neg := false;
+ max_expand := pdf_font_expand_ratio[pdf_font_stretch[f]];
+ end;
+ if e > max_expand then
+ e := max_expand
+ else begin
+ step := pdf_font_step[f];
+ if e mod step > 0 then
+ e := step*round_xn_over_d(e, 1, step);
+ end;
+ if neg then
+ e := -e;
+ fix_expand_value := e;
+end;
+
+function get_expand_font(f: internal_font_number; e: integer): internal_font_number;
+{look up and create if not found an expanded version of |f|; |f| is an
+expandable font; |e| is nonzero and is a multiple of |pdf_font_step[f]|}
+var k: internal_font_number;
+begin
+ k := pdf_font_elink[f];
+ while k <> null_font do begin
+ if pdf_font_expand_ratio[k] = e then begin
+ get_expand_font := k;
+ return;
+ end;
+ k := pdf_font_elink[k];
+ end;
+ k := load_expand_font(f, e);
+ pdf_font_elink[k] := pdf_font_elink[f];
+ pdf_font_elink[f] := k;
+ get_expand_font := k;
+end;
+
+function expand_font(f: internal_font_number; e: integer): internal_font_number;
+{looks up for font |f| expanded by |e| thousandths, |e| is an arbitrary value
+between max stretch and max shrink of |f|; if not found then creates it}
+var max_expand: integer;
+begin
+ expand_font := f;
+ if e = 0 then
+ return;
+ e := fix_expand_value(f, e);
+ if e = 0 then
+ return;
+ if pdf_font_elink[f] = null_font then
+ pdf_error("font expansion", "uninitialized pdf_font_elink");
+ expand_font := get_expand_font(f, e);
+end;
+
+procedure read_expand_font; {read font expansion spec and load expanded font}
+var font_shrink, font_stretch, font_step: integer;
+ f: internal_font_number;
+ auto_expand: boolean;
+begin
+ {read font expansion parameters}
+ scan_font_ident;
+ f := cur_val;
+ if f = null_font then
+ pdf_error("font expansion", "invalid font identifier");
+ scan_optional_equals;
+ scan_int;
+ font_stretch := fix_int(cur_val, 0, 1000);
+ scan_int;
+ font_shrink := fix_int(cur_val, 0, 1000);
+ scan_int;
+ font_step := fix_int(cur_val, 0, 1000);
+ if font_step = 0 then
+ pdf_error("font expansion", "invalid step");
+ font_stretch := font_stretch - font_stretch mod font_step;
+ if font_stretch < 0 then
+ font_stretch := 0;
+ font_shrink := font_shrink - font_shrink mod font_step;
+ if font_shrink < 0 then
+ font_shrink := 0;
+ if font_shrink = 1000 then
+ font_shrink := font_shrink - font_step; {don't allow zero-width font}
+ if (font_stretch = 0) and (font_shrink = 0) then
+ pdf_error("font expansion", "invalid limit");
+ auto_expand := false;
+ if scan_keyword("autoexpand") then begin
+ auto_expand := true;
+ @<Scan an optional space@>; end;
+
+ {check if the font can be expanded}
+ if (pdf_font_expand_ratio[f] <> 0) then
+ pdf_error("font expansion", "this font has been expanded by another font so it cannot be used now");
+ if (pdf_font_step[f] <> 0) then
+ {this font has been expanded, ensure the expansion parameters are identical}
+ begin
+ if (pdf_font_step[f] <> font_step) or
+ ((pdf_font_stretch[f] = null_font) and (font_stretch <> 0)) or
+ ((pdf_font_stretch[f] <> null_font) and
+ (pdf_font_expand_ratio[pdf_font_stretch[f]] <> font_stretch)) or
+ ((pdf_font_shrink[f] = null_font) and (font_shrink <> 0)) or
+ ((pdf_font_shrink[f] <> null_font) and
+ (pdf_font_expand_ratio[pdf_font_shrink[f]] <> -font_shrink)) or
+ (pdf_font_auto_expand[f] <> auto_expand)
+ then
+ pdf_error("font expansion", "font has been expanded with different parameters");
+ end
+ else begin
+ pdf_font_step[f] := font_step;
+ pdf_font_auto_expand[f] := auto_expand;
+ if font_stretch > 0 then
+ pdf_font_stretch[f] := get_expand_font(f, font_stretch);
+ if font_shrink > 0 then
+ pdf_font_shrink[f] := get_expand_font(f, -font_shrink);
+ end;
+end;
+@z
+
+@x [32f] - margin kerning
+glue_node: @<(\pdfTeX) Move right or output leaders@>;
+@y
+glue_node: @<(\pdfTeX) Move right or output leaders@>;
+margin_kern_node,
+@z
+
+@x [649] - font expansion
+@ Here now is |hpack|, which contains few if any surprises.
+
+@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer;
+@y
+@ @<Glob...@>=
+@!pdf_font_blink: ^internal_font_number; {link to base font (used for expanded fonts only)}
+@!pdf_font_elink: ^internal_font_number; {link to expanded fonts (used for base fonts only)}
+@!pdf_font_stretch: ^integer; {limit of stretching}
+@!pdf_font_shrink: ^integer; {limit of shrinking}
+@!pdf_font_step: ^integer; {amount of one step of expansion}
+@!pdf_font_expand_ratio: ^integer; {expansion ratio of a particular font}
+@!pdf_font_auto_expand: ^boolean; {this font is auto-expanded?}
+@!pdf_font_lp_base: ^integer; {base of left-protruding factor}
+@!pdf_font_rp_base: ^integer; {base of right-protruding factor}
+@!pdf_font_ef_base: ^integer; {base of font expansion factor}
+@!font_expand_ratio: integer; {current expansion ratio}
+@!last_leftmost_char: pointer;
+@!last_rightmost_char: pointer;
+@!hlist_stack:array[0..max_hlist_stack] of pointer; {stack for |find_protchar_left()| and |find_protchar_right()|}
+@!hlist_stack_level:0..max_hlist_stack; {fill level for |hlist_stack|}
+
+@ @d cal_margin_kern_var(#) ==
+begin
+ character(cp) := character(#);
+ font(cp) := font(#);
+ do_subst_font(cp, 1000);
+ if font(cp) <> font(#) then
+ margin_kern_stretch := margin_kern_stretch + left_pw(#) - left_pw(cp);
+ font(cp) := font(#);
+ do_subst_font(cp, -1000);
+ if font(cp) <> font(#) then
+ margin_kern_shrink := margin_kern_shrink + left_pw(cp) - left_pw(#);
+end
+
+@<Calculate variations of marginal kerns@>=
+begin
+ lp := last_leftmost_char;
+ rp := last_rightmost_char;
+ fast_get_avail(cp);
+ if lp <> null then
+ cal_margin_kern_var(lp);
+ if rp <> null then
+ cal_margin_kern_var(rp);
+ free_avail(cp);
+end
+
+@ Here is |hpack|, which is place where we do font substituting when
+font expansion is being used. We define some constants used when calling
+|hpack| to deal with font expansion.
+
+@d cal_expand_ratio == 2 {calculate amount for font expansion after breaking
+ paragraph into lines}
+@d subst_ex_font == 3 {substitute fonts}
+
+@d substituted = 3 {|subtype| of kern nodes that should be substituted}
+
+@d left_pw(#) == char_pw(#, left_side)
+@d right_pw(#) == char_pw(#, right_side)
+
+@p
+function check_expand_pars(f: internal_font_number): boolean;
+var k: internal_font_number;
+begin
+ check_expand_pars := false;
+ if (pdf_font_step[f] = 0) or ((pdf_font_stretch[f] = null_font) and
+ (pdf_font_shrink[f] = null_font)) then
+ return;
+ if cur_font_step < 0 then
+ cur_font_step := pdf_font_step[f]
+ else if cur_font_step <> pdf_font_step[f] then
+ pdf_error("font expansion", "using fonts with different step of expansion in one paragraph is not allowed");
+ k := pdf_font_stretch[f];
+ if k <> null_font then begin
+ if max_stretch_ratio < 0 then
+ max_stretch_ratio := pdf_font_expand_ratio[k]
+ else if max_stretch_ratio <> pdf_font_expand_ratio[k] then
+ pdf_error("font expansion", "using fonts with different limit of expansion in one paragraph is not allowed");
+ end;
+ k := pdf_font_shrink[f];
+ if k <> null_font then begin
+ if max_shrink_ratio < 0 then
+ max_shrink_ratio := pdf_font_expand_ratio[k]
+ else if max_shrink_ratio <> pdf_font_expand_ratio[k] then
+ pdf_error("font expansion", "using fonts with different limit of expansion in one paragraph is not allowed");
+ end;
+ check_expand_pars := true;
+end;
+
+function char_stretch(f: internal_font_number; c: eight_bits): scaled;
+var k: internal_font_number;
+ dw: scaled;
+ ef: integer;
+begin
+ char_stretch := 0;
+ k := pdf_font_stretch[f];
+ ef := get_ef_code(f, c);
+ if (k <> null_font) and (ef > 0) then begin
+ dw := char_width(k)(char_info(k)(c)) - char_width(f)(char_info(f)(c));
+ if dw > 0 then
+ char_stretch := round_xn_over_d(dw, ef, 1000);
+ end;
+end;
+
+function char_shrink(f: internal_font_number; c: eight_bits): scaled;
+var k: internal_font_number;
+ dw: scaled;
+ ef: integer;
+begin
+ char_shrink := 0;
+ k := pdf_font_shrink[f];
+ ef := get_ef_code(f, c);
+ if (k <> null_font) and (ef > 0) then begin
+ dw := char_width(f)(char_info(f)(c)) - char_width(k)(char_info(k)(c));
+ if dw > 0 then
+ char_shrink := round_xn_over_d(dw, ef, 1000);
+ end;
+end;
+
+function get_kern(f: internal_font_number; lc, rc: eight_bits): scaled;
+label continue;
+var i: four_quarters;
+ j: four_quarters;
+ k: font_index;
+ p: pointer;
+ s: integer;
+begin
+ get_kern := 0;
+ i := char_info(f)(lc);
+ if char_tag(i) <> lig_tag then
+ return;
+ k := lig_kern_start(f)(i);
+ j := font_info[k].qqqq;
+ if skip_byte(j) <= stop_flag then
+ goto continue + 1;
+ k := lig_kern_restart(f)(j);
+continue:
+ j := font_info[k].qqqq;
+continue + 1:
+ if (next_char(j) = rc) and (skip_byte(j) <= stop_flag) and
+ (op_byte(j) >= kern_flag)
+ then begin
+ get_kern := char_kern(f)(j);
+ return;
+ end;
+ if skip_byte(j) = qi(0) then
+ incr(k)
+ else begin
+ if skip_byte(j) >= stop_flag then
+ return;
+ k := k + qo(skip_byte(j)) + 1;
+ end;
+ goto continue;
+end;
+
+function kern_stretch(p: pointer): scaled;
+var l, r: pointer;
+ d: scaled;
+begin
+ kern_stretch := 0;
+ if (prev_char_p = null) or (link(prev_char_p) <> p) or (link(p) = null)
+ then
+ return;
+ l := prev_char_p;
+ r := link(p);
+ if type(l) = ligature_node then
+ l := lig_char(l);
+ if type(r) = ligature_node then
+ r := lig_char(r);
+ if not (is_char_node(l) and is_char_node(r) and
+ (font(l) = font(r)) and
+ (pdf_font_stretch[font(l)] <> null_font))
+ then
+ return;
+ d := get_kern(pdf_font_stretch[font(l)], character(l), character(r));
+ kern_stretch := round_xn_over_d(d - width(p),
+ get_ef_code(font(l), character(l)), 1000);
+end;
+
+function kern_shrink(p: pointer): scaled;
+var l, r: pointer;
+ d: scaled;
+begin
+ kern_shrink := 0;
+ if (prev_char_p = null) or (link(prev_char_p) <> p) or (link(p) = null)
+ then
+ return;
+ l := prev_char_p;
+ r := link(p);
+ if type(l) = ligature_node then
+ l := lig_char(l);
+ if type(r) = ligature_node then
+ r := lig_char(r);
+ if not (is_char_node(l) and is_char_node(r) and
+ (font(l) = font(r)) and
+ (pdf_font_shrink[font(l)] <> null_font))
+ then
+ return;
+ d := get_kern(pdf_font_shrink[font(l)], character(l), character(r));
+ kern_shrink := round_xn_over_d(width(p) - d,
+ get_ef_code(font(l), character(l)), 1000);
+end;
+
+procedure do_subst_font(p: pointer; ex_ratio: integer);
+var f, k: internal_font_number;
+ r: pointer;
+ ef: integer;
+begin
+ if not is_char_node(p) and (type(p) = disc_node) then begin
+ r := pre_break(p);
+ while r <> null do begin
+ if is_char_node(r) or (type(r) = ligature_node) then
+ do_subst_font(r, ex_ratio);
+ r := link(r);
+ end;
+ r := post_break(p);
+ while r <> null do begin
+ if is_char_node(r) or (type(r) = ligature_node) then
+ do_subst_font(r, ex_ratio);
+ r := link(r);
+ end;
+ return;
+ end;
+ if is_char_node(p) then
+ r := p
+ else if type(p) = ligature_node then
+ r := lig_char(p)
+ else begin
+ {|short_display_n(p, 5);|}
+ pdf_error("font expansion", "invalid node type");
+ end;
+ f := font(r);
+ ef := get_ef_code(f, character(r));
+ if ef = 0 then
+ return;
+ if (pdf_font_stretch[f] <> null_font) and (ex_ratio > 0) then
+ k := expand_font(f, divide_scaled(ex_ratio*
+ pdf_font_expand_ratio[pdf_font_stretch[f]]*ef,
+ 1000000, 0))
+ else if (pdf_font_shrink[f] <> null_font) and (ex_ratio < 0) then
+ k := expand_font(f, -divide_scaled(ex_ratio*
+ pdf_font_expand_ratio[pdf_font_shrink[f]]*ef,
+ 1000000, 0))
+ else
+ k := f;
+ if k <> f then begin
+ font(r) := k;
+ if not is_char_node(p) then begin
+ r := lig_ptr(p);
+ while r <> null do begin
+ font(r) := k;
+ r := link(r);
+ end;
+ end;
+ end;
+end;
+
+function char_pw(p: pointer; side: small_number): scaled;
+var f: internal_font_number;
+ c: integer;
+begin
+ char_pw := 0;
+ if side = left_side then
+ last_leftmost_char := null
+ else
+ last_rightmost_char := null;
+ if p = null then
+ return;
+ if not is_char_node(p) then begin
+ if type(p) = ligature_node then
+ p := lig_char(p)
+ else
+ return;
+ end;
+ f := font(p);
+ if side = left_side then begin
+ c := get_lp_code(f, character(p));
+ last_leftmost_char := p;
+ end
+ else begin
+ c := get_rp_code(f, character(p));
+ last_rightmost_char := p;
+ end;
+ if c = 0 then
+ return;
+ char_pw :=
+ round_xn_over_d(quad(f), c, 1000);
+end;
+
+function new_margin_kern(w: scaled; p: pointer; side: small_number): pointer;
+var k: pointer;
+begin
+ k := get_node(margin_kern_node_size);
+ type(k) := margin_kern_node;
+ subtype(k) := side;
+ width(k) := w;
+ if p = null then
+ pdf_error("margin kerning", "invalid pointer to marginal char node");
+ fast_get_avail(margin_char(k));
+ character(margin_char(k)) := character(p);
+ font(margin_char(k)) := font(p);
+ new_margin_kern := k;
+end;
+
+function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer;
+@z
+
+@x [649] - font expansion
+begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node;
+subtype(r):=min_quarterword; shift_amount(r):=0;
+q:=r+list_offset; link(q):=p;@/
+@y
+font_stretch: scaled;
+font_shrink: scaled;
+k: scaled;
+begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node;
+subtype(r):=min_quarterword; shift_amount(r):=0;
+q:=r+list_offset; link(q):=p;@/
+if m = cal_expand_ratio then begin
+ prev_char_p := null;
+ font_stretch := 0;
+ font_shrink := 0;
+ font_expand_ratio := 0;
+end;
+@z
+
+@x [649] - font expansion
+hpack:=r;
+@y
+if (m = cal_expand_ratio) and (font_expand_ratio <> 0) then begin
+ font_expand_ratio := fix_int(font_expand_ratio, -1000, 1000);
+ q := list_ptr(r);
+ free_node(r, box_node_size);
+ r := hpack(q, w, subst_ex_font);
+end;
+hpack:=r;
+@z
+
+@x [651] - font expansion
+ kern_node: x:=x+width(p);
+@y
+ margin_kern_node: begin
+ if m = cal_expand_ratio then begin
+ f := font(margin_char(p));
+ do_subst_font(margin_char(p), 1000);
+ if f <> font(margin_char(p)) then
+ font_stretch := font_stretch - width(p) -
+ char_pw(margin_char(p), subtype(p));
+ font(margin_char(p)) := f;
+ do_subst_font(margin_char(p), -1000);
+ if f <> font(margin_char(p)) then
+ font_shrink := font_shrink - width(p) -
+ char_pw(margin_char(p), subtype(p));
+ font(margin_char(p)) := f;
+ end
+ else if m = subst_ex_font then begin
+ do_subst_font(margin_char(p), font_expand_ratio);
+ width(p) := -char_pw(margin_char(p), subtype(p));
+ end;
+ x := x + width(p);
+ end;
+ kern_node: begin
+ if (m = cal_expand_ratio) and (subtype(p) = normal) then begin
+ k := kern_stretch(p);
+ if k <> 0 then begin
+ subtype(p) := substituted;
+ font_stretch := font_stretch + k;
+ end;
+ k := kern_shrink(p);
+ if k <> 0 then begin
+ subtype(p) := substituted;
+ font_shrink := font_shrink + k;
+ end;
+ end
+ else if (m = subst_ex_font) and (subtype(p) = substituted) then begin
+ if type(link(p)) = ligature_node then
+ width(p) := get_kern(font(prev_char_p),
+ character(prev_char_p),
+ character(lig_char(link(p))))
+ else
+ width(p) := get_kern(font(prev_char_p),
+ character(prev_char_p),
+ character(link(p)))
+ end;
+ x := x + width(p);
+ end;
+@z
+
+@x [651] - font expansion
+ ligature_node: @<Make node |p| look like a |char_node|
+ and |goto reswitch|@>;
+@y
+ ligature_node: begin
+ if m = subst_ex_font then
+ do_subst_font(p, font_expand_ratio);
+ @<Make node |p| look like a |char_node| and |goto reswitch|@>;
+ end;
+ disc_node:
+ if m = subst_ex_font then
+ do_subst_font(p, font_expand_ratio);
+@z
+
+@x [654] - font expansion
+begin f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i);
+@y
+begin
+if m >= cal_expand_ratio then begin
+ prev_char_p := p;
+ case m of
+ cal_expand_ratio: begin
+ f := font(p);
+ add_char_stretch(font_stretch)(character(p));
+ add_char_shrink(font_shrink)(character(p));
+ end;
+ subst_ex_font:
+ do_subst_font(p, font_expand_ratio);
+ endcases;
+end;
+f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i);
+@z
+
+@x [658] - font expansion
+@ @<Determine horizontal glue stretch setting...@>=
+begin @<Determine the stretch order@>;
+@y
+@ If |hpack| is called with |m=cal_expand_ratio| we calculate
+|font_expand_ratio| and return without checking for overfull or underfull box.
+
+@<Determine horizontal glue stretch setting...@>=
+begin @<Determine the stretch order@>;
+if (m = cal_expand_ratio) and (o = normal) and (font_stretch > 0) then begin
+ font_expand_ratio := divide_scaled(x, font_stretch, 3);
+ return;
+end;
+@z
+
+@x [664] - font expansion
+@ @<Determine horizontal glue shrink setting...@>=
+begin @<Determine the shrink order@>;
+@y
+@ @<Determine horizontal glue shrink setting...@>=
+begin @<Determine the shrink order@>;
+if (m = cal_expand_ratio) and (o = normal) and (font_shrink > 0) then begin
+ font_expand_ratio := divide_scaled(x, font_shrink, 3);
+ return;
+end;
+@z
+
+@x [822] - font expansion
+@d delta_node_size=7 {number of words in a delta node}
+@y
+@d delta_node_size=9 {number of words in a delta node}
+@z
+
+@x [823] - font expansion, margin kerning, avoiding overfull boxes
+@<Glo...@>=
+@!active_width:array[1..6] of scaled;
+ {distance from first active node to~|cur_p|}
+@!cur_active_width:array[1..6] of scaled; {distance from current active node}
+@!background:array[1..6] of scaled; {length of an ``empty'' line}
+@!break_width:array[1..6] of scaled; {length being computed after current break}
+@y
+@d do_seven_eight(#) == if pdf_adjust_spacing > 1 then begin #(7);#(8); end
+@d do_all_eight(#) == do_all_six(#); do_seven_eight(#)
+@d do_one_seven_eight(#) == #(1); do_seven_eight(#)
+
+@d total_font_stretch == cur_active_width[7]
+@d total_font_shrink == cur_active_width[8]
+
+@d save_active_width(#) == prev_active_width[#] := active_width[#]
+@d restore_active_width(#) == active_width[#] := prev_active_width[#]
+
+@<Glo...@>=
+@!active_width:array[1..8] of scaled;
+ {distance from first active node to~|cur_p|}
+@!cur_active_width:array[1..8] of scaled; {distance from current active node}
+@!background:array[1..8] of scaled; {length of an ``empty'' line}
+@!break_width:array[1..8] of scaled; {length being computed after current break}
+@#
+@!auto_breaking: boolean; {make |auto_breaking| accessible out of |line_break|}
+@!prev_p: pointer; {make |prev_p| accessible out of |line_break|}
+@!first_p: pointer; {to access the first node of the paragraph}
+@!prev_char_p: pointer; {pointer to the previous char of an implicit kern}
+@!next_char_p: pointer; {pointer to the next char of an implicit kern}
+@#
+@!try_prev_break: boolean; {force break at the previous legal breakpoint?}
+@!prev_legal: pointer; {the previous legal breakpoint}
+@!prev_prev_legal: pointer; {to save |prev_p| corresponding to |prev_legal|}
+@!prev_auto_breaking: boolean; {to save |auto_breaking| corresponding to |prev_legal|}
+@!prev_active_width: array[1..8] of scaled; {to save |active_width| corresponding to |prev_legal|}
+@!rejected_cur_p: pointer; {the last |cur_p| that has been rejected}
+@!before_rejected_cur_p: boolean; {|cur_p| is still before |rejected_cur_p|?}
+@#
+@!max_stretch_ratio: integer; {maximal stretch ratio of expanded fonts}
+@!max_shrink_ratio: integer; {maximal shrink ratio of expanded fonts}
+@!cur_font_step: integer; {the current step of expanded fonts}
+@z
+
+@x [827] - font expansion
+background[6]:=shrink(q)+shrink(r);
+@y
+background[6]:=shrink(q)+shrink(r);
+if pdf_adjust_spacing > 1 then begin
+ background[7] := 0;
+ background[8] := 0;
+ max_stretch_ratio := -1;
+ max_shrink_ratio := -1;
+ cur_font_step := -1;
+ prev_char_p := null;
+end;
+@z
+
+@x [829] - margin kerning
+@<Declare subprocedures for |line_break|@>=
+procedure try_break(@!pi:integer;@!break_type:small_number);
+@y
+@d cp_skipable(#) == {skipable nodes at the margins during character protrusion}
+(
+ not is_char_node(#) and
+ (
+ (type(#) = ins_node)
+ or (type(#) = mark_node)
+ or (type(#) = adjust_node)
+ or (type(#) = penalty_node)
+ or ((type(#) = whatsit_node) and
+ (subtype(#) <> pdf_refximage_node) and
+ (subtype(#) <> pdf_refxform_node)) {reference to an image or XObject form}
+ or ((type(#) = disc_node) and
+ (pre_break(#) = null) and
+ (post_break(#) = null) and
+ (replace_count(#) = 0)) {an empty |disc_node|}
+ or ((type(#) = math_node) and (width(#) = 0))
+ or ((type(#) = kern_node) and
+ ((width(#) = 0) or (subtype(#) = normal)))
+ or ((type(#) = glue_node) and (glue_ptr(#) = zero_glue))
+ or ((type(#) = hlist_node) and (width(#) = 0) and (height(#) = 0) and
+ (depth(#) = 0) and (list_ptr(#) = null))
+ )
+)
+
+
+@<Declare subprocedures for |line_break|@>=
+procedure push_node(p: pointer);
+begin
+ if hlist_stack_level > max_hlist_stack then
+ pdf_error("push_node", "stack overflow");
+ hlist_stack[hlist_stack_level] := p;
+ hlist_stack_level := hlist_stack_level + 1;
+end;
+
+function pop_node: pointer;
+begin
+ hlist_stack_level := hlist_stack_level - 1;
+ if hlist_stack_level < 0 then {would point to some bug}
+ pdf_error("pop_node", "stack underflow (internal error)");
+ pop_node := hlist_stack[hlist_stack_level];
+end;
+
+function find_protchar_left(l: pointer; d: boolean): pointer;
+{searches left to right from list head |l|, returns 1st non-skipable item}
+var t: pointer;
+ run: boolean;
+begin
+ if (link(l) <> null) and (type(l) = hlist_node) and (width(l) = 0)
+ and (height(l) = 0) and (depth(l) = 0) and (list_ptr(l) = null) then
+ l := link(l) {for paragraph start with \.{\\parindent = 0pt}}
+ else if d then
+ while (link(l) <> null) and (not (is_char_node(l) or non_discardable(l))) do
+ l := link(l); {std.\ discardables at line break, \TeX book, p 95}
+ hlist_stack_level := 0;
+ run := true;
+ repeat
+ t := l;
+ while run and (type(l) = hlist_node) and (list_ptr(l) <> null) do begin
+ push_node(l);
+ l := list_ptr(l);
+ end;
+ while run and cp_skipable(l) do begin
+ while (link(l) = null) and (hlist_stack_level > 0) do begin
+ l := pop_node; {don't visit this node again}
+ end;
+ if link(l) <> null then
+ l := link(l)
+ else if hlist_stack_level = 0 then run := false
+ end;
+ until t = l;
+ find_protchar_left := l;
+end;
+
+function find_protchar_right(l, r: pointer): pointer;
+{searches right to left from list tail |r| to head |l|, returns 1st non-skipable item}
+var t: pointer;
+ run: boolean;
+begin
+ find_protchar_right := null;
+ if r = null then return;
+ hlist_stack_level := 0;
+ run := true;
+ repeat
+ t := r;
+ while run and (type(r) = hlist_node) and (list_ptr(r) <> null) do begin
+ push_node(l);
+ push_node(r);
+ l := list_ptr(r);
+ r := l;
+ while link(r) <> null do
+ r := link(r);
+ end;
+ while run and cp_skipable(r) do begin
+ while (r = l) and (hlist_stack_level > 0) do begin
+ r := pop_node; {don't visit this node again}
+ l := pop_node;
+ end;
+ if (r <> l) and (r <> null) then
+ r := prev_rightmost(l, r)
+ else if (r = l) and (hlist_stack_level = 0) then run := false
+ end;
+ until t = r;
+ find_protchar_right := r;
+end;
+
+function total_pw(q, p: pointer): scaled;
+{returns the total width of character protrusion of a line;
+|cur_break(break_node(q))| and |p| is the leftmost resp. rightmost node in the
+horizontal list representing the actual line}
+var l, r, s: pointer;
+ n: integer;
+begin
+ if break_node(q) = null then
+ l := first_p
+ else
+ l := cur_break(break_node(q));
+ r := prev_rightmost(prev_p, p); {get |link(r)=p|}
+ {let's look at the right margin first}
+ {|
+ short_display_n(r, 2);
+ print("&");
+ short_display_n(p, 2);
+ print_ln;
+ |}
+ if (p <> null) and (type(p) = disc_node) and (pre_break(p) <> null) then
+ {a |disc_node| with non-empty |pre_break|, protrude the last char of |pre_break|}
+ begin
+ r := pre_break(p);
+ while link(r) <> null do
+ r := link(r);
+ end else r := find_protchar_right(l, r);
+ {now the left margin}
+ {|
+ short_display_n(l, 2);
+ print_ln;
+ breadth_max := 10;
+ depth_threshold := 2;
+ show_node_list(l);
+ print_ln;
+ |}
+ if (l <> null) and (type(l) = disc_node) then begin
+ if post_break(l) <> null then begin
+ l := post_break(l); {protrude the first char}
+ goto done;
+ end else {discard |replace_count(l)| nodes}
+ begin
+ n := replace_count(l);
+ l := link(l);
+ while n > 0 do begin
+ if link(l) <> null then
+ l := link(l);
+ decr(n);
+ end;
+ end;
+ end;
+ l := find_protchar_left(l, true);
+done:
+ total_pw := left_pw(l) + right_pw(r);
+end;
+
+procedure try_break(@!pi:integer;@!break_type:small_number);
+@z
+
+@x
+var r:pointer; {runs through the active list}
+@y
+var r:pointer; {runs through the active list}
+@!margin_kern_stretch: scaled;
+@!margin_kern_shrink: scaled;
+@!lp, rp, cp: pointer;
+@z
+
+
+@x [829] - font expansion
+do_all_six(copy_to_cur_active);
+@y
+do_all_eight(copy_to_cur_active);
+@z
+
+@x [832] - font expansion
+ begin do_all_six(update_width);
+@y
+ begin do_all_eight(update_width);
+@z
+
+@x [837] - font expansion
+begin no_break_yet:=false; do_all_six(set_break_width_to_background);
+@y
+begin no_break_yet:=false; do_all_eight(set_break_width_to_background);
+@z
+
+@x [839] - font expansion
+@<Glob...@>=
+@!disc_width:scaled; {the length of discretionary material preceding a break}
+@y
+@d reset_disc_width(#) == disc_width[#] := 0
+
+@d add_disc_width_to_break_width(#) ==
+ break_width[#] := break_width[#] + disc_width[#]
+
+@d add_disc_width_to_active_width(#) ==
+ active_width[#] := active_width[#] + disc_width[#]
+
+@d sub_disc_width_from_active_width(#) ==
+ active_width[#] := active_width[#] - disc_width[#]
+
+@d add_char_stretch_end(#) == char_stretch(f, #)
+@d add_char_stretch(#) == # := # + add_char_stretch_end
+
+@d add_char_shrink_end(#) == char_shrink(f, #)
+@d add_char_shrink(#) == # := # + add_char_shrink_end
+
+@d sub_char_stretch_end(#) == char_stretch(f, #)
+@d sub_char_stretch(#) == # := # - sub_char_stretch_end
+
+@d sub_char_shrink_end(#) == char_shrink(f, #)
+@d sub_char_shrink(#) == # := # - sub_char_shrink_end
+
+@d add_kern_stretch_end(#) == kern_stretch(#)
+@d add_kern_stretch(#) == # := # + add_kern_stretch_end
+
+@d add_kern_shrink_end(#) == kern_shrink(#)
+@d add_kern_shrink(#) == # := # + add_kern_shrink_end
+
+@d sub_kern_stretch_end(#) == kern_stretch(#)
+@d sub_kern_stretch(#) == # := # - sub_kern_stretch_end
+
+@d sub_kern_shrink_end(#) == kern_shrink(#)
+@d sub_kern_shrink(#) == # := # - sub_kern_shrink_end
+
+@<Glob...@>=
+@!disc_width: array[1..8] of scaled; {the length of discretionary material preceding a break}
+@z
+
+@x [840] - font expansion
+break_width[1]:=break_width[1]+disc_width;
+@y
+do_one_seven_eight(add_disc_width_to_break_width);
+@z
+
+@x [841] - font expansion
+ break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v)));
+@y
+ break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v)));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := v;
+ sub_char_stretch(break_width[7])(character(v));
+ sub_char_shrink(break_width[8])(character(v));
+ end;
+@z
+
+@x [841] - font expansion
+ break_width[1]:=@|break_width[1]-
+ char_width(f)(char_info(f)(character(lig_char(v))));
+@y
+ break_width[1]:=@|break_width[1]-
+ char_width(f)(char_info(f)(character(lig_char(v))));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := v;
+ sub_char_stretch(break_width[7])(character(lig_char(v)));
+ sub_char_shrink(break_width[8])(character(lig_char(v)));
+ end;
+@z
+
+@x [841] - font expansion
+ hlist_node,vlist_node,rule_node,kern_node:
+ break_width[1]:=break_width[1]-width(v);
+@y
+ hlist_node,vlist_node,rule_node,kern_node: begin
+ break_width[1]:=break_width[1]-width(v);
+ if (type(v) = kern_node) and
+ (pdf_adjust_spacing > 1) and (subtype(v) = normal)
+ then begin
+ sub_kern_stretch(break_width[7])(v);
+ sub_kern_shrink(break_width[8])(v);
+ end;
+ end;
+@z
+
+@x [842] - font expansion
+ break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
+@y
+ break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := s;
+ add_char_stretch(break_width[7])(character(s));
+ add_char_shrink(break_width[8])(character(s));
+ end;
+@z
+
+@x [842] - font expansion
+ break_width[1]:=break_width[1]+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+@y
+ break_width[1]:=break_width[1]+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := s;
+ add_char_stretch(break_width[7])(character(lig_char(s)));
+ add_char_shrink(break_width[8])(character(lig_char(s)));
+ end;
+@z
+
+@x [842] - font expansion
+ hlist_node,vlist_node,rule_node,kern_node:
+ break_width[1]:=break_width[1]+width(s);
+@y
+ hlist_node,vlist_node,rule_node,kern_node: begin
+ break_width[1]:=break_width[1]+width(s);
+ if (type(s) = kern_node) and
+ (pdf_adjust_spacing > 1) and (subtype(s) = normal)
+ then begin
+ add_kern_stretch(break_width[7])(s);
+ add_kern_shrink(break_width[8])(s);
+ end;
+ end;
+@z
+
+@x [843] - font expansion
+ begin do_all_six(convert_to_break_width);
+@y
+ begin do_all_eight(convert_to_break_width);
+@z
+
+@x [843] - font expansion
+ begin do_all_six(store_break_width);
+@y
+ begin do_all_eight(store_break_width);
+@z
+
+@x [843] - font expansion
+ do_all_six(new_delta_to_break_width);
+@y
+ do_all_eight(new_delta_to_break_width);
+@z
+
+@x [844] - font expansion
+ do_all_six(new_delta_from_break_width);
+@y
+ do_all_eight(new_delta_from_break_width);
+@z
+
+@x [851] - font expansion, margin kerning
+shortfall:=line_width-cur_active_width[1]; {we're this much too short}
+@y
+shortfall:=line_width-cur_active_width[1]; {we're this much too short}
+
+{|
+if pdf_output > 2 then begin
+print_ln;
+if (r <> null) and (break_node(r) <> null) then
+ short_display_n(cur_break(break_node(r)), 5);
+print_ln;
+short_display_n(cur_p, 5);
+print_ln;
+end;
+|}
+
+if pdf_protrude_chars > 1 then
+ shortfall := shortfall + total_pw(r, cur_p);
+if (pdf_adjust_spacing > 1) and (shortfall <> 0) then begin
+ margin_kern_stretch := 0;
+ margin_kern_shrink := 0;
+ if pdf_protrude_chars > 1 then
+ @<Calculate variations of marginal kerns@>;
+ if (shortfall > 0) and ((total_font_stretch + margin_kern_stretch) > 0)
+ then begin
+ if (total_font_stretch + margin_kern_stretch) > shortfall then
+ shortfall := ((total_font_stretch + margin_kern_stretch) div
+ (max_stretch_ratio div cur_font_step)) div 2
+ else
+ shortfall := shortfall - (total_font_stretch + margin_kern_stretch);
+ end
+ else if (shortfall < 0) and ((total_font_shrink + margin_kern_shrink) > 0)
+ then begin
+ if (total_font_shrink + margin_kern_shrink) > -shortfall then
+ shortfall := -((total_font_shrink + margin_kern_shrink) div
+ (max_shrink_ratio div cur_font_step)) div 2
+ else
+ shortfall := shortfall + (total_font_shrink + margin_kern_shrink);
+ end;
+end;
+@z
+
+@x [860] - font expansion
+ begin do_all_six(downdate_width);
+@y
+ begin do_all_eight(downdate_width);
+@z
+
+@x [860] - font expansion
+ begin do_all_six(update_width);
+ do_all_six(combine_two_deltas);
+@y
+ begin do_all_eight(update_width);
+ do_all_eight(combine_two_deltas);
+@z
+
+@x [861] - font expansion
+ begin do_all_six(update_active);
+ do_all_six(copy_to_cur_active);
+@y
+ begin do_all_eight(update_active);
+ do_all_eight(copy_to_cur_active);
+@z
+
+@x [862] - margin kerning, avoiding overfull boxes
+@!auto_breaking:boolean; {is node |cur_p| outside a formula?}
+@!prev_p:pointer; {helps to determine when glue nodes are breakpoints}
+@y
+@z
+
+@x [863] - margin kerning, avoiding overfull boxes
+ while (cur_p<>null)and(link(active)<>last_active) do
+@y
+ prev_char_p := null;
+ prev_legal := null;
+ rejected_cur_p := null;
+ try_prev_break := false;
+ before_rejected_cur_p := false;
+ first_p := cur_p; {to access the first node of paragraph as the first active
+ node has |break_node=null|}
+ while (cur_p<>null)and(link(active)<>last_active) do
+@z
+
+@x [864] - font expansion
+do_all_six(store_background);@/
+@y
+do_all_eight(store_background);@/
+@z
+
+@x [666] - font expansion
+ else act_width:=act_width+width(cur_p);
+@y
+ else begin
+ act_width:=act_width+width(cur_p);
+ if (pdf_adjust_spacing > 1) and (subtype(cur_p) = normal) then begin
+ add_kern_stretch(active_width[7])(cur_p);
+ add_kern_shrink(active_width[8])(cur_p);
+ end;
+ end;
+@z
+
+@x [866] - font expansion
+ act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
+@y
+ act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := cur_p;
+ add_char_stretch(active_width[7])(character(lig_char(cur_p)));
+ add_char_shrink(active_width[8])(character(lig_char(cur_p)));
+ end;
+@z
+
+@x [867] - font expansion
+act_width:=act_width+char_width(f)(char_info(f)(character(cur_p)));
+@y
+act_width:=act_width+char_width(f)(char_info(f)(character(cur_p)));
+if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := cur_p;
+ add_char_stretch(active_width[7])(character(cur_p));
+ add_char_shrink(active_width[8])(character(cur_p));
+end;
+@z
+
+@x [869] - font expansion
+begin s:=pre_break(cur_p); disc_width:=0;
+@y
+begin s:=pre_break(cur_p);
+do_one_seven_eight(reset_disc_width);
+@z
+
+@x [869] - font expansion
+ act_width:=act_width+disc_width;
+ try_break(hyphen_penalty,hyphenated);
+ act_width:=act_width-disc_width;
+@y
+ do_one_seven_eight(add_disc_width_to_active_width);
+ try_break(hyphen_penalty,hyphenated);
+ do_one_seven_eight(sub_disc_width_from_active_width);
+@z
+
+@x [870] - font expansion
+ disc_width:=disc_width+char_width(f)(char_info(f)(character(s)));
+@y
+ disc_width[1]:=disc_width[1]+char_width(f)(char_info(f)(character(s)));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := s;
+ add_char_stretch(disc_width[7])(character(s));
+ add_char_shrink(disc_width[8])(character(s));
+ end;
+@z
+
+@x [870] - font expansion
+ disc_width:=disc_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+@y
+ disc_width[1]:=disc_width[1]+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := s;
+ add_char_stretch(disc_width[7])(character(lig_char(s)));
+ add_char_shrink(disc_width[8])(character(lig_char(s)));
+ end;
+@z
+
+@x [870] - font expansion
+ hlist_node,vlist_node,rule_node,kern_node:
+ disc_width:=disc_width+width(s);
+@y
+ hlist_node,vlist_node,rule_node,kern_node: begin
+ disc_width[1]:=disc_width[1]+width(s);
+ if (type(s) = kern_node) and
+ (pdf_adjust_spacing > 1) and (subtype(s) = normal)
+ then begin
+ add_kern_stretch(disc_width[7])(s);
+ add_kern_shrink(disc_width[8])(s);
+ end;
+ end;
+@z
+
+@x [871] - font expansion
+ act_width:=act_width+char_width(f)(char_info(f)(character(s)));
+@y
+ act_width:=act_width+char_width(f)(char_info(f)(character(s)));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := s;
+ add_char_stretch(active_width[7])(character(s));
+ add_char_shrink(active_width[8])(character(s));
+ end;
+@z
+
+@x [871] - font expansion
+ act_width:=act_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+@y
+ act_width:=act_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin
+ prev_char_p := s;
+ add_char_stretch(active_width[7])(character(lig_char(s)));
+ add_char_shrink(active_width[8])(character(lig_char(s)));
+ end;
+@z
+
+@x [871] - font expansion
+ hlist_node,vlist_node,rule_node,kern_node:
+ act_width:=act_width+width(s);
+@y
+ hlist_node,vlist_node,rule_node,kern_node: begin
+ act_width:=act_width+width(s);
+ if (type(s) = kern_node) and
+ (pdf_adjust_spacing > 1) and (subtype(s) = normal)
+ then begin
+ add_kern_stretch(active_width[7])(s);
+ add_kern_shrink(active_width[8])(s);
+ end;
+ end;
+@z
+
+@x [877] - margin kerning
+var q,@!r,@!s:pointer; {temporary registers for list manipulation}
+@y
+var q,@!r,@!s:pointer; {temporary registers for list manipulation}
+ p, k: pointer;
+ w: scaled;
+ glue_break: boolean; {was a break at glue?}
+ ptmp: pointer;
+@z
+
+@x [881] - margin kerning
+q:=cur_break(cur_p); disc_break:=false; post_disc_break:=false;
+@y
+q:=cur_break(cur_p); disc_break:=false; post_disc_break:=false;
+glue_break := false;
+@z
+
+@x [881] - margin kerning
+ subtype(q):=right_skip_code+1; add_glue_ref(right_skip);
+ goto done;
+@y
+ subtype(q):=right_skip_code+1; add_glue_ref(right_skip);
+ glue_break := true;
+ goto done;
+@z
+
+@x [881] - margin kerning
+@<Put the \(r)\.{\\rightskip} glue after node |q|@>;
+done:
+@y
+done:
+
+{at this point |q| is the rightmost breakpoint; the only exception is the case
+of a discretionary break with non-empty |pre_break|, then |q| has been changed
+to the last node of the |pre_break| list}
+
+if pdf_protrude_chars > 0 then begin
+ if disc_break and (is_char_node(q) or (type(q) <> disc_node))
+ {|q| has been reset to the last node of |pre_break|}
+ then begin
+ p := q;
+ ptmp := p;
+ end else begin
+ p := prev_rightmost(temp_head, q); {get |link(p) = q|}
+ ptmp := p;
+ p := find_protchar_right(temp_head, p);
+ end;
+ {|
+ short_display_n(p, 1);
+ print_ln;
+ |}
+ w := right_pw(p);
+ if w <> 0 then {we have found a marginal kern, append it after |ptmp|}
+ begin
+ k := new_margin_kern(-w, last_rightmost_char, right_side);
+ link(k) := link(ptmp);
+ link(ptmp) := k;
+ if (ptmp = q) then
+ q := link(q);
+ end;
+end;
+
+{if |q| was not a breakpoint at glue and has been reset to |rightskip| then
+ we append |rightskip| after |q| now}
+if not glue_break then begin
+ @<Put the \(r)\.{\\rightskip} glue after node |q|@>;
+end;
+@z
+
+@x [887] - margin kerning
+if left_skip<>zero_glue then
+@y
+{at this point |q| is the leftmost node; all discardable nodes have been discarded}
+if pdf_protrude_chars > 0 then begin
+ p := q;
+ p := find_protchar_left(p, false); {no more discardables}
+ w := left_pw(p);
+ if w <> 0 then begin
+ k := new_margin_kern(-w, last_leftmost_char, left_side);
+ link(k) := q;
+ q := k;
+ end;
+end;
+if left_skip<>zero_glue then
+@z
+
+@x [889] - font expansion, pre vadjust
+just_box:=hpack(q,cur_width,exactly);
+@y
+if pdf_adjust_spacing > 0 then
+ just_box := hpack(q, cur_width, cal_expand_ratio)
+else
+ just_box := hpack(q, cur_width, exactly);
+@z
+
+@x [1110] - margin kerning
+var p:pointer; {the box}
+@y
+var p:pointer; {the box}
+ r: pointer; {to remove marginal kern nodes}
+@z
+
+@x [1110] - margin kerning
+while link(tail)<>null do tail:=link(tail);
+@y
+while link(tail) <> null do begin
+ r := link(tail);
+ if not is_char_node(r) and (type(r) = margin_kern_node) then begin
+ link(tail) := link(r);
+ free_avail(margin_char(r));
+ free_node(r, margin_kern_node_size);
+ end;
+ tail:=link(tail);
+end;
+@z
+
+@x [1147] - margin kerning
+ligature_node:@<Make node |p| look like a |char_node|...@>;
+@y
+ligature_node:@<Make node |p| look like a |char_node|...@>;
+margin_kern_node: d:=width(p);
+@z
+
+@x [1253] - font expansion
+assign_font_int: begin n:=cur_chr; scan_font_ident; f:=cur_val;
+ scan_optional_equals; scan_int;
+ if n=0 then hyphen_char[f]:=cur_val@+else skew_char[f]:=cur_val;
+ end;
+@y
+assign_font_int: begin n:=cur_chr; scan_font_ident; f:=cur_val;
+ if n < lp_code_base then begin
+ scan_optional_equals; scan_int;
+ if n=0 then hyphen_char[f]:=cur_val@+else skew_char[f]:=cur_val;
+ end
+ else begin
+ scan_char_num; p := cur_val;
+ scan_optional_equals; scan_int;
+ case n of
+ lp_code_base: set_lp_code(f, p, cur_val);
+ rp_code_base: set_rp_code(f, p, cur_val);
+ ef_code_base: set_ef_code(f, p, cur_val);
+ end;
+ end;
+end;
+@z
+
+@x [1254] - font expansion
+primitive("skewchar",assign_font_int,1);
+@!@:skew_char_}{\.{\\skewchar} primitive@>
+@y
+primitive("skewchar",assign_font_int,1);
+@!@:skew_char_}{\.{\\skewchar} primitive@>
+primitive("lpcode",assign_font_int,lp_code_base);
+@!@:lp_code_}{\.{\\lpcode} primitive@>
+primitive("rpcode",assign_font_int,rp_code_base);
+@!@:rp_code_}{\.{\\rpcode} primitive@>
+primitive("efcode",assign_font_int,ef_code_base);
+@!@:ef_code_}{\.{\\efcode} primitive@>
+@z
+
+@x [1255] - font expansion
+assign_font_int: if chr_code=0 then print_esc("hyphenchar")
+ else print_esc("skewchar");
+@y
+assign_font_int: case chr_code of
+0: print_esc("hyphenchar");
+1: print_esc("skewchar");
+lp_code_base: print_esc("lpcode");
+rp_code_base: print_esc("rpcode");
+ef_code_base: print_esc("efcode");
+endcases;
+@z
+
+@x [1344]
+@d pdftex_last_extension_code == pdftex_first_extension_code + 27
+@y
+@d pdf_font_expand_code == pdftex_first_extension_code + 28
+@d pdftex_last_extension_code == pdftex_first_extension_code + 28
+@z
+
+@x [1344]
+primitive("setlanguage",extension,set_language_code);@/
+@!@:set_language_}{\.{\\setlanguage} primitive@>
+@y
+primitive("setlanguage",extension,set_language_code);@/
+@!@:set_language_}{\.{\\setlanguage} primitive@>
+primitive("pdffontexpand",extension,pdf_font_expand_code);@/
+@!@:pdf_font_expand_}{\.{\\pdffontexpand} primitive@>
+@z
+
+@x [1346]
+ immediate_code:print_esc("immediate");
+ set_language_code:print_esc("setlanguage");
+@y
+ immediate_code:print_esc("immediate");
+ set_language_code:print_esc("setlanguage");
+ pdf_font_expand_code: print_esc("pdffontexpand");
+@z
+
+@x [1348]
+set_language_code:@<Implement \.{\\setlanguage}@>;
+@y
+set_language_code:@<Implement \.{\\setlanguage}@>;
+pdf_font_expand_code: @<Implement \.{\\pdffontexpand}@>;
+@z
+
+@x [1354]
+@<Implement \.{\\special}@>=
+begin new_whatsit(special_node,write_node_size); write_stream(tail):=null;
+p:=scan_toks(false,true); write_tokens(tail):=def_ref;
+end
+@y
+@<Implement \.{\\special}@>=
+begin new_whatsit(special_node,write_node_size); write_stream(tail):=null;
+p:=scan_toks(false,true); write_tokens(tail):=def_ref;
+end
+
+@ @<Implement \.{\\pdffontexpand}@>=
+ read_expand_font
+@z
+
+@x [15??]
+@<Declare procedures that need to be declared forward for pdftex@>=
+@y
+@<Declare procedures that need to be declared forward for pdftex@>=
+function prev_rightmost(s, e: pointer): pointer;
+{finds the node preceding the rightmost node |e|; |s| is some node
+before |e|}
+var p: pointer;
+begin
+ prev_rightmost := null;
+ p := s;
+ if p = null then
+ return;
+ while link(p) <> e do begin
+ p := link(p);
+ if p = null then
+ return;
+ end;
+ prev_rightmost := p;
+end;
+@z
+