From a9d1d6e6aa29a179adcd5f0adf6095086c321d90 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Tue, 22 Jul 2014 01:58:59 +0000 Subject: New RTL extension for XeTeX git-svn-id: svn://tug.org/texlive/trunk@34691 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/texk/web2c/synctexdir/ChangeLog | 6 + Build/source/texk/web2c/synctexdir/am/synctex.am | 3 +- .../texk/web2c/synctexdir/synctex-xe-rec.ch0 | 109 ++ Build/source/texk/web2c/xetexdir/ChangeLog | 7 + Build/source/texk/web2c/xetexdir/tex.ch0 | 2 +- Build/source/texk/web2c/xetexdir/xetex.ch | 2 +- Build/source/texk/web2c/xetexdir/xetex.web | 1259 +++++--------------- 7 files changed, 421 insertions(+), 967 deletions(-) create mode 100644 Build/source/texk/web2c/synctexdir/synctex-xe-rec.ch0 (limited to 'Build/source/texk/web2c') diff --git a/Build/source/texk/web2c/synctexdir/ChangeLog b/Build/source/texk/web2c/synctexdir/ChangeLog index c169e25fcda..3094db84802 100644 --- a/Build/source/texk/web2c/synctexdir/ChangeLog +++ b/Build/source/texk/web2c/synctexdir/ChangeLog @@ -1,3 +1,9 @@ +2014-07-22 Khaled Hosny + + * am/synctex.am: Don't apply synctex-e-mem.ch0 to XeTeX, and replace + synctex-e-rec.ch0 with synctex-xe-rec.ch0, after TeX--XeT removal. + * synctex-xe-rec.ch0: New file (adapted from synctex-e-rec.ch0). + 2014-01-14 Sebastian Ramacher * synctex_main.c: Bug fix (segfault). diff --git a/Build/source/texk/web2c/synctexdir/am/synctex.am b/Build/source/texk/web2c/synctexdir/am/synctex.am index 4a853f5e532..9df0b2ae30e 100644 --- a/Build/source/texk/web2c/synctexdir/am/synctex.am +++ b/Build/source/texk/web2c/synctexdir/am/synctex.am @@ -321,10 +321,9 @@ xetex_CPPFLAGS += -I$(srcdir)/synctexdir xetex_ch_synctex = \ synctexdir/synctex-xe-def.ch0 \ synctexdir/synctex-mem.ch0 \ - synctexdir/synctex-e-mem.ch0 \ synctexdir/synctex-e-mem.ch1 \ synctexdir/synctex-rec.ch0 \ - synctexdir/synctex-e-rec.ch0 + synctexdir/synctex-xe-rec.ch0 xetex_post_ch_synctex = \ synctexdir/synctex-xe-rec.ch3 diff --git a/Build/source/texk/web2c/synctexdir/synctex-xe-rec.ch0 b/Build/source/texk/web2c/synctexdir/synctex-xe-rec.ch0 new file mode 100644 index 00000000000..9cdc845d0ca --- /dev/null +++ b/Build/source/texk/web2c/synctexdir/synctex-xe-rec.ch0 @@ -0,0 +1,109 @@ +Copyright (c) 2008-2011 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +Latest Revision: Wed Jul 1 11:17:29 UTC 2009 + +License: +-------- +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +Acknowledgments: +---------------- +The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh, +and significant help from XeTeX developer Jonathan Kew + +Nota Bene: +---------- +If you include or use a significant part of the synctex package into a software, +I would appreciate to be listed as contributor and see "SyncTeX" highlighted. + +Version 1 +Thu Jun 19 09:39:21 UTC 2008 + +Notice: +------- +Description forthcoming + +@x srcdir/etex.ch l.536 +@/@@/ +othercases print("[unknown integer parameter!]") +@y +@/@@/ +@/@@/ +othercases print("[unknown integer parameter!]") +@z + +@x etex.ch l.1568 +kern_node,math_node:cur_h:=cur_h+width(p); +@y +kern_node: begin + @; + cur_h:=cur_h+width(p); +end; +math_node: begin + @; + cur_h:=cur_h+width(p); +end; +@z + +@x etex.ch l.4459 + name:=19; print("( "); incr(open_parens); update_terminal; + end +else name:=18 +@y + name:=19; print("( "); incr(open_parens); update_terminal; + end +else begin + name:=18; + @; +end +@z + +@x synctex-mem.ch0 l.236 +@ @= +primitive("synctex",assign_int,int_base+synctex_code);@/ +@!@:synctex_}{\.{\\synctex} primitive@> +@y +@ @= +primitive("synctex",assign_int,int_base+synctex_code);@/ +@!@:synctex_}{\.{\\synctex} primitive@> + +@ @= +synctex_code: print_esc("synctex"); +@z + +@x synctex-rec.ch0 l.267 +@ @= +synctex_tag:=0; +@y +@ @= +synctex_tag:=0; + +@ @= +synctex_tag:=0; +@z diff --git a/Build/source/texk/web2c/xetexdir/ChangeLog b/Build/source/texk/web2c/xetexdir/ChangeLog index 6a17ce9b324..82ff9fe1848 100644 --- a/Build/source/texk/web2c/xetexdir/ChangeLog +++ b/Build/source/texk/web2c/xetexdir/ChangeLog @@ -1,3 +1,10 @@ +2014-07-22 Khaled Hosny + + * xetex.web, xetex.ch, tex.ch0: Switch right-to-left support from + e-TeX's TeX--XeT to Knuth's original TeX-XeT code (with some fixes and + slight modification to the DVI opcode) to fix TeX--XeT paired specials + issue. + 2014-07-15 Khaled Hosny Peter Breitenlohner diff --git a/Build/source/texk/web2c/xetexdir/tex.ch0 b/Build/source/texk/web2c/xetexdir/tex.ch0 index ff1d4950cfe..b27b72cc1ba 100644 --- a/Build/source/texk/web2c/xetexdir/tex.ch0 +++ b/Build/source/texk/web2c/xetexdir/tex.ch0 @@ -12,7 +12,7 @@ @z @x [15.209] l.4165 - additional XeTeX commands -@d shorthand_def=97 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} +@d shorthand_def=98 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} @y @d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} @z diff --git a/Build/source/texk/web2c/xetexdir/xetex.ch b/Build/source/texk/web2c/xetexdir/xetex.ch index c0b1f9f0a04..84d46506b1a 100644 --- a/Build/source/texk/web2c/xetexdir/xetex.ch +++ b/Build/source/texk/web2c/xetexdir/xetex.ch @@ -141,7 +141,7 @@ if translate_filename then begin @x [15.209] l.4165 @d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} @y -@d shorthand_def=97 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} +@d shorthand_def=98 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} @z @x [17.222] l.4523 - frozen_special, for source specials. diff --git a/Build/source/texk/web2c/xetexdir/xetex.web b/Build/source/texk/web2c/xetexdir/xetex.web index e897b6aabb3..e3e179d4377 100644 --- a/Build/source/texk/web2c/xetexdir/xetex.web +++ b/Build/source/texk/web2c/xetexdir/xetex.web @@ -315,6 +315,12 @@ helping to determine whether a particular implementation deserves to be known as `\TeX' [cf.~Stanford Computer Science report CS1027, November 1984]. +This program contains code for mixed left-to-right and right-to-left +typesetting, based on \TeXeT\ as presented by Donald~E. Knuth and Pierre +MacKay in {\sl TUGboat\/} {\bf 8}, 14--25, 1987. +@^Knuth, Donald Ervin@> +@^MacKay, Pierre@> + A similar test suite called the ``\.{e-TRIP} test'' is available for helping to determine whether a particular implementation deserves to be known as `\eTeX'. @@ -334,7 +340,7 @@ known as `\eTeX'. @# @d TEX==XETEX {change program name into |XETEX|} @# -@d TeXXeT_code=0 {the \TeXXeT\ feature is optional} +@d TeXXeT_code=0 {for backward compatibility, ignored in \XeTeX} @# @d XeTeX_dash_break_code=1 {non-zero to enable breaks after en- and em-dashes} @# @@ -375,7 +381,6 @@ made here to avoid using several idiosyncratic features of standard into other high-level languages. For example, the `\&{with}' and `\\{new}' features are not used, nor are pointer types, set types, or enumerated scalar types; there are no `\&{var}' parameters, except in the case of files ---- \eTeX, however, does use `\&{var}' parameters for the |reverse| function; there are no tag fields on variant records; there are no assignments |real:=integer|; no procedures are declared local to other procedures.) @@ -3119,8 +3124,7 @@ the proportionality constant for glue setting; |glue_sign(p)| is |stretching| or |shrinking| or |normal| depending on whether or not the glue should stretch or shrink or remain rigid; and |glue_order(p)| specifies the order of infinity to which glue setting applies (|normal|, -|fil|, |fill|, or |filll|). The |subtype| field is not used in \TeX. -In \eTeX\ the |subtype| field records the box direction mode |box_lr|. +|fil|, |fill|, or |filll|). The |subtype| field is not used. @d hlist_node=0 {|type| of hlist nodes} @d box_node_size=7 {number of words to allocate for a box node} @@ -3397,28 +3401,9 @@ after mathematical formulas. The |subtype| field is |before| before the formula and |after| after it. There is a |width| field, which represents the amount of surrounding space inserted by \.{\\mathsurround}. -In addition a |math_node| with |subtype>after| and |width=0| will be -(ab)used to record a regular |math_node| reinserted after being -discarded at a line break or one of the text direction primitives ( -\.{\\beginL}, \.{\\endL}, \.{\\beginR}, and \.{\\endR} ). - @d math_node=9 {|type| of a math node} @d before=0 {|subtype| for math node that introduces a formula} @d after=1 {|subtype| for math node that winds up a formula} -@# -@d M_code=2 -@d begin_M_code=M_code+before {|subtype| for \.{\\beginM} node} -@d end_M_code=M_code+after {|subtype| for \.{\\endM} node} -@d L_code=4 -@d begin_L_code=L_code+begin_M_code {|subtype| for \.{\\beginL} node} -@d end_L_code=L_code+end_M_code {|subtype| for \.{\\endL} node} -@d R_code=L_code+L_code -@d begin_R_code=R_code+begin_M_code {|subtype| for \.{\\beginR} node} -@d end_R_code=R_code+end_M_code {|subtype| for \.{\\endR} node} -@# -@d end_LR(#)==odd(subtype(#)) -@d end_LR_type(#)==(L_code*(subtype(#) div L_code)+end_M_code) -@d begin_LR_type(#)==(#-after+before) @p function new_math(@!w:scaled;@!s:small_number):pointer; var p:pointer; {the new node} @@ -3655,6 +3640,7 @@ However, other references to the nodes are made symbolically in terms of the \.{WEB} macro definitions above, so that format changes will leave \TeX's other algorithms intact. @^system dependencies@> +@p@ @* \[11] Memory layout. Some areas of |mem| are dedicated to fixed usage, since static allocation is @@ -3983,8 +3969,7 @@ whatsit_node: endcases; rule_node: print_char("|"); glue_node: if glue_ptr(p)<>zero_glue then print_char(" "); -math_node: if subtype(p)>=L_code then print("[]") - else print_char("$"); +math_node: print_char("$"); ligature_node: short_display(lig_ptr(p)); disc_node: begin short_display(pre_break(p)); short_display(post_break(p));@/ @@ -4162,7 +4147,6 @@ else begin @; if shift_amount(p)<>0 then begin print(", shifted "); print_scaled(shift_amount(p)); end; - if eTeX_ex then @; end; node_list_display(list_ptr(p)); {recursive call} end @@ -4259,13 +4243,6 @@ else begin print_esc("mkern"); print_scaled(width(p)); print("mu"); end @ @= -if subtype(p)>after then - begin if end_LR(p) then print_esc("end") - else print_esc("begin"); - if subtype(p)>R_code then print_char("R") - else if subtype(p)>L_code then print_char("L") - else print_char("M"); - end else begin print_esc("math"); if subtype(p)=before then print("on") else print("off"); @@ -4568,7 +4545,6 @@ expanded by `\.{\\the}'. @d leader_ship=31 {use a box ( \.{\\shipout}, \.{\\leaders}, etc.~)} @d halign=32 {horizontal table alignment ( \.{\\halign} )} @d valign=33 {vertical table alignment ( \.{\\valign} )} - {or text direction directives ( \.{\\beginL}, etc.~)} @d no_align=34 {temporary escape from alignment ( \.{\\noalign} )} @d vrule=35 {vertical rule ( \.{\\vrule} )} @d hrule=36 {horizontal rule ( \.{\\hrule} )} @@ -4610,52 +4586,53 @@ expanded by `\.{\\the}'. @d XeTeX_math_given=70 {extended math code defined by \.{\\Umathchardef}} @d last_item=71 {most recent item ( \.{\\lastpenalty}, \.{\\lastkern}, \.{\\lastskip} )} -@d max_non_prefixed_command=71 {largest command code that can't be \.{\\global}} +@d LR=72 {text direction ( \.{\\beginL}, \.{\\beginR}, \.{\\endL}, \.{\\endR} )} +@d max_non_prefixed_command=72 {largest command code that can't be \.{\\global}} @ The next codes are special; they all relate to mode-independent assignment of values to \TeX's internal registers or tables. Codes that are |max_internal| or less represent internal quantities that might be expanded by `\.{\\the}'. -@d toks_register=72 {token list register ( \.{\\toks} )} -@d assign_toks=73 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)} -@d assign_int=74 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)} -@d assign_dimen=75 {user-defined length ( \.{\\hsize}, etc.~)} -@d assign_glue=76 {user-defined glue ( \.{\\baselineskip}, etc.~)} -@d assign_mu_glue=77 {user-defined muglue ( \.{\\thinmuskip}, etc.~)} -@d assign_font_dimen=78 {user-defined font dimension ( \.{\\fontdimen} )} -@d assign_font_int=79 {user-defined font integer ( \.{\\hyphenchar}, +@d toks_register=73 {token list register ( \.{\\toks} )} +@d assign_toks=74 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)} +@d assign_int=75 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)} +@d assign_dimen=76 {user-defined length ( \.{\\hsize}, etc.~)} +@d assign_glue=77 {user-defined glue ( \.{\\baselineskip}, etc.~)} +@d assign_mu_glue=78 {user-defined muglue ( \.{\\thinmuskip}, etc.~)} +@d assign_font_dimen=79 {user-defined font dimension ( \.{\\fontdimen} )} +@d assign_font_int=80 {user-defined font integer ( \.{\\hyphenchar}, \.{\\skewchar} )} -@d set_aux=80 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )} -@d set_prev_graf=81 {specify state info ( \.{\\prevgraf} )} -@d set_page_dimen=82 {specify state info ( \.{\\pagegoal}, etc.~)} -@d set_page_int=83 {specify state info ( \.{\\deadcycles}, +@d set_aux=81 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )} +@d set_prev_graf=82 {specify state info ( \.{\\prevgraf} )} +@d set_page_dimen=83 {specify state info ( \.{\\pagegoal}, etc.~)} +@d set_page_int=84 {specify state info ( \.{\\deadcycles}, \.{\\insertpenalties} )} {( or \.{\\interactionmode} )} -@d set_box_dimen=84 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )} -@d set_shape=85 {specify fancy paragraph shape ( \.{\\parshape} )} +@d set_box_dimen=85 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )} +@d set_shape=86 {specify fancy paragraph shape ( \.{\\parshape} )} {(or \.{\\interlinepenalties}, etc.~)} -@d def_code=86 {define a character code ( \.{\\catcode}, etc.~)} -@d XeTeX_def_code=87 {\.{\\Umathcode}, \.{\\Udelcode}} -@d def_family=88 {declare math fonts ( \.{\\textfont}, etc.~)} -@d set_font=89 {set current font ( font identifiers )} -@d def_font=90 {define a font file ( \.{\\font} )} -@d register=91 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)} -@d max_internal=91 {the largest code that can follow \.{\\the}} -@d advance=92 {advance a register or parameter ( \.{\\advance} )} -@d multiply=93 {multiply a register or parameter ( \.{\\multiply} )} -@d divide=94 {divide a register or parameter ( \.{\\divide} )} -@d prefix=95 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} +@d def_code=87 {define a character code ( \.{\\catcode}, etc.~)} +@d XeTeX_def_code=88 {\.{\\Umathcode}, \.{\\Udelcode}} +@d def_family=89 {declare math fonts ( \.{\\textfont}, etc.~)} +@d set_font=90 {set current font ( font identifiers )} +@d def_font=91 {define a font file ( \.{\\font} )} +@d register=92 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)} +@d max_internal=92 {the largest code that can follow \.{\\the}} +@d advance=93 {advance a register or parameter ( \.{\\advance} )} +@d multiply=94 {multiply a register or parameter ( \.{\\multiply} )} +@d divide=95 {divide a register or parameter ( \.{\\divide} )} +@d prefix=96 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} {( or \.{\\protected} )} -@d let=96 {assign a command code ( \.{\\let}, \.{\\futurelet} )} -@d shorthand_def=97 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} -@d read_to_cs=98 {read into a control sequence ( \.{\\read} )} +@d let=97 {assign a command code ( \.{\\let}, \.{\\futurelet} )} +@d shorthand_def=98 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} +@d read_to_cs=99 {read into a control sequence ( \.{\\read} )} {( or \.{\\readline} )} -@d def=99 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )} -@d set_box=100 {set a box ( \.{\\setbox} )} -@d hyph_data=101 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )} -@d set_interaction=102 {define level of interaction ( \.{\\batchmode}, etc.~)} -@d max_command=102 {the largest command code seen at |big_switch|} +@d def=100 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )} +@d set_box=101 {set a box ( \.{\\setbox} )} +@d hyph_data=102 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )} +@d set_interaction=103 {define level of interaction ( \.{\\batchmode}, etc.~)} +@d max_command=103 {the largest command code seen at |big_switch|} @ The remaining command codes are extra special, since they cannot get through \TeX's scanner to the main control routine. They have been given values higher @@ -6488,8 +6465,7 @@ the: if chr_code=0 then print_esc("the") @; toks_register: @; vadjust: print_esc("vadjust"); -valign: if chr_code=0 then print_esc("valign")@/ - @; +valign: print_esc("valign"); vcenter: print_esc("vcenter"); vrule: print_esc("vrule"); @@ -9314,7 +9290,6 @@ label exit; var m:halfword; {|chr_code| part of the operand token} n, k, kk: integer; {accumulators} @!q,@!r:pointer; {general purpose indices} -@!tx:pointer; {effective tail node} @!i:four_quarters; {character info} @!p:0..nest_size; {index into |nest|} begin m:=cur_chr; @@ -9616,21 +9591,6 @@ implemented. The reference count for \.{\\lastskip} will be updated later. We also handle \.{\\inputlineno} and \.{\\badness} here, because they are legal in similar contexts. -The macro |find_effective_tail_eTeX| sets |tx| to the last non-\.{\\endM} -node of the current list. - -@d find_effective_tail_eTeX== -tx:=tail; -if not is_char_node(tx) then - if (type(tx)=math_node)and(subtype(tx)=end_M_code) then - begin r:=head; - repeat q:=r; r:=link(q); - until r=tx; - tx:=q; - end -@# -@d find_effective_tail==find_effective_tail_eTeX - @= if m>=input_line_no_code then if m>=eTeX_glue then @@; @@ -9656,24 +9616,23 @@ if m>=input_line_no_code then cur_val_level:=int_val; end else begin if cur_chr=glue_val then cur_val:=zero_glue@+else cur_val:=0; - find_effective_tail; if cur_chr=last_node_type_code then begin cur_val_level:=int_val; - if (tx=head)or(mode=0) then cur_val:=-1; + if (tail=head)or(mode=0) then cur_val:=-1; end else cur_val_level:=cur_chr; - if not is_char_node(tx)and(mode<>0) then + if not is_char_node(tail)and(mode<>0) then case cur_chr of - int_val: if type(tx)=penalty_node then cur_val:=penalty(tx); - dimen_val: if type(tx)=kern_node then cur_val:=width(tx); - glue_val: if type(tx)=glue_node then - begin cur_val:=glue_ptr(tx); - if subtype(tx)=mu_glue then cur_val_level:=mu_val; + int_val: if type(tail)=penalty_node then cur_val:=penalty(tail); + dimen_val: if type(tail)=kern_node then cur_val:=width(tail); + glue_val: if type(tail)=glue_node then + begin cur_val:=glue_ptr(tail); + if subtype(tail)=mu_glue then cur_val_level:=mu_val; end; - last_node_type_code: if type(tx)<=unset_node then cur_val:=type(tx)+1 + last_node_type_code: if type(tail)<=unset_node then cur_val:=type(tail)+1 else cur_val:=unset_node+2; end {there are no other cases} - else if (mode=vmode)and(tx=head) then + else if (mode=vmode)and(tail=head) then case cur_chr of int_val: cur_val:=last_penalty; dimen_val: cur_val:=last_kern; @@ -12772,6 +12731,9 @@ notation. For example, a two-byte-long distance parameter has a value between $-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy more than one byte position appear in BigEndian order. +\XeTeX\ extends the format of \.{DVI} with its own commands, and thus produced +``extended device independent'' (\.{XDV}) files. + A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one or more ``pages,'' followed by a ``postamble.'' The preamble is simply a |pre| command, with its parameters that define the dimensions used in the @@ -12825,7 +12787,7 @@ measurement is variable, as explained below; \TeX\ sets things up so that its \.{DVI} output is in sp units, i.e., scaled points, in agreement with all the |scaled| dimensions in \TeX's data structures. -@ Here is a list of all the commands that may appear in a \.{DVI} file. Each +@ Here is a list of all the commands that may appear in a \.{XDV} file. Each command is specified by its symbolic name (e.g., |bop|), its opcode byte (e.g., 139), and its parameters (if any). The parameters are followed by a bracketed number telling how many bytes they occupy; for example, @@ -13060,6 +13022,12 @@ file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below. \yskip\hang|post_post| 249. Ending of the postamble, see below. +\yskip\noindent Commands 250--255 are undefined in normal \.{DVI} files, but +the following commands are used in \.{XDV} files. + +\yskip\hang|reflect| 250 |b[1]|. Begin (|b=0|) or end (|b=1|) a (possibly +recursive) reflected segment. + \yskip\hang|pic_file| 251 |flags[1]| |t[4][6]| |p[2]| |len[2]| |path[l]|. |flags=0| for raster image, and |1| for \.{PDF}. |t| is transform matrix. @@ -13070,17 +13038,17 @@ file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below. \yskip\hang\vbox{\halign{#&#\hfil\cr |define_native_font| 252 & |k[4]| |s[4]| |flags[2]| |lenps[1]| |lenfam[1]| |lensty[1]| |ps[lenps]| |fam[lenfam]| |sty[lensty]|\cr & |if (flags and COLORED) then| |rgba[4]|\cr +& |if (flags and EXTEND) then| |extend[4]|\cr +& |if (flags and SLANT) then| |slant[4]|\cr +& |if (flags and EMBOLDEN) then| |embolden[4]|\cr & |if (flags and VARIATIONS) then| |numvars[2]| |axes[4nv]| |values[4nv]|\cr -& |if (flags and MATRIX) then| |ta[4]| |tb[4]| |tc[4]| |td[4]| |tx[4]| |ty[4]|\cr }} \yskip\hang|set_glyph_array| 253 |w[4]| |k[2]| |xy[8k]| |g[2k]|. \yskip\hang|set_glyph_string| 254 |w[4]| |k[2]| |x[4k]| |g[2k]|. -\yskip\noindent Commands 250--255 are undefined in normal \.{DVI} files, -but 251--254 are permitted in the extended `\.{XDV}' files -produced by \XeTeX. p\TeX\ uses 255. +\yskip\noindent Command 255 is undefined in normal \.{XDV} files. @ @d set_char_0=0 {typeset character 0 and move right} @d set1=128 {typeset a character and move right} @@ -13110,6 +13078,7 @@ produced by \XeTeX. p\TeX\ uses 255. @d post=248 {postamble beginning} @d post_post=249 {postamble ending} +@d reflect=250 {begin or end a reflected segment} @d pic_file=251 {embed picture or PDF} @d define_native_font=252 {define native font} @d set_glyph_array=253 {sequence of glyphs with individual x-y coordinates} @@ -13750,33 +13719,6 @@ there is no need for a `\\{cur\_f}' variable. The depth of nesting of |hlist_out| and |vlist_out| is called |cur_s|; this is essentially the depth of |push| commands in the \.{DVI} output. -For mixed direction text (\TeXXeT) the current text direction is called -|cur_dir|. As the box being shipped out will never be used again and -soon be recycled, we can simply reverse any R-text (i.e., right-to-left) -segments of hlist nodes as well as complete hlist nodes embedded in such -segments. Moreover this can be done iteratively rather than recursively. -There are, however, two complications related to leaders that require -some additional bookkeeping: (1)~One and the same hlist node might be -used more than once (but never inside both L- and R-text); and -(2)~leader boxes inside hlists must be aligned with respect to the left -edge of the original hlist. - -A math node is changed into a kern node whenever the text direction -remains the same, it is replaced by an |edge_node| if the text direction -changes; the subtype of an an |hlist_node| inside R-text is changed to -|reversed| once its hlist has been reversed. -@!@^data structure assumptions@> - -@d reversed=1 {subtype for an |hlist_node| whose hlist has been reversed} -@d dlist=2 {subtype for an |hlist_node| from display math mode} -@d box_lr(#) == (qo(subtype(#))) {direction mode of a box} -@d set_box_lr(#) == subtype(#):=set_box_lr_end -@d set_box_lr_end(#) == qi(#) -@# -@d left_to_right=0 -@d right_to_left=1 -@d reflected==1-cur_dir {the opposite of |cur_dir|} -@# @d synch_h==if cur_h<>dvi_h then begin movement(cur_h-dvi_h,right1); dvi_h:=cur_h; end @@ -13849,7 +13791,7 @@ var base_line: scaled; {the baseline coordinate for this box} @!leader_wd:scaled; {width of leader box being replicated} @!lx:scaled; {extra space between leader boxes} @!outer_doing_leaders:boolean; {were we doing leaders?} -@!edge:scaled; {right edge of sub-box or leader space} +@!edge:scaled; {left edge of sub-box, or right edge of leader space} @!prev_p:pointer; {one step behind |p|} @!len: integer; {length of scratch string for native word output} @!q,@!r: pointer; @@ -13865,13 +13807,9 @@ p:=list_ptr(this_box); incr(cur_s); if cur_s>0 then dvi_out(push); if cur_s>max_push then max_push:=cur_s; -save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; -prev_p:=this_box+list_offset; -@; -left_edge:=cur_h; +save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h; while p<>null do @; -@; prune_movements(save_loc); if cur_s>0 then dvi_pop(save_loc); decr(cur_s); @@ -13984,7 +13922,6 @@ reswitch: if is_char_node(p) then if c>=qi(128) then dvi_out(set1); dvi_out(qo(c));@/ cur_h:=cur_h+char_width(f)(char_info(f)(c)); - prev_p:=link(prev_p); {N.B.: not |prev_p:=p|, |p| might be |lig_trick|} p:=link(p); until not is_char_node(p); dvi_h:=cur_h; @@ -14013,27 +13950,24 @@ glue_node: @; margin_kern_node: begin cur_h:=cur_h+width(p); end; -kern_node:cur_h:=cur_h+width(p); -math_node: @; +kern_node,math_node:cur_h:=cur_h+width(p); ligature_node: @; -@/@@; othercases do_nothing endcases;@/ goto next_p; fin_rule: @; move_past: cur_h:=cur_h+rule_wd; -next_p:prev_p:=p; p:=link(p); +next_p:p:=link(p); end @ @= if list_ptr(p)=null then cur_h:=cur_h+width(p) else begin save_h:=dvi_h; save_v:=dvi_v; cur_v:=base_line+shift_amount(p); {shift the box down} - temp_ptr:=p; edge:=cur_h+width(p); - if cur_dir=right_to_left then cur_h:=edge; + temp_ptr:=p; edge:=cur_h; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_h:=save_h; dvi_v:=save_v; - cur_h:=edge; cur_v:=base_line; + cur_h:=edge+width(p); cur_v:=base_line; end @ @= @@ -14052,8 +13986,9 @@ if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} glue_temp:=billion else if glue_temp<-billion then glue_temp:=-billion -@# -@d round_glue==g:=glue_ptr(p); rule_wd:=width(g)-cur_g; + +@= +begin g:=glue_ptr(p); rule_wd:=width(g)-cur_g; if g_sign<>normal then begin if g_sign=stretching then begin if stretch_order(g)=g_order then @@ -14069,11 +14004,7 @@ if g_sign<>normal then cur_g:=round(glue_temp); end; end; -rule_wd:=rule_wd+cur_g - -@= -begin round_glue; -if eTeX_ex then @; +rule_wd:=rule_wd+cur_g; if subtype(p)>=a_leaders then @; @@ -14089,16 +14020,13 @@ if type(leader_box)=rule_node then leader_wd:=width(leader_box); if (leader_wd>0)and(rule_wd>0) then begin rule_wd:=rule_wd+10; {compensate for floating-point rounding} - if cur_dir=right_to_left then cur_h:=cur_h-10; edge:=cur_h+rule_wd; lx:=0; @; while cur_h+leader_wd<=edge do @; - if cur_dir=right_to_left then cur_h:=edge - else cur_h:=edge-10; - goto next_p; + cur_h:=edge-10; goto next_p; end; end @@ -14138,7 +14066,6 @@ bytes needed to specify horizontal and vertical motion in the \.{DVI} output. @= begin cur_v:=base_line+shift_amount(leader_box); synch_v; save_v:=dvi_v;@/ synch_h; save_h:=dvi_h; temp_ptr:=leader_box; -if cur_dir=right_to_left then cur_h:=cur_h+leader_wd; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_out@+else hlist_out; doing_leaders:=outer_doing_leaders; @@ -14215,8 +14142,7 @@ usually be constant. if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) else begin if upwards then cur_v:=cur_v-depth(p) else cur_v:=cur_v+height(p); synch_v; save_h:=dvi_h; save_v:=dvi_v; - if cur_dir=right_to_left then cur_h:=left_edge-shift_amount(p) - else cur_h:=left_edge+shift_amount(p); {shift the box right} + cur_h:=left_edge+shift_amount(p); {shift the box right} temp_ptr:=p; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_h:=save_h; dvi_v:=save_v; @@ -14228,10 +14154,8 @@ if is_running(rule_wd) then rule_wd:=width(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} if upwards then cur_v:=cur_v-rule_ht else cur_v:=cur_v+rule_ht; if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} - begin if cur_dir=right_to_left then cur_h:=cur_h-rule_wd; - synch_h; synch_v; + begin synch_h; synch_v; dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); - cur_h:=left_edge; end; goto next_p @@ -14296,10 +14220,7 @@ else begin lq:=rule_ht div leader_ht; {the number of box copies} leader box, not its baseline. @= -begin if cur_dir=right_to_left then - cur_h:=left_edge-shift_amount(leader_box) - else cur_h:=left_edge+shift_amount(leader_box); -synch_h; save_h:=dvi_h;@/ +begin cur_h:=left_edge+shift_amount(leader_box); synch_h; save_h:=dvi_h;@/ cur_v:=cur_v+height(leader_box); synch_v; save_v:=dvi_v; temp_ptr:=leader_box; outer_doing_leaders:=doing_leaders; doing_leaders:=true; @@ -14320,6 +14241,7 @@ var page_loc:integer; {location of the current |bop|} @!old_setting:0..max_selector; {saved |selector| setting} begin if job_name=0 then open_log_file; +LR_ptr:=get_avail; info(LR_ptr):=0; {|begin_L_code| at outer level} if tracing_output>0 then begin print_nl(""); print_ln; print("Completed box being shipped out"); @@ -14339,7 +14261,6 @@ if tracing_output>0 then begin_diagnostic; show_box(p); end_diagnostic(true); end; @; -if eTeX_ex then @; if tracing_output<=0 then print_char("]"); dead_cycles:=0; update_terminal; {progress report} @@ -14354,7 +14275,7 @@ end; print_int(dyn_used); print_char(";"); end; tats@/ -flush_node_list(p); +flush_node_list(p); @; @!stat if tracing_stats>1 then begin print(" after: "); print_int(var_used); print_char("&"); @@ -14642,11 +14563,13 @@ var r:pointer; {the box node that will be returned} @!hd:eight_bits; {height and depth indices for a character} @!pp,@!ppp: pointer; @!total_chars, @!k: integer; -begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node; +@!LR_ptr,@!LR_tmp:pointer; {for LR stack maintenance} +@!LR_problems:integer; {counts missing begins and ends} +begin LR_ptr:=null; LR_problems:=0; +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;@/ h:=0; @; -if TeXXeT_en then @; while p<>null do @; @@ -14657,7 +14580,7 @@ height(r):=h; depth(r):=d;@/ then |return| or |goto common_ending|@>; common_ending: @; -exit: if TeXXeT_en then @; +exit: @; hpack:=r; end; @@ -14682,11 +14605,8 @@ if p<>null then @; whatsit_node:@; glue_node:@; - kern_node: x:=x+width(p); + kern_node,math_node: x:=x+width(p); margin_kern_node: x:=x+width(p); - math_node: begin x:=x+width(p); - if TeXXeT_en then @; - end; ligature_node: @; othercases do_nothing @@ -18591,7 +18511,6 @@ depending on how soon \.{\\cr} occurred in that row. @= begin if mode=-vmode then begin type(q):=hlist_node; width(q):=width(p); - if nest[nest_ptr-1].mode_field=mmode then set_box_lr(q)(dlist); {for |ship_out|} end else begin type(q):=vlist_node; height(q):=height(p); end; @@ -18610,7 +18529,6 @@ arithmetic from entering into the dimensions of any boxes. @= n:=span_count(r); t:=width(s); w:=t; u:=hold_head; -set_box_lr(r)(0); {for |ship_out|} while n>min_quarterword do begin decr(n); @; -math_node: begin if subtype(cur_p); @@ -20229,8 +20146,6 @@ loop@+ begin q:=link(r); if non_discardable(q) then goto done1; if type(q)=kern_node then if subtype(q)<>explicit then goto done1; r:=q; {now |type(q)=glue_node|, |kern_node|, |math_node| or |penalty_node|} - if type(q)=math_node then if TeXXeT_en then - @; end; done1: if r<>temp_head then begin link(r):=null; flush_node_list(link(temp_head)); @@ -20247,12 +20162,11 @@ is compulsory, and we set |disc_break| to |true|. We also append the |left_skip| glue at the left of the line, unless it is zero. @= -if TeXXeT_en then - @; +@; +@; @; -if TeXXeT_en then @; +@; @; @; @null then {|q| cannot be a |char_node|} else begin if type(q)=disc_node then @ - else if type(q)=kern_node then width(q):=0 - else if type(q)=math_node then - begin width(q):=0; - if TeXXeT_en then @; - end; + else if (type(q)=math_node)or(type(q)=kern_node) then width(q):=0; end else begin q:=temp_head; while link(q)<>null do q:=link(q); @@ -20466,8 +20376,7 @@ A sequence of characters will be considered for hyphenation only if it belongs to a ``potentially hyphenatable part'' of the current paragraph. This is a sequence of nodes $p_0p_1\ldots p_m$ where $p_0$ is a glue node, $p_1\ldots p_{m-1}$ are either character or ligature or whatsit or -implicit kern or text direction nodes, and $p_m$ is a glue or penalty or -insertion or adjust +implicit kern nodes, and $p_m$ is a glue or penalty or insertion or adjust or mark or whatsit or explicit kern node. (Therefore hyphenation is disabled by boxes, math formulas, and discretionary nodes already inserted by the user.) The ligature nodes among $p_1\ldots p_{m-1}$ are effectively @@ -20653,7 +20562,6 @@ loop@+ begin if is_char_node(s) then else begin q:=lig_ptr(s); c:=qo(character(q)); hf:=font(q); end else if (type(s)=kern_node)and(subtype(s)=normal) then goto continue - else if (type(s)=math_node)and(subtype(s)>=L_code) then goto continue else if type(s)=whatsit_node then begin if subtype(s) = native_word_node then begin @@ -20737,7 +20645,6 @@ loop@+ begin if not(is_char_node(s)) then kern_node: if subtype(s)<>normal then goto done4; whatsit_node,glue_node,penalty_node,ins_node,adjust_node,mark_node: goto done4; - math_node: if subtype(s)>=L_code then goto done4@+else goto done1; othercases goto done1 endcases; s:=link(s); @@ -24441,9 +24348,6 @@ box desired, and |cur_cmd=make_box|. procedure begin_box(@!box_context:integer); label exit, done; var @!p,@!q:pointer; {run through the current list} -@!r:pointer; {running behind |p|} -@!fm:boolean; {a final \.{\\beginM} \.{\\endM} node pair?} -@!tx:pointer; {effective tail node} @!m:quarterword; {the length of a replacement list} @!k:halfword; {0 or |vmode| or |hmode|} @!n:halfword; {a box number} @@ -24464,28 +24368,6 @@ exit:end; @ Note that the condition |not is_char_node(tail)| implies that |head<>tail|, since |head| is a one-word node. -@d fetch_effective_tail_eTeX(#)== {extract |tx|, - drop \.{\\beginM} \.{\\endM} pair} -q:=head; p:=null; -repeat r:=p; p:=q; fm:=false; -if not is_char_node(q) then - if type(q)=disc_node then - begin for m:=1 to replace_count(q) do p:=link(p); - if p=tx then #; - end - else if (type(q)=math_node)and(subtype(q)=begin_M_code) then fm:=true; -q:=link(p); -until q=tx; {found |r|$\to$|p|$\to$|q=tx|} -q:=link(tx); link(p):=q; link(tx):=null; -if q=null then if fm then confusion("tail1") -@:this can't happen tail1}{\quad tail1@> - else tail:=p -else if fm then {|r|$\to$|p=begin_M|$\to$|q=end_M|} - begin tail:=r; link(r):=null; flush_node_list(p);@+end -@# -@d check_effective_tail(#)==find_effective_tail_eTeX -@d fetch_effective_tail==fetch_effective_tail_eTeX - @= begin cur_box:=null; if abs(mode)=mmode then @@ -24496,17 +24378,24 @@ else if (mode=vmode)and(head=tail) then help2("Sorry...I usually can't take things from the current page.")@/ ("This \lastbox will therefore be void."); error; end -else begin check_effective_tail(goto done); - if not is_char_node(tx) then - if (type(tx)=hlist_node)or(type(tx)=vlist_node) then +else begin if not is_char_node(tail) then + if (type(tail)=hlist_node)or(type(tail)=vlist_node) then @; - done:end; + end; end @ @= -begin fetch_effective_tail(goto done); -cur_box:=tx; shift_amount(cur_box):=0; -end +begin q:=head; +repeat p:=q; +if not is_char_node(q) then if type(q)=disc_node then + begin for m:=1 to replace_count(q) do p:=link(p); + if p=tail then goto done; + end; +q:=link(p); +until q=tail; +cur_box:=tail; shift_amount(cur_box):=0; +tail:=p; link(p):=null; +done:end @ Here we deal with things like `\.{\\vsplit 13 to 100pt}'. @@ -24625,7 +24514,7 @@ vmode+start_par: new_graf(cur_chr>0); vmode+letter,vmode+other_char,vmode+char_num,vmode+char_given, vmode+math_shift,vmode+un_hbox,vmode+vrule, vmode+accent,vmode+discretionary,vmode+hskip,vmode+valign, - vmode+ex_space,vmode+no_boundary:@t@>@;@/ + vmode+ex_space,vmode+no_boundary,vmode+LR:@t@>@;@/ begin back_input; new_graf(true); end; @@ -24699,7 +24588,7 @@ end; procedure end_graf; begin if mode=hmode then begin if head=tail then pop_nest {null paragraphs are ignored} - else line_break(false); + else line_break(widow_penalty); if LR_save<>null then begin flush_list(LR_save); LR_save:=null; end; @@ -24802,17 +24691,20 @@ will be deleted, if present. procedure delete_last; label exit; var @!p,@!q:pointer; {run through the current list} -@!r:pointer; {running behind |p|} -@!fm:boolean; {a final \.{\\beginM} \.{\\endM} node pair?} -@!tx:pointer; {effective tail node} @!m:quarterword; {the length of a replacement list} begin if (mode=vmode)and(tail=head) then @ -else begin check_effective_tail(return); - if not is_char_node(tx) then if type(tx)=cur_chr then - begin fetch_effective_tail(return); - flush_node_list(tx); +else begin if not is_char_node(tail) then if type(tail)=cur_chr then + begin q:=head; + repeat p:=q; + if not is_char_node(q) then if type(q)=disc_node then + begin for m:=1 to replace_count(q) do p:=link(p); + if p=tail then return; + end; + q:=link(p); + until q=tail; + link(p):=null; flush_node_list(tail); tail:=p; end; end; exit:end; @@ -25187,8 +25079,7 @@ end; Let's take a look at what happens when they are used correctly. @= -vmode+halign:init_align; -hmode+valign:@@; init_align; +vmode+halign,hmode+valign:init_align; mmode+halign: if privileged then if cur_group=math_shift_group then init_align else off_save; @@ -25267,12 +25158,9 @@ called for. hmode+math_shift:init_math; @ @= -@t\4@>@@; procedure init_math; label reswitch,found,not_found,done; var w:scaled; {new or partial |pre_display_size|} -@!j:pointer; {prototype box for display} -@!x:integer; {new |pre_display_direction|} @!l:scaled; {new |display_width|} @!s:scaled; {new |display_indent|} @!p:pointer; {current node when calculating |pre_display_size|} @@ -25328,10 +25216,10 @@ display. Then we can set the proper values of |display_width| and |display_indent| and |pre_display_size|. @= -begin j:=null; w:=-max_dimen; -if head=tail then {`\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}'} - @ -else begin line_break(true);@/ +begin if head=tail then {`\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}'} + begin pop_nest; w:=-max_dimen; + end +else begin line_break(display_widow_penalty);@/ @null then begin_token_list(every_display,every_display_text); @@ -25351,7 +25237,8 @@ if nest_ptr=1 then build_page; end @ @= -@; +v:=shift_amount(just_box)+2*quad(cur_font); w:=-max_dimen; +p:=list_ptr(just_box); while p<>null do begin @null do not_found: p:=link(p); end; done: -@ @ @= reswitch: if is_char_node(p) then @@ -25377,9 +25263,8 @@ case type(p) of hlist_node,vlist_node,rule_node: begin d:=width(p); goto found; end; ligature_node:@; -kern_node: d:=width(p); +kern_node,math_node: d:=width(p); margin_kern_node: d:=width(p); -@t\4@>@@; glue_node:@; whatsit_node: @; @@ -26093,7 +25978,6 @@ mmode+math_shift: if cur_group=math_shift_group then after_math else off_save; @ @= -@t\4@>@@; procedure after_math; var l:boolean; {`\.{\\leqno}' instead of `\.{\\eqno}'} @!danger:boolean; {not enough symbol fonts are present} @@ -26102,7 +25986,6 @@ var l:boolean; {`\.{\\leqno}' instead of `\.{\\eqno}'} @!a:pointer; {box containing equation number} @@; begin danger:=false; -@; @; m:=mode; l:=false; p:=fin_mlist(null); {this pops the nest} @@ -26110,11 +25993,9 @@ if mode=-m then {end of equation number} begin @; cur_mlist:=p; cur_style:=text_style; mlist_penalties:=false; mlist_to_hlist; a:=hpack(link(temp_head),natural); - set_box_lr(a)(dlist); unsave; decr(save_ptr); {now |cur_group=math_shift_group|} if saved(0)=1 then l:=true; danger:=false; - @; @; m:=mode; p:=fin_mlist(null); @@ -26161,9 +26042,11 @@ space above that display. @= begin tail_append(new_math(math_surround,before)); +@; cur_mlist:=p; cur_style:=text_style; mlist_penalties:=(mode>0); mlist_to_hlist; link(tail):=link(temp_head); while link(tail)<>null do tail:=link(tail); +@; tail_append(new_math(math_surround,after)); space_factor:=1000; unsave; end @@ -26211,7 +26094,6 @@ b:=hpack(p,natural); p:=list_ptr(b); t:=adjust_tail; adjust_tail:=null;@/ pre_t:=pre_adjust_tail; pre_adjust_tail:=null;@/ w:=width(b); z:=display_width; s:=display_indent; -if pre_display_direction<0 then s:=-s-z; if (a=null)or danger then begin e:=0; q:=0; end @@ -26226,7 +26108,6 @@ if w+q>z then @; @; @; -@; resume_after_display @ @= @@ -26269,7 +26150,6 @@ is taken only if the display begins with glue, since we assume that the user put glue there to control the spacing precisely. @= -set_box_lr(b)(dlist); d:=half(z-w); if (e>0)and(d<2*e) then {too close} begin d:=half(z-w-e); @@ -26291,7 +26171,7 @@ else begin g1:=above_display_short_skip_code; g2:=below_display_short_skip_code; end; if l and(e=0) then {it follows that |type(a)=hlist_node|} - begin app_display(j,a,0); + begin shift_amount(a):=s; append_to_vlist(a); tail_append(new_penalty(inf_penalty)); end else tail_append(new_param_glue(g1)) @@ -26306,12 +26186,13 @@ if e<>0 then end; b:=hpack(b,natural); end; -app_display(j,b,d) +shift_amount(b):=s+d; append_to_vlist(b) @ @= if (a<>null)and(e=0)and not l then begin tail_append(new_penalty(inf_penalty)); - app_display(j,a,z-width(a)); + shift_amount(a):=s+z-width(a); + append_to_vlist(a); g2:=0; end; if t<>adjust_head then {migrating material comes after equation number} @@ -26332,7 +26213,6 @@ resulting list, and with |aux_save| holding the |prev_depth| value. begin do_assignments; if cur_cmd<>math_shift then @ else @; -flush_node_list(LR_box); pop_nest; tail_append(new_penalty(pre_display_penalty)); tail_append(new_param_glue(above_display_skip_code)); @@ -28540,7 +28420,9 @@ to hold the string numbers for name, area, and extension. @d write_node=1 {|subtype| in whatsits that represent things to \.{\\write}} @d close_node=2 {|subtype| in whatsits that represent streams to \.{\\closeout}} @d special_node=3 {|subtype| in whatsits that represent \.{\\special} things} -@d language_node=4 {|subtype| in whatsits that change the current language} +@d LR_node=4 {|subtype| in whatsits that represent \.{\\beginL}, etc.} +@d LR_type(#)==mem[#+1].int {the sub-subtype} +@d language_node=5 {|subtype| in whatsits that change the current language} @d what_lang(#)==link(#+1) {language number, in the range |0..255|} @d what_lhm(#)==type(#+1) {minimum left fragment, in the range |1..63|} @d what_rhm(#)==subtype(#+1) {minimum right fragment, in the range |1..63|} @@ -28570,6 +28452,13 @@ stays the same. @d immediate_code=4 {command modifier for \.{\\immediate}} @d set_language_code=5 {command modifier for \.{\\setlanguage}} +@d begin_L_code=0 {command modifier for \.{\\beginL}} +@d begin_R_code=1 {command modifier for \.{\\beginR}} +@d end_L_code=2 {command modifier for \.{\\endL}} +@d end_R_code=3 {command modifier for \.{\\endR}} +@d begin_LR(#)==(LR_type(#)= +primitive("beginL",LR,begin_L_code);@/ +@!@:begin_L_}{\.{\\beginL} primitive@> +primitive("beginR",LR,begin_R_code);@/ +@!@:begin_R_}{\.{\\beginR} primitive@> +primitive("endL",LR,end_L_code);@/ +@!@:end_L_}{\.{\\endL} primitive@> +primitive("endR",LR,end_R_code);@/ +@!@:end_R_}{\.{\\endR} primitive@> primitive("openout",extension,open_node);@/ @!@:open_out_}{\.{\\openout} primitive@> primitive("write",extension,write_node); write_loc:=cur_val;@/ @@ -28619,6 +28516,12 @@ appropriate error message in case of ``runaway'' write texts. @!write_loc:pointer; {|eqtb| address of \.{\\write}} @ @= +LR: case chr_code of +begin_L_code: print_esc("beginL"); +begin_R_code: print_esc("beginR"); +end_L_code: print_esc("endL"); +othercases print_esc("endR") +endcases; extension: case chr_code of open_node:print_esc("openout"); write_node:print_esc("write"); @@ -28849,6 +28752,12 @@ pic_node,pdf_node: begin print(""""); end; pdf_save_pos_node: print_esc("pdfsavepos"); +LR_node: case LR_type(p) of +begin_L_code: print_esc("beginL"); +begin_R_code: print_esc("beginR"); +end_L_code: print_esc("endL"); +othercases print_esc("endR") +endcases; othercases print("whatsit?") endcases @@ -28862,7 +28771,7 @@ open_node: begin r:=get_node(open_node_size); words:=open_node_size; write_node,special_node: begin r:=get_node(write_node_size); add_token_ref(write_tokens(p)); words:=write_node_size; end; -close_node,language_node: begin r:=get_node(small_node_size); +close_node,language_node,LR_node: begin r:=get_node(small_node_size); words:=small_node_size; end; native_word_node: begin words:=native_size(p); @@ -28890,7 +28799,7 @@ open_node: free_node(p,open_node_size); write_node,special_node: begin delete_token_ref(write_tokens(p)); free_node(p,write_node_size); goto done; end; -close_node,language_node: free_node(p,small_node_size); +close_node,language_node,LR_node: free_node(p,small_node_size); native_word_node: begin free_native_glyph_info(p); free_node(p,native_size(p)); end; glyph_node: free_node(p,glyph_node_size); pic_node,pdf_node: free_node(p,total_pic_node_size(p)); @@ -29001,6 +28910,8 @@ begin x := x + width(p); end; + LR_node: @; + othercases do_nothing @@ -29093,6 +29004,8 @@ begin pdf_save_pos_node: @; + LR_node: @; + othercases out_what(p) @@ -29155,7 +29068,6 @@ begin save_h:=dvi_h; save_v:=dvi_v; cur_v:=base_line; edge:=cur_h+width(p); - if cur_dir=right_to_left then cur_h:=edge; pic_out(p, subtype(p) = pdf_node); dvi_h:=save_h; dvi_v:=save_v; cur_h:=edge; cur_v:=base_line; @@ -29164,6 +29076,8 @@ begin pdf_save_pos_node: @; + LR_node: @; + othercases out_what(p) @@ -30737,81 +30651,7 @@ primitive("middle",left_right,middle_noad); @ @= else if chr_code=middle_noad then print_esc("middle") -@ In constructions such as -$$\vbox{\halign{\.{#}\hfil\cr -{}\\hbox to \\hsize\{\cr -\hskip 25pt \\hskip 0pt plus 0.0001fil\cr -\hskip 25pt ...\cr -\hskip 25pt \\hfil\\penalty-200\\hfilneg\cr -\hskip 25pt ...\}\cr}}$$ -the stretch components of \.{\\hfil} and \.{\\hfilneg} compensate; they may, -however, get modified in order to prevent arithmetic overflow during -|hlist_out| when each of them is multiplied by a large |glue_set| value. - -Since this ``glue rounding'' depends on state variables |cur_g| and -|cur_glue| and \TeXXeT\ is supposed to emulate the behaviour of \TeXeT\ -(plus a suitable postprocessor) as close as possible the glue rounding -cannot be postponed until (segments of) an hlist has been reversed. - -The code below is invoked after the effective width, |rule_wd|, of a glue -node has been computed. The glue node is either converted into a kern node -or, for leaders, the glue specification is replaced by an equivalent rigid -one; the subtype of the glue node remains unchanged. - -@= -if (((g_sign=stretching) and (stretch_order(g)=g_order)) or - ((g_sign=shrinking) and (shrink_order(g)=g_order))) then - begin fast_delete_glue_ref(g); - if subtype(p) -@^MacKay, Pierre@> - -In order to avoid confusion with \TeXeT\ the present implementation of -mixed direction typesetting is called \TeXXeT. It differs from \TeXeT\ -in several important aspects: (1)~Right-to-left text is reversed -explicitly by the |ship_out| routine and is written to a normal \.{DVI} -file without any |begin_reflect| or |end_reflect| commands; (2)~a -|math_node| is (ab)used instead of a |whatsit_node| to record the -\.{\\beginL}, \.{\\endL}, \.{\\beginR}, and \.{\\endR} text direction -primitives in order to keep the influence on the line breaking algorithm -for pure left-to-right text as small as possible; (3)~right-to-left text -interrupted by a displayed equation is automatically resumed after that -equation; and (4)~the |valign| command code with a non-zero command -modifier is (ab)used for the text direction primitives. - -Nevertheless there is a subtle difference between \TeX\ and \TeXXeT\ -that may influence the line breaking algorithm for pure left-to-right -text. When a paragraph containing math mode material is broken into -lines \TeX\ may generate lines where math mode material is not enclosed -by properly nested \.{\\mathon} and \.{\\mathoff} nodes. Unboxing such -lines as part of a new paragraph may have the effect that hyphenation is -attempted for `words' originating from math mode or that hyphenation is -inhibited for words originating from horizontal mode. - -In \TeXXeT\ additional \.{\\beginM}, resp.\ \.{\\endM} math nodes are -supplied at the start, resp.\ end of lines such that math mode material -inside a horizontal list always starts with either \.{\\mathon} or -\.{\\beginM} and ends with \.{\\mathoff} or \.{\\endM}. These -additional nodes are transparent to operations such as \.{\\unskip}, -\.{\\lastpenalty}, or \.{\\lastbox} but they do have the effect that -hyphenation is never attempted for `words' originating from math mode -and is never inhibited for words originating from horizontal mode. - -@d TeXXeT_state==eTeX_state(TeXXeT_code) -@d TeXXeT_en==(TeXXeT_state>0) {is \TeXXeT\ enabled?} - +@ @d TeXXeT_state==eTeX_state(TeXXeT_code) @d XeTeX_upwards_state==eTeX_state(XeTeX_upwards_code) @d XeTeX_upwards==(XeTeX_upwards_state>0) @@ -30861,631 +30701,6 @@ primitive("XeTeXtracingfonts",assign_int,eTeX_state_base+XeTeX_tracing_fonts_cod primitive("XeTeXinputencoding",extension,XeTeX_input_encoding_extension_code); primitive("XeTeXdefaultencoding",extension,XeTeX_default_encoding_extension_code); -primitive("beginL",valign,begin_L_code); -@!@:beginL_}{\.{\\beginL} primitive@> -primitive("endL",valign,end_L_code); -@!@:endL_}{\.{\\endL} primitive@> -primitive("beginR",valign,begin_R_code); -@!@:beginR_}{\.{\\beginR} primitive@> -primitive("endR",valign,end_R_code); -@!@:endR_}{\.{\\endR} primitive@> - -@ @= -else case chr_code of - begin_L_code: print_esc("beginL"); - end_L_code: print_esc("endL"); - begin_R_code: print_esc("beginR"); - othercases print_esc("endR") - endcases - -@ @= -if cur_chr>0 then - begin if eTeX_enabled(TeXXeT_en,cur_cmd,cur_chr) then -@.Improper \\beginL@> -@.Improper \\endL@> -@.Improper \\beginR@> -@.Improper \\endR@> - tail_append(new_math(0,cur_chr)); - end -else - -@ An hbox with subtype dlist will never be reversed, even when embedded -in right-to-left text. - -@= -if (type(p)=hlist_node)and(box_lr(p)=dlist) then print(", display") - -@ A number of routines are based on a stack of one-word nodes whose -|info| fields contain |end_M_code|, |end_L_code|, or |end_R_code|. The -top of the stack is pointed to by |LR_ptr|. - -When the stack manipulation macros of this section are used below, -variable |LR_ptr| might be the global variable declared here for |hpack| -and |ship_out|, or might be local to |post_line_break|. - -@d put_LR(#)==begin temp_ptr:=get_avail; info(temp_ptr):=#; - link(temp_ptr):=LR_ptr; LR_ptr:=temp_ptr; - end -@# -@d push_LR(#)==put_LR(end_LR_type(#)) -@# -@d pop_LR==begin temp_ptr:=LR_ptr; LR_ptr:=link(temp_ptr); - free_avail(temp_ptr); - end - -@= -@!LR_ptr:pointer; {stack of LR codes for |hpack|, |ship_out|, and |init_math|} -@!LR_problems:integer; {counts missing begins and ends} -@!cur_dir:small_number; {current text direction} - -@ @= -LR_ptr:=null; LR_problems:=0; cur_dir:=left_to_right; - -@ @= -begin q:=link(temp_head); -if LR_ptr<>null then - begin temp_ptr:=LR_ptr; r:=q; - repeat s:=new_math(0,begin_LR_type(info(temp_ptr))); link(s):=r; r:=s; - temp_ptr:=link(temp_ptr); - until temp_ptr=null; - link(temp_head):=r; - end; -while q<>cur_break(cur_p) do - begin if not is_char_node(q) then - if type(q)=math_node then @; - q:=link(q); - end; -end - -@ @= -if end_LR(q) then - begin if LR_ptr<>null then if info(LR_ptr)=end_LR_type(q) then pop_LR; - end -else push_LR(q) - -@ We use the fact that |q| now points to the node with \.{\\rightskip} glue. - -@= -if LR_ptr<>null then - begin s:=temp_head; r:=link(s); - while r<>q do - begin s:=r; r:=link(s); - end; - r:=LR_ptr; - while r<>null do - begin temp_ptr:=new_math(0,info(r)); - link(s):=temp_ptr; s:=temp_ptr; r:=link(r); - end; - link(s):=q; - end - -@ @= -put_LR(before) {this will never match} - -@ @= -if end_LR(p) then - if info(LR_ptr)=end_LR_type(p) then pop_LR - else begin incr(LR_problems); type(p):=kern_node; subtype(p):=explicit; - end -else push_LR(p) - -@ @= -begin if info(LR_ptr)<>before then - begin while link(q)<>null do q:=link(q); - repeat temp_ptr:=q; q:=new_math(0,info(LR_ptr)); link(temp_ptr):=q; - LR_problems:=LR_problems+10000; pop_LR; - until info(LR_ptr)=before; - end; -if LR_problems>0 then - begin @; goto common_ending; - end; -pop_LR; -if LR_ptr<>null then confusion("LR1"); -@:this can't happen LR1}{\quad LR1@> -end - -@ @= -begin print_ln; print_nl("\endL or \endR problem (");@/ -print_int(LR_problems div 10000); print(" missing, ");@/ -print_int(LR_problems mod 10000); print(" extra");@/ -LR_problems:=0; -end - -@ @= -if eTeX_ex then - begin @; - if box_lr(this_box)=dlist then - if cur_dir=right_to_left then - begin cur_dir:=left_to_right; cur_h:=cur_h-width(this_box); - end - else set_box_lr(this_box)(0); - if (cur_dir=right_to_left)and(box_lr(this_box)<>reversed) then - @; - end - -@ @= -if eTeX_ex then - begin @; - if box_lr(this_box)=dlist then cur_dir:=right_to_left; - end - -@ @= -begin if eTeX_ex then - @; - cur_h:=cur_h+width(p); - end - -@ Breaking a paragraph into lines while \TeXXeT\ is disabled may result -in lines whith unpaired math nodes. Such hlists are silently accepted -in the absence of text direction directives. - -@d LR_dir(#)==(subtype(#) div R_code) {text direction of a `math node'} - -@= -begin if end_LR(p) then - if info(LR_ptr)=end_LR_type(p) then pop_LR - else begin if subtype(p)>L_code then incr(LR_problems); - end -else begin push_LR(p); - if LR_dir(p)<>cur_dir then - @; - end; -type(p):=kern_node; -end - -@ @= -begin while info(LR_ptr)<>before do - begin if info(LR_ptr)>L_code then LR_problems:=LR_problems+10000; - pop_LR; - end; -pop_LR; -end - -@ @d edge_node=style_node {a |style_node| does not occur in hlists} -@d edge_node_size=style_node_size {number of words in an edge node} -@d edge_dist(#)==depth(#) {new |left_edge| position relative to |cur_h| - (after |width| has been taken into account)} - -@= -function new_edge(@!s:small_number;@!w:scaled):pointer; - {create an edge node} -var p:pointer; {the new node} -begin p:=get_node(edge_node_size); type(p):=edge_node; subtype(p):=s; -width(p):=w; edge_dist(p):=0; {the |edge_dist| field will be set later} -new_edge:=p; -end; - -@ @= -edge_node: begin cur_h:=cur_h+width(p); - left_edge:=cur_h+edge_dist(p); cur_dir:=subtype(p); - end; - -@ We detach the hlist, start a new one consisting of just one kern node, -append the reversed list, and set the width of the kern node. - -@= -begin save_h:=cur_h; temp_ptr:=p; p:=new_kern(0); link(prev_p):=p; -cur_h:=0; link(p):=reverse(this_box,null,cur_g,cur_glue); width(p):=-cur_h; -cur_h:=save_h; set_box_lr(this_box)(reversed); -end - -@ We detach the remainder of the hlist, replace the math node by -an edge node, and append the reversed hlist segment to it; the tail of -the reversed segment is another edge node and the remainder of the -original list is attached to it. - -@= -begin save_h:=cur_h; temp_ptr:=link(p); rule_wd:=width(p); -free_node(p,small_node_size); -cur_dir:=reflected; p:=new_edge(cur_dir,rule_wd); link(prev_p):=p; -cur_h:=cur_h-left_edge+rule_wd; -link(p):=reverse(this_box,new_edge(reflected,0),cur_g,cur_glue); -edge_dist(p):=cur_h; cur_dir:=reflected; cur_h:=save_h; -goto reswitch; -end - -@ The |reverse| function defined here is responsible to reverse the -nodes of an hlist (segment). The first parameter |this_box| is the enclosing -hlist node, the second parameter |t| is to become the tail of the reversed -list, and the global variable |temp_ptr| is the head of the list to be -reversed. Finally |cur_g| and |cur_glue| are the current glue rounding state -variables, to be updated by this function. We remove nodes from the original -list and add them to the head of the new one. - -@= -function reverse(@!this_box,@!t:pointer; var cur_g:scaled; - var cur_glue:real):pointer; -label reswitch,next_p,done; -var l:pointer; {the new list} -@!p:pointer; {the current node} -@!q:pointer; {the next node} -@!g_order: glue_ord; {applicable order of infinity for glue} -@!g_sign: normal..shrinking; {selects type of glue} -@!glue_temp:real; {glue value before rounding} -@!m,@!n:halfword; {count of unmatched math nodes} -begin g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); -l:=t; p:=temp_ptr; m:=min_halfword; n:=min_halfword; -loop@+ begin while p<>null do - @; - if (t=null)and(m=min_halfword)and(n=min_halfword) then goto done; - p:=new_math(0,info(LR_ptr)); LR_problems:=LR_problems+10000; - {manufacture one missing math node} - end; -done:reverse:=l; -end; - -@ @= -reswitch: if is_char_node(p) then - repeat f:=font(p); c:=character(p); - cur_h:=cur_h+char_width(f)(char_info(f)(c)); - q:=link(p); link(p):=l; l:=p; p:=q; - until not is_char_node(p) -else @ - -@ @= -begin q:=link(p); -case type(p) of -hlist_node,vlist_node,rule_node,kern_node: rule_wd:=width(p); -@t\4@>@@; -edge_node: confusion("LR2"); -@:this can't happen LR2}{\quad LR2@> -othercases goto next_p -endcases;@/ -cur_h:=cur_h+rule_wd; -next_p: link(p):=l; -if type(p)=kern_node then if (rule_wd=0)or(l=null) then - begin free_node(p,small_node_size); p:=l; - end; -l:=p; p:=q; -end - -@ Need to measure |native_word| and picture nodes when reversing! -@= -whatsit_node: - if (subtype(p)=native_word_node) - or (subtype(p)=glyph_node) - or (subtype(p)=pic_node) - or (subtype(p)=pdf_node) - then - rule_wd:=width(p) - else - goto next_p; - -@ Here we compute the effective width of a glue node as in |hlist_out|. - -@= -glue_node: begin round_glue; - @; - end; - -@ A ligature node is replaced by a char node. - -@= -ligature_node: begin flush_node_list(lig_ptr(p)); - temp_ptr:=p; p:=get_avail; mem[p]:=mem[lig_char(temp_ptr)]; link(p):=q; - free_node(temp_ptr,small_node_size); goto reswitch; - end; - -@ Math nodes in an inner reflected segment are modified, those at the -outer level are changed into kern nodes. - -@= -math_node: begin rule_wd:=width(p); -if end_LR(p) then - if info(LR_ptr)<>end_LR_type(p) then - begin type(p):=kern_node; incr(LR_problems); - end - else begin pop_LR; - if n>min_halfword then - begin decr(n); decr(subtype(p)); {change |after| into |before|} - end - else begin type(p):=kern_node; - if m>min_halfword then decr(m) - else @; - end; - end -else begin push_LR(p); - if (n>min_halfword)or(LR_dir(p)<>cur_dir) then - begin incr(n); incr(subtype(p)); {change |before| into |after|} - end - else begin type(p):=kern_node; incr(m); - end; - end; -end; - -@ Finally we have found the end of the hlist segment to be reversed; the -final math node is released and the remaining list attached to the -edge node terminating the reversed segment. - -@= -begin free_node(p,small_node_size); -link(t):=q; width(t):=rule_wd; edge_dist(t):=-cur_h-rule_wd; goto done; -end - -@ @= -begin if LR_problems>0 then - begin @; print_char(")"); print_ln; - end; -if (LR_ptr<>null)or(cur_dir<>left_to_right) then confusion("LR3"); -@:this can't happen LR3}{\quad LR3@> -end - -@ Some special actions are required for displayed equation in paragraphs -with mixed direction texts. First of all we have to set the text -direction preceding the display. - -@= -if LR_save=null then x:=0 -else if info(LR_save)>=R_code then x:=-1@+else x:=1 - -@ @= -begin pop_nest; @; -end - -@ When calculating the natural width, |w|, of the final line preceding -the display, we may have to copy all or part of its hlist. We copy, -however, only those parts of the original list that are relevant for the -computation of |pre_display_size|. -@^data structure assumptions@> - -@= -procedure just_copy(@!p,@!h,@!t:pointer); -label found,not_found; -var @!r:pointer; {current node being fabricated for new list} -@!words:0..5; {number of words remaining to be copied} -begin while p<>null do - begin words:=1; {this setting occurs in more branches than any other} - if is_char_node(p) then r:=get_avail - else case type(p) of - hlist_node,vlist_node: begin r:=get_node(box_node_size); - mem[r+6]:=mem[p+6]; mem[r+5]:=mem[p+5]; {copy the last two words} - words:=5; list_ptr(r):=null; {this affects |mem[r+5]|} - end; - rule_node: begin r:=get_node(rule_node_size); words:=rule_node_size; - end; - ligature_node: begin r:=get_avail; {only |font| and |character| are needed} - mem[r]:=mem[lig_char(p)]; goto found; - end; - kern_node,math_node: begin r:=get_node(small_node_size); - words:=small_node_size; - end; - glue_node: begin r:=get_node(small_node_size); add_glue_ref(glue_ptr(p)); - glue_ptr(r):=glue_ptr(p); leader_ptr(r):=null; - end; - whatsit_node:@; - othercases goto not_found - endcases; - while words>0 do - begin decr(words); mem[r+words]:=mem[p+words]; - end; - found: link(h):=r; h:=r; - not_found: p:=link(p); - end; -link(h):=t; -end; - -@ When the final line ends with R-text, the value |w| refers to the line -reflected with respect to the left edge of the enclosing vertical list. - -@= -if eTeX_ex then @; -v:=shift_amount(just_box); -@; -if x>=0 then - begin p:=list_ptr(just_box); link(temp_head):=null; - end -else begin v:=-v-width(just_box); - p:=new_math(0,begin_L_code); link(temp_head):=p; - just_copy(list_ptr(just_box),p,new_math(0,end_L_code)); - cur_dir:=right_to_left; - end; -v:=v+2*quad(cur_font); -if TeXXeT_en then @ - -@ @= -if TeXXeT_en then - begin while LR_ptr<>null do pop_LR; - if LR_problems<>0 then - begin w:=max_dimen; LR_problems:=0; - end; - end; -cur_dir:=left_to_right; flush_node_list(link(temp_head)) - -@ In the presence of text direction directives we assume that any LR -problems have been fixed by the |hpack| routine. If the final line -contains, however, text direction directives while \TeXXeT\ is disabled, -then we set |w:=max_dimen|. - -@= -math_node: begin d:=width(p); - if TeXXeT_en then @ - else if subtype(p)>=L_code then - begin w:=max_dimen; goto done; - end; - end; -edge_node: begin d:=width(p); cur_dir:=subtype(p); - end; - -@ @= -if end_LR(p) then - begin if info(LR_ptr)=end_LR_type(p) then pop_LR - else if subtype(p)>L_code then - begin w:=max_dimen; goto done; - end - end -else begin push_LR(p); - if LR_dir(p)<>cur_dir then - begin just_reverse(p); p:=temp_head; - end; - end - -@ @= -procedure just_reverse(@!p:pointer); -label found,done; -var l:pointer; {the new list} -@!t:pointer; {tail of reversed segment} -@!q:pointer; {the next node} -@!m,@!n:halfword; {count of unmatched math nodes} -begin m:=min_halfword; n:=min_halfword; -if link(temp_head)=null then - begin just_copy(link(p),temp_head,null); q:=link(temp_head); - end -else begin q:=link(p); link(p):=null; flush_node_list(link(temp_head)); - end; -t:=new_edge(cur_dir,0); l:=t; cur_dir:=reflected; -while q<>null do - if is_char_node(q) then - repeat p:=q; q:=link(p); link(p):=l; l:=p; - until not is_char_node(q) - else begin p:=q; q:=link(p); - if type(p)=math_node then - @; - link(p):=l; l:=p; - end; -goto done; -found:width(t):=width(p); link(t):=q; free_node(p,small_node_size); -done:link(temp_head):=l; -end; - -@ @= -if end_LR(p) then - if info(LR_ptr)<>end_LR_type(p) then - begin type(p):=kern_node; incr(LR_problems); - end - else begin pop_LR; - if n>min_halfword then - begin decr(n); decr(subtype(p)); {change |after| into |before|} - end - else begin if m>min_halfword then decr(m)@+else goto found; - type(p):=kern_node; - end; - end -else begin push_LR(p); - if (n>min_halfword)or(LR_dir(p)<>cur_dir) then - begin incr(n); incr(subtype(p)); {change |before| into |after|} - end - else begin type(p):=kern_node; incr(m); - end; - end - -@ The prototype box is an hlist node with the width, glue set, and shift -amount of |just_box|, i.e., the last line preceding the display. Its -hlist reflects the current \.{\\leftskip} and \.{\\rightskip}. - -@= -begin if right_skip=zero_glue then j:=new_kern(0) -else j:=new_param_glue(right_skip_code); -if left_skip=zero_glue then p:=new_kern(0) -else p:=new_param_glue(left_skip_code); -link(p):=j; j:=new_null_box; width(j):=width(just_box); -shift_amount(j):=shift_amount(just_box); list_ptr(j):=p; -glue_order(j):=glue_order(just_box); glue_sign(j):=glue_sign(just_box); -glue_set(j):=glue_set(just_box); -end - -@ At the end of a displayed equation we retrieve the prototype box. - -@= -@!j:pointer; {prototype box} - -@ @= -if mode=mmode then j:=LR_box - -@ @= -flush_node_list(j) - -@ The |app_display| procedure used to append the displayed equation -and\slash or equation number to the current vertical list has three -parameters: the prototype box, the hbox to be appended, and the -displacement of the hbox in the display line. - -@= -procedure app_display(@!j,@!b:pointer;@!d:scaled); -var z:scaled; {width of the line} -@!s:scaled; {move the line right this much} -@!e:scaled; {distance from right edge of box to end of line} -@!x:integer; {|pre_display_direction|} -@!p,@!q,@!r,@!t,@!u:pointer; {for list manipulation} -begin s:=display_indent; x:=pre_display_direction; -if x=0 then shift_amount(b):=s+d -else begin z:=display_width; p:=b; - @; - @; - end; -append_to_vlist(b); -end; - -@ Here we construct the hlist for the display, starting with node |p| -and ending with node |q|. We also set |d| and |e| to the amount of -kerning to be added before and after the hlist (adjusted for the -prototype box). - -@= -if x>0 then e:=z-d-width(p) -else begin e:=d; d:=z-e-width(p); - end; -if j<>null then - begin b:=copy_node_list(j); height(b):=height(p); depth(b):=depth(p); - s:=s-shift_amount(b); d:=d+s; e:=e+width(b)-z-s; - end; -if box_lr(p)=dlist then q:=p {display or equation number} -else begin {display and equation number} - r:=list_ptr(p); free_node(p,box_node_size); - if r=null then confusion("LR4"); - if x>0 then - begin p:=r; - repeat q:=r; r:=link(r); {find tail of list} - until r=null; - end - else begin p:=null; q:=r; - repeat t:=link(r); link(r):=p; p:=r; r:=t; {reverse list} - until r=null; - end; - end - -@ In the presence of a prototype box we use its shift amount and width -to adjust the values of kerning and add these values to the glue nodes -inserted to cancel the \.{\\leftskip} and \.{\\rightskip}. If there is -no prototype box (because the display is preceded by an empty -paragraph), or if the skip parameters are zero, we just add kerns. - -The |cancel_glue| macro creates and links a glue node that is, together -with another glue node, equivalent to a given amount of kerning. We can -use |j| as temporary pointer, since all we need is |j<>null|. - -@d cancel_glue(#)==j:=new_skip_param(#); cancel_glue_cont -@d cancel_glue_cont(#)==link(#):=j; cancel_glue_cont_cont -@d cancel_glue_cont_cont(#)==link(j):=#; cancel_glue_end -@d cancel_glue_end(#)==j:=glue_ptr(#); cancel_glue_end_end -@d cancel_glue_end_end(#)== -stretch_order(temp_ptr):=stretch_order(j); -shrink_order(temp_ptr):=shrink_order(j); width(temp_ptr):=#-width(j); -stretch(temp_ptr):=-stretch(j); shrink(temp_ptr):=-shrink(j) - -@= -if j=null then - begin r:=new_kern(0); t:=new_kern(0); {the widths will be set later} - end -else begin r:=list_ptr(b); t:=link(r); - end; -u:=new_math(0,end_M_code); -if type(t)=glue_node then {|t| is \.{\\rightskip} glue} - begin cancel_glue(right_skip_code)(q)(u)(t)(e); link(u):=t; - end -else begin width(t):=e; link(t):=u; link(q):=t; - end; -u:=new_math(0,begin_M_code); -if type(r)=glue_node then {|r| is \.{\\leftskip} glue} - begin cancel_glue(left_skip_code)(u)(p)(r)(d); link(r):=u; - end -else begin width(r):=d; link(r):=p; link(u):=r; - if j=null then - begin b:=hpack(u,natural); shift_amount(b):=s; - end - else list_ptr(b):=u; - end @ The |scan_tokens| feature of \eTeX\ defines the \.{\\scantokens} primitive. @@ -33302,6 +32517,124 @@ else begin if cur_val>penalty(equiv(m)) then cur_val:=penalty(equiv(m)); end; end +@ Now we do the main work required for mixed-direction texts. + +@= +hmode+LR,mmode+LR: begin new_whatsit(LR_node,small_node_size); LR_type(tail):=cur_chr; + end; + +@ A number of routines are based on a stack of one-word nodes whose |info| +fields contain either |begin_L_code| or |begin_R_code|. The top of the +stack is pointed to by |LR_ptr|, and an auxiliary variable |LR_tmp| is +available for stack manipulation. + +@= +@!LR_ptr,@!LR_tmp:pointer; {stack of LR codes and temp for manipulation} + +@ @= +function new_LR(@!s:small_number): pointer; +var p: pointer; {the new node} +begin p:=get_node(small_node_size); type(p):=whatsit_node; subtype(p):=LR_node; +LR_type(p):=s; new_LR:=p; +end; + +@ @= +function safe_info(@!p:pointer): integer; +begin if p=null then safe_info:=-1@+else safe_info:=info(p); +end; + +@ @= +tail_append(new_LR(begin_L_code)) + +@ @= +tail_append(new_LR(end_L_code)) + +@ When the stack-manipulation macros of this section are used below, variables +|LR_ptr| and |LR_tmp| might be the global variables declared above, or they +might be local to |hpack| or |post_line_break|. + +@d push_LR(#)==begin LR_tmp:=get_avail; info(LR_tmp):=LR_type(#); + link(LR_tmp):=LR_ptr; LR_ptr:=LR_tmp; + end +@d pop_LR==begin LR_tmp:=LR_ptr; LR_ptr:=link(LR_tmp); free_avail(LR_tmp); + end + +@=while LR_ptr<>null do pop_LR + +@ @= +while LR_ptr<>null do + begin LR_tmp:=new_LR(info(LR_ptr)); link(LR_tmp):=link(temp_head); + link(temp_head):=LR_tmp; pop_LR; + end + +@ @= +q:=link(temp_head); +while q<>cur_break(cur_p) do + begin if not is_char_node(q) then if type(q)=whatsit_node then + if subtype(q)=LR_node then + if begin_LR(q) then push_LR(q) + else if LR_ptr<>null then + if info(LR_ptr)=begin_LR_type(q) then pop_LR; + q:=link(q); + end + +@ We use the fact that |q| now points to the node with \.{\\rightskip} glue. + +@= +if LR_ptr<>null then + begin s:=temp_head; r:=link(s); + while r<>q do + begin s:=r; r:=link(s); + end; + r:=LR_ptr; + while r<>null do + begin LR_tmp:=new_LR(info(r)+end_L_code); + link(s):=LR_tmp; s:=LR_tmp; r:=link(r); + end; + link(s):=q; + end + +@ @= +if begin_LR(p) then push_LR(p) +else if safe_info(LR_ptr)=begin_LR_type(p) then pop_LR +else begin incr(LR_problems); + while link(q)<>p do q:=link(q); + link(q):=link(p); free_node(p,small_node_size); p:=q; + end + +@ @= +if LR_ptr<>null then + begin while link(q)<>null do q:=link(q); + repeat link(q):=new_LR(info(LR_ptr)+end_L_code); q:=link(q); + LR_problems:=LR_problems+10000; pop_LR; + until LR_ptr=null; + end; +if LR_problems>0 then + begin print_ln; print_nl("\endL or \endR problem (");@/ + print_int(LR_problems div 10000); print(" missing, ");@/ + print_int(LR_problems mod 10000); print(" extra");@/ + LR_problems:=0; goto common_ending; + end + +@ @d begin_reflect=0 {begin a reflcted segment value of |reflect| \.{XDV} command} +@d end_reflect=1 {end a reflcted segment value of |reflect| \.{XDV} command} + +@= +if begin_LR(p) then + begin if safe_info(LR_ptr)<>LR_type(p) then + begin synch_h; synch_v; dvi_out(reflect); dvi_out(begin_reflect); + end; + push_LR(p); + end +else if safe_info(LR_ptr)=begin_LR_type(p) then + begin pop_LR; + if info(LR_ptr)+end_L_code<>LR_type(p) then + begin synch_h; synch_v; dvi_out(reflect); dvi_out(end_reflect); + end; + end +else confusion("LR") +@:this can't happen LR}{\quad LR@> + @* \[54] System-dependent changes. This section should be replaced, if necessary, by any special modifications of the program -- cgit v1.2.3