diff options
Diffstat (limited to 'Build/source/texk/web2c/pdftexdir/hz.ch')
-rw-r--r-- | Build/source/texk/web2c/pdftexdir/hz.ch | 1935 |
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 + |