summaryrefslogtreecommitdiff
path: root/source/luametatex/source/tex
diff options
context:
space:
mode:
Diffstat (limited to 'source/luametatex/source/tex')
-rw-r--r--source/luametatex/source/tex/texadjust.c2
-rw-r--r--source/luametatex/source/tex/texalign.c4
-rw-r--r--source/luametatex/source/tex/texbuildpage.c11
-rw-r--r--source/luametatex/source/tex/texcommands.c25
-rw-r--r--source/luametatex/source/tex/texcommands.h19
-rw-r--r--source/luametatex/source/tex/texconditional.c27
-rw-r--r--source/luametatex/source/tex/texconditional.h3
-rw-r--r--source/luametatex/source/tex/texdumpdata.h2
-rw-r--r--source/luametatex/source/tex/texequivalents.c2
-rw-r--r--source/luametatex/source/tex/texequivalents.h18
-rw-r--r--source/luametatex/source/tex/texexpand.c20
-rw-r--r--source/luametatex/source/tex/texinputstack.c7
-rw-r--r--source/luametatex/source/tex/texinserts.c2
-rw-r--r--source/luametatex/source/tex/texlinebreak.c1310
-rw-r--r--source/luametatex/source/tex/texlinebreak.h8
-rw-r--r--source/luametatex/source/tex/texlocalboxes.c4
-rw-r--r--source/luametatex/source/tex/texmaincontrol.c106
-rw-r--r--source/luametatex/source/tex/texmaincontrol.h2
-rw-r--r--source/luametatex/source/tex/texmath.c156
-rw-r--r--source/luametatex/source/tex/texmath.h2
-rw-r--r--source/luametatex/source/tex/texmlist.c54
-rw-r--r--source/luametatex/source/tex/texnodes.c52
-rw-r--r--source/luametatex/source/tex/texnodes.h57
-rw-r--r--source/luametatex/source/tex/texpackaging.c122
-rw-r--r--source/luametatex/source/tex/texprimitive.c6
-rw-r--r--source/luametatex/source/tex/texprinting.c3
-rw-r--r--source/luametatex/source/tex/texrules.c196
-rw-r--r--source/luametatex/source/tex/texrules.h5
-rw-r--r--source/luametatex/source/tex/texscanning.c29
-rw-r--r--source/luametatex/source/tex/texscanning.h3
-rw-r--r--source/luametatex/source/tex/textoken.c68
-rw-r--r--source/luametatex/source/tex/textypes.h1
32 files changed, 1432 insertions, 894 deletions
diff --git a/source/luametatex/source/tex/texadjust.c b/source/luametatex/source/tex/texadjust.c
index 11d2da6ad..775fd546d 100644
--- a/source/luametatex/source/tex/texadjust.c
+++ b/source/luametatex/source/tex/texadjust.c
@@ -161,7 +161,7 @@ void tex_run_vadjust(void)
void tex_finish_vadjust_group(void)
{
- if (! tex_wrapped_up_paragraph(vadjust_par_context)) {
+ if (! tex_wrapped_up_paragraph(vadjust_par_context, 0)) {
halfword box, adjust, target; /*tex for short-term use */
tex_end_paragraph(vadjust_group, vadjust_par_context);
tex_unsave();
diff --git a/source/luametatex/source/tex/texalign.c b/source/luametatex/source/tex/texalign.c
index 7a1045fea..e82a9eaae 100644
--- a/source/luametatex/source/tex/texalign.c
+++ b/source/luametatex/source/tex/texalign.c
@@ -837,7 +837,7 @@ static int tex_aux_nested_no_align(void)
void tex_finish_no_alignment_group(void)
{
- if (! tex_wrapped_up_paragraph(no_align_par_context)) { /* needs testing */
+ if (! tex_wrapped_up_paragraph(no_align_par_context, 0)) { /* needs testing */
tex_end_paragraph(no_align_group, no_align_par_context);
tex_aux_trace_no_align("leaving");
--lmt_alignment_state.no_align_level;
@@ -2091,7 +2091,7 @@ void tex_run_alignment_end_template(void)
} else if (lmt_input_state.input_stack[lmt_input_state.base_ptr].state != token_list_state) {
tex_alignment_interwoven_error(4);
} else if (cur_group == align_group) {
- if (! tex_wrapped_up_paragraph(align_par_context)) { /* needs testing */
+ if (! tex_wrapped_up_paragraph(align_par_context, 0)) { /* needs testing */
tex_end_paragraph(align_group, align_par_context);
if (tex_aux_finish_column()) {
tex_aux_finish_row();
diff --git a/source/luametatex/source/tex/texbuildpage.c b/source/luametatex/source/tex/texbuildpage.c
index be75042eb..5079e926e 100644
--- a/source/luametatex/source/tex/texbuildpage.c
+++ b/source/luametatex/source/tex/texbuildpage.c
@@ -363,6 +363,7 @@ void tex_build_page(void)
do {
halfword current = node_next(contribute_head);
halfword type = node_type(current);
+ halfword subtype = node_subtype(current);
/*tex Update the values of |last_glue|, |last_penalty|, and |last_kern|. */
if (lmt_page_builder_state.last_glue != max_halfword) {
tex_flush_node(lmt_page_builder_state.last_glue);
@@ -372,7 +373,7 @@ void tex_build_page(void)
lmt_page_builder_state.last_kern = 0;
lmt_page_builder_state.last_boundary = 0;
lmt_page_builder_state.last_node_type = type;
- lmt_page_builder_state.last_node_subtype = node_subtype(current);
+ lmt_page_builder_state.last_node_subtype = subtype;
lmt_page_builder_state.last_extra_used = 0;
switch (type) {
case glue_node:
@@ -385,7 +386,9 @@ void tex_build_page(void)
lmt_page_builder_state.last_kern = kern_amount(current);
break;
case boundary_node:
- lmt_page_builder_state.last_boundary = boundary_data(current);
+ if (subtype == page_boundary) {
+ lmt_page_builder_state.last_boundary = boundary_data(current);
+ }
break;
}
/*tex
@@ -725,9 +728,9 @@ void tex_build_page(void)
}
}
if (badness >= awful_bad) {
- criterium = badness;
+ criterium = badness; /* trigger fireup */
} else if (penalty <= eject_penalty) {
- criterium = penalty;
+ criterium = penalty; /* trigger fireup */
} else if (badness < infinite_bad) {
criterium = badness + penalty + lmt_page_builder_state.insert_penalties;
} else {
diff --git a/source/luametatex/source/tex/texcommands.c b/source/luametatex/source/tex/texcommands.c
index 3529f24d2..ddc57f0bd 100644
--- a/source/luametatex/source/tex/texcommands.c
+++ b/source/luametatex/source/tex/texcommands.c
@@ -87,10 +87,11 @@ void tex_initialize_commands(void)
tex_primitive(tex_command, "tabskip", internal_glue_cmd, tab_skip_code, internal_glue_base);
tex_primitive(tex_command, "spaceskip", internal_glue_cmd, space_skip_code, internal_glue_base);
tex_primitive(tex_command, "xspaceskip", internal_glue_cmd, xspace_skip_code, internal_glue_base);
- tex_primitive(tex_command, "parfillleftskip", internal_glue_cmd, par_fill_left_skip_code, internal_glue_base);
- tex_primitive(tex_command, "parfillskip", internal_glue_cmd, par_fill_right_skip_code, internal_glue_base);
- tex_primitive(tex_command, "parinitleftskip", internal_glue_cmd, par_init_left_skip_code, internal_glue_base);
- tex_primitive(tex_command, "parinitrightskip", internal_glue_cmd, par_init_right_skip_code, internal_glue_base);
+ tex_primitive(tex_command, "parfillskip", internal_glue_cmd, par_fill_right_skip_code, internal_glue_base); /*tex This is more like an alias now. */
+ tex_primitive(luatex_command, "parfillleftskip", internal_glue_cmd, par_fill_left_skip_code, internal_glue_base);
+ tex_primitive(luatex_command, "parfillrightskip", internal_glue_cmd, par_fill_right_skip_code, internal_glue_base);
+ tex_primitive(luatex_command, "parinitleftskip", internal_glue_cmd, par_init_left_skip_code, internal_glue_base);
+ tex_primitive(luatex_command, "parinitrightskip", internal_glue_cmd, par_init_right_skip_code, internal_glue_base);
tex_primitive(luatex_command, "mathsurroundskip", internal_glue_cmd, math_skip_code, internal_glue_base);
tex_primitive(luatex_command, "maththreshold", internal_glue_cmd, math_threshold_code, internal_glue_base);
@@ -164,6 +165,8 @@ void tex_initialize_commands(void)
tex_primitive(tex_command, "predisplaypenalty", internal_int_cmd, pre_display_penalty_code, internal_int_base);
tex_primitive(luatex_command, "postinlinepenalty", internal_int_cmd, post_inline_penalty_code, internal_int_base);
tex_primitive(luatex_command, "preinlinepenalty", internal_int_cmd, pre_inline_penalty_code, internal_int_base);
+ tex_primitive(luatex_command, "postshortinlinepenalty", internal_int_cmd, post_short_inline_penalty_code, internal_int_base);
+ tex_primitive(luatex_command, "preshortinlinepenalty", internal_int_cmd, pre_short_inline_penalty_code, internal_int_base);
tex_primitive(tex_command, "pretolerance", internal_int_cmd, pre_tolerance_code, internal_int_base);
tex_primitive(tex_command, "relpenalty", internal_int_cmd, post_relation_penalty_code, internal_int_base); /*tex For old times sake. */
tex_primitive(tex_command, "righthyphenmin", internal_int_cmd, right_hyphen_min_code, internal_int_base);
@@ -344,7 +347,9 @@ void tex_initialize_commands(void)
tex_primitive(luatex_command, "pageboundary", boundary_cmd, page_boundary, 0);
/* tex_primitive(luatex_command, "parboundary", boundary_cmd, par_boundary, 0); */
- tex_primitive(tex_command, "penalty", penalty_cmd, normal_code, 0);
+ tex_primitive(tex_command, "penalty", penalty_cmd, normal_penalty_code, 0);
+ tex_primitive(luatex_command, "hpenalty", penalty_cmd, h_penalty_code, 0);
+ tex_primitive(luatex_command, "vpenalty", penalty_cmd, v_penalty_code, 0);
tex_primitive(tex_command, "char", char_number_cmd, char_number_code, 0);
tex_primitive(luatex_command, "glyph", char_number_cmd, glyph_number_code, 0);
@@ -659,7 +664,6 @@ void tex_initialize_commands(void)
tex_primitive(luatex_command, "meaningasis", convert_cmd, meaning_asis_code, 0); /* for manuals and articles */
tex_primitive(luatex_command, "meaningful", convert_cmd, meaning_ful_code, 0); /* full as in fil */
tex_primitive(luatex_command, "meaningles", convert_cmd, meaning_les_code, 0); /* less as in fil, can't be less than this */
- /*tex Maybe some day also |meaningonly| (no macro: in front). */
tex_primitive(tex_command, "number", convert_cmd, number_code, 0);
tex_primitive(luatex_command, "tointeger", convert_cmd, to_integer_code, 0);
tex_primitive(luatex_command, "tohexadecimal", convert_cmd, to_hexadecimal_code, 0);
@@ -675,6 +679,7 @@ void tex_initialize_commands(void)
tex_primitive(luatex_command, "csactive", convert_cmd, cs_active_code, 0);
/* tex_primitive(luatex_command, "csnamestring", convert_cmd, cs_lastname_code, 0); */
tex_primitive(luatex_command, "detokenized", convert_cmd, detokenized_code, 0);
+ tex_primitive(luatex_command, "detokened", convert_cmd, detokened_code, 0);
tex_primitive(luatex_command, "expanded", convert_cmd, expanded_code, 0);
tex_primitive(luatex_command, "semiexpanded", convert_cmd, semi_expanded_code, 0);
tex_primitive(luatex_command, "formatname", convert_cmd, format_name_code, 0);
@@ -713,6 +718,9 @@ void tex_initialize_commands(void)
tex_primitive(luatex_command, "ifincsname", if_test_cmd, if_in_csname_code, 0); /* This is obsolete and might be dropped. */
tex_primitive(luatex_command, "ifabsnum", if_test_cmd, if_abs_int_code, 0);
tex_primitive(luatex_command, "ifabsdim", if_test_cmd, if_abs_dim_code, 0);
+ tex_primitive(luatex_command, "ifintervalnum", if_test_cmd, if_interval_int_code, 0); /* playground */
+ tex_primitive(luatex_command, "ifintervaldim", if_test_cmd, if_interval_dim_code, 0); /* playground */
+ tex_primitive(luatex_command, "ifintervalfloat", if_test_cmd, if_interval_posit_code, 0); /* playground */
tex_primitive(luatex_command, "iffloat", if_test_cmd, if_posit_code, 0);
tex_primitive(luatex_command, "ifabsfloat", if_test_cmd, if_abs_posit_code, 0);
tex_primitive(luatex_command, "ifzeronum", if_test_cmd, if_zero_int_code, 0);
@@ -832,8 +840,8 @@ void tex_initialize_commands(void)
tex_primitive(luatex_command, "hjcode", hyphenation_cmd, hjcode_code, 0);
tex_primitive(tex_command, "kern", kern_cmd, normal_kern_code, 0);
- /* tex_primitive(tex_command, "hkern", kern_cmd, h_kern_code, 0); */
- /* tex_primitive(tex_command, "vkern", kern_cmd, v_kern_code, 0); */
+ tex_primitive(tex_command, "hkern", kern_cmd, h_kern_code, 0);
+ tex_primitive(tex_command, "vkern", kern_cmd, v_kern_code, 0);
/* tex_primitive(tex_command, "nonzerowidthkern", kern_cmd, non_zero_width_kern_code, 0); */ /* maybe */
tex_primitive(luatex_command, "localleftbox", local_box_cmd, local_left_box_code, 0);
@@ -1026,7 +1034,6 @@ void tex_initialize_commands(void)
tex_primitive(tex_command, "muskipdef", shorthand_def_cmd, mu_skip_def_code, 0);
tex_primitive(tex_command, "skipdef", shorthand_def_cmd, skip_def_code, 0);
tex_primitive(tex_command, "toksdef", shorthand_def_cmd, toks_def_code, 0);
- /* tex_primitive(luatex_command, "stringdef", shorthand_def_cmd, string_def_code, 0); */
tex_primitive(luatex_command, "Umathchardef", shorthand_def_cmd, math_xchar_def_code, 0);
tex_primitive(luatex_command, "Umathdictdef", shorthand_def_cmd, math_dchar_def_code, 0);
tex_primitive(luatex_command, "attributedef", shorthand_def_cmd, attribute_def_code, 0);
diff --git a/source/luametatex/source/tex/texcommands.h b/source/luametatex/source/tex/texcommands.h
index d90456f25..372066049 100644
--- a/source/luametatex/source/tex/texcommands.h
+++ b/source/luametatex/source/tex/texcommands.h
@@ -55,6 +55,7 @@
*/
/*tex
+
Some commands are shared, for instance |car_ret_cmd| is never seen in a token list so it can be
used for signaling a parameter: |out_param_cmd| in a macro body. These constants relate to the
21 bit shifting in token properties!
@@ -89,6 +90,8 @@
easier to extend alignments when we're at it because it brings some code and logic together (of
course the principles are the same, but there can be slight differences in the way errors are
reported).
+
+ Comment: experimental |string_cmd| has been removed, as we now have |\constant| flagged macros.
*/
@@ -230,7 +233,6 @@ typedef enum tex_command_code {
mathspec_cmd,
fontspec_cmd,
register_cmd, /*tex internal register (|\count|, |\dimen|, etc.) */
- /* string_cmd, */ /*tex discarded experiment but maybe ... */
combine_toks_cmd, /*tex the |toksapp| and similar token (list) combiners */
/*tex
That was the last command that could follow |\the|.
@@ -260,7 +262,6 @@ typedef enum tex_command_code {
convert_cmd, /*tex convert to text (|\number|, |\string|, etc.) */
the_cmd, /*tex expand an internal quantity (|\the| or |\unexpanded|, |\detokenize|) */
get_mark_cmd, /*tex inserted mark (|\topmark|, etc.) */
- /* string_cmd, */
/*tex
These refer to macros. We might at some point promote the tolerant ones to have their own
cmd codes. Protected macros were done with an initial token signaling that property but
@@ -459,6 +460,7 @@ typedef enum convert_codes {
cs_active_code, /*tex command code for |\csactive| */
/* cs_lastname_code, */ /*tex command code for |\cslastname| */
detokenized_code, /*tex command code for |\detokenized| */
+ detokened_code, /*tex command code for |\detokened| */
roman_numeral_code, /*tex command code for |\romannumeral| */
meaning_code, /*tex command code for |\meaning| */
meaning_full_code, /*tex command code for |\meaningfull| */
@@ -702,7 +704,6 @@ typedef enum shorthand_def_codes {
skip_def_code, /*tex |\skipdef| */
mu_skip_def_code, /*tex |\muskipdef| */
toks_def_code, /*tex |\toksdef| */
- /* string_def_code, */
lua_def_code, /*tex |\luadef| */
integer_def_code,
posit_def_code,
@@ -1199,13 +1200,21 @@ typedef enum remove_item_codes {
typedef enum kern_codes {
normal_kern_code,
- h_kern_code, /* maybe */
- v_kern_code, /* maybe */
+ h_kern_code,
+ v_kern_code,
non_zero_width_kern_code, /* maybe */
} kern_codes;
# define last_kern_code normal_kern_code
+typedef enum penalty_codes {
+ normal_penalty_code,
+ h_penalty_code,
+ v_penalty_code,
+} penalty_codes;
+
+# define last_penalty_code normal_penalty_code
+
typedef enum tex_mskip_codes {
normal_mskip_code,
atom_mskip_code,
diff --git a/source/luametatex/source/tex/texconditional.c b/source/luametatex/source/tex/texconditional.c
index b2219e2ab..b4541f342 100644
--- a/source/luametatex/source/tex/texconditional.c
+++ b/source/luametatex/source/tex/texconditional.c
@@ -578,6 +578,15 @@ void tex_conditional_if(halfword code, int unless)
case if_zero_int_code:
result = tex_scan_int(0, NULL) == 0;
goto RESULT;
+ case if_interval_int_code:
+ {
+ scaled n0 = tex_scan_int(0, NULL);
+ scaled n1 = tex_scan_int(0, NULL);
+ scaled n2 = tex_scan_int(0, NULL);
+ result = n1 - n2;
+ result = result == 0 ? 1 : (result > 0 ? result <= n0 : -result <= n0);
+ }
+ goto RESULT;
case if_abs_posit_code:
case if_posit_code:
{
@@ -608,6 +617,15 @@ void tex_conditional_if(halfword code, int unless)
case if_zero_posit_code:
result = tex_posit_eq_zero(tex_scan_posit(0));
goto RESULT;
+ case if_interval_posit_code:
+ {
+ halfword n0 = tex_scan_posit(0);
+ halfword n1 = tex_scan_posit(0);
+ halfword n2 = tex_scan_posit(0);
+ result = tex_posit_sub(n1, n2);
+ result = tex_posit_eq_zero(result) ? 1 : (tex_posit_gt_zero(result) ? tex_posit_le(result, n0) : tex_posit_le(tex_posit_neg(result), n0));
+ }
+ goto RESULT;
case if_abs_dim_code:
case if_dim_code:
{
@@ -638,6 +656,15 @@ void tex_conditional_if(halfword code, int unless)
case if_zero_dim_code:
result = tex_scan_dimen(0, 0, 0, 0, NULL) == 0;
goto RESULT;
+ case if_interval_dim_code:
+ {
+ scaled n0 = tex_scan_dimen(0, 0, 0, 0, NULL);
+ scaled n1 = tex_scan_dimen(0, 0, 0, 0, NULL);
+ scaled n2 = tex_scan_dimen(0, 0, 0, 0, NULL);
+ result = n1 - n2;
+ result = result == 0 ? 1 : (result > 0 ? result <= n0 : -result <= n0);
+ }
+ goto RESULT;
case if_odd_code:
result = odd(tex_scan_int(0, NULL));
goto RESULT;
diff --git a/source/luametatex/source/tex/texconditional.h b/source/luametatex/source/tex/texconditional.h
index 41b33dc36..0790d86f9 100644
--- a/source/luametatex/source/tex/texconditional.h
+++ b/source/luametatex/source/tex/texconditional.h
@@ -55,12 +55,15 @@ typedef enum if_test_codes {
if_int_code, /*tex |\ifnum| */
if_abs_int_code, /*tex |\ifabsnum| */
if_zero_int_code, /*tex |\ifzeronum|*/
+ if_interval_int_code,
if_posit_code,
if_abs_posit_code,
if_zero_posit_code,
+ if_interval_posit_code,
if_dim_code, /*tex |\ifdim| */
if_abs_dim_code, /*tex |\ifabsdim| */
if_zero_dim_code, /*tex |\ifzerodim| */
+ if_interval_dim_code,
if_odd_code, /*tex |\ifodd| */
if_vmode_code, /*tex |\ifvmode| */
if_hmode_code, /*tex |\ifhmode| */
diff --git a/source/luametatex/source/tex/texdumpdata.h b/source/luametatex/source/tex/texdumpdata.h
index e21177713..be45c0045 100644
--- a/source/luametatex/source/tex/texdumpdata.h
+++ b/source/luametatex/source/tex/texdumpdata.h
@@ -55,7 +55,7 @@
*/
-# define luametatex_format_fingerprint 689
+# define luametatex_format_fingerprint 690
/* These end up in the string pool. */
diff --git a/source/luametatex/source/tex/texequivalents.c b/source/luametatex/source/tex/texequivalents.c
index c3cbf087d..4f8f789b7 100644
--- a/source/luametatex/source/tex/texequivalents.c
+++ b/source/luametatex/source/tex/texequivalents.c
@@ -1542,9 +1542,7 @@ void tex_unsave(void)
}
tex_local_control(1);
}
-
unsave_attribute_state_before();
-
tex_unsave_math_codes(cur_level);
tex_unsave_cat_codes(cat_code_table_par, cur_level);
tex_unsave_text_codes(cur_level);
diff --git a/source/luametatex/source/tex/texequivalents.h b/source/luametatex/source/tex/texequivalents.h
index a2ea8762d..5ecf73ee0 100644
--- a/source/luametatex/source/tex/texequivalents.h
+++ b/source/luametatex/source/tex/texequivalents.h
@@ -435,6 +435,8 @@ typedef enum int_codes {
post_display_penalty_code, /*tex penalty for breaking just after a displayed formula */
pre_inline_penalty_code, /*tex penalty for breaking just before an inlined formula */
post_inline_penalty_code, /*tex penalty for breaking just after an inlined formula */
+ pre_short_inline_penalty_code, /*tex penalty for breaking just before a single character inlined formula */
+ post_short_inline_penalty_code, /*tex penalty for breaking just after a single character inlined formula */
inter_line_penalty_code, /*tex additional penalty between lines */
double_hyphen_demerits_code, /*tex demerits for double hyphen break */
final_hyphen_demerits_code, /*tex demerits for final hyphen break */
@@ -1050,6 +1052,19 @@ typedef enum tex_alignment_context_codes {
wrapup_pass_alignment_context,
} tex_alignment_context_codes;
+
+typedef enum tex_breaks_context_codes {
+ initialize_show_breaks_context,
+ start_show_breaks_context,
+ list_show_breaks_context,
+ stop_show_breaks_context,
+ collect_show_breaks_context,
+ line_show_breaks_context,
+ delete_show_breaks_context,
+ report_show_breaks_context,
+ wrapup_show_breaks_context,
+} tex_breaks_context_codes;
+
typedef enum tex_page_context_codes {
box_page_context,
end_page_context,
@@ -1392,6 +1407,8 @@ extern void tex_forced_word_define (int g, halfword p, singleword flag, halfword
# define post_display_penalty_par count_parameter(post_display_penalty_code)
# define pre_inline_penalty_par count_parameter(pre_inline_penalty_code)
# define post_inline_penalty_par count_parameter(post_inline_penalty_code)
+# define pre_short_inline_penalty_par count_parameter(pre_short_inline_penalty_code)
+# define post_short_inline_penalty_par count_parameter(post_short_inline_penalty_code)
# define local_interline_penalty_par count_parameter(local_interline_penalty_code)
# define local_broken_penalty_par count_parameter(local_broken_penalty_code)
@@ -1664,6 +1681,7 @@ typedef enum normalize_line_mode_bits {
typedef enum normalize_par_mode_bits {
normalize_par_mode = 0x0001,
flatten_v_leaders_mode = 0x0002, /* used to be 0x200 */
+ limit_prev_graf_mode = 0x0004,
} normalize_par_mode_bits;
# define normalize_line_mode_permitted(a,b) ((a & b) == b)
diff --git a/source/luametatex/source/tex/texexpand.c b/source/luametatex/source/tex/texexpand.c
index 706972bfe..d0de0c9f1 100644
--- a/source/luametatex/source/tex/texexpand.c
+++ b/source/luametatex/source/tex/texexpand.c
@@ -535,14 +535,6 @@ void tex_expand_current_token(void)
}
break;
}
- /*
- case string_cmd:
- {
- halfword head = str_toks(str_lstring(cs_offset_value + cur_chr), NULL);
- begin_inserted_list(head);
- break;
- }
- */
default:
/* Maybe ... or maybe an option */
// if (lmt_expand_state.cs_name_level == 0) {
@@ -636,21 +628,13 @@ static int tex_aux_collect_cs_tokens(halfword *p, int *n)
case spacer_cmd:
case letter_cmd:
case other_char_cmd:
- case active_char_cmd: /* new */
- // cur_tok = token_val(cur_cmd, cur_chr);
- // *p = tex_store_new_token(*p, cur_tok);
+ case active_char_cmd: /* new, here we don't expand */
*p = tex_store_new_token(*p, token_val(cur_cmd, cur_chr));
*n += 1;
break;
/* case comment_cmd: */
/* case invalid_char_cmd: */
- /*
- case string_cmd:
- cur_tok = token_val(cur_cmd, cur_chr);
- *p = store_new_token(*p, cur_tok);
- *n += str_length(cs_offset_value + cur_chr);
- break;
- */
+ /* break; */
case call_cmd:
case tolerant_call_cmd:
if (get_token_reference(cur_chr) == max_token_reference) { // ! get_token_parameters(cur_chr)) {
diff --git a/source/luametatex/source/tex/texinputstack.c b/source/luametatex/source/tex/texinputstack.c
index 7780c17bc..92a9c8a0c 100644
--- a/source/luametatex/source/tex/texinputstack.c
+++ b/source/luametatex/source/tex/texinputstack.c
@@ -184,8 +184,15 @@ static int tex_aux_room_on_parameter_stack(void) /* quite similar to save_stack
void tex_copy_to_parameter_stack(halfword *pstack, int n)
{
if (tex_aux_room_on_parameter_stack()) {
+if (n == 1) {
+ lmt_input_state.parameter_stack[lmt_input_state.parameter_stack_data.ptr++] = pstack[0];
+//} else if (n == 2) {
+// lmt_input_state.parameter_stack[lmt_input_state.parameter_stack_data.ptr++] = pstack[0];
+// lmt_input_state.parameter_stack[lmt_input_state.parameter_stack_data.ptr++] = pstack[1];
+} else {
memcpy(&lmt_input_state.parameter_stack[lmt_input_state.parameter_stack_data.ptr], pstack, n * sizeof(halfword));
lmt_input_state.parameter_stack_data.ptr += n;
+}
}
}
diff --git a/source/luametatex/source/tex/texinserts.c b/source/luametatex/source/tex/texinserts.c
index 15d4b8c53..5a76ebaad 100644
--- a/source/luametatex/source/tex/texinserts.c
+++ b/source/luametatex/source/tex/texinserts.c
@@ -456,7 +456,7 @@ void tex_run_insert(void)
void tex_finish_insert_group(void)
{
- if (! tex_wrapped_up_paragraph(insert_par_context)) {
+ if (! tex_wrapped_up_paragraph(insert_par_context, 0)) {
halfword p, q; /*tex for short-term use */
scaled d; /*tex holds |split_max_depth| in |insert_group| */
halfword f; /*tex holds |floating_penalty| in |insert_group| */
diff --git a/source/luametatex/source/tex/texlinebreak.c b/source/luametatex/source/tex/texlinebreak.c
index af60f1c40..e009d3e50 100644
--- a/source/luametatex/source/tex/texlinebreak.c
+++ b/source/luametatex/source/tex/texlinebreak.c
@@ -53,6 +53,14 @@
understand. (Remark for myself: the lua variant that i use for playing around occasionally is
not in sync with the code here!)
+ I played a bit with prerolling: make a copy, run the par builder, afterwards collect the
+ result in a box that then can be consulted: wd, ht, dp, quality, hyphens, and especially
+ shape fitting (which was the reason, because |\hangafter| assumes lines and esp with math a
+ line is somewhat unpredictable so we get bad fitting). In the end we decided that it was kind
+ of useless because of the unlikely usage scenario. But I might pick up on it. Of course it can
+ be done in \LUA\ but we don't want the associated performance hit (management overhead) and
+ dealing with (progressive) solution oscillating is also an issue.
+
*/
linebreak_state_info lmt_linebreak_state = {
@@ -859,12 +867,14 @@ static halfword tex_aux_clean_up_the_memory(halfword p)
halfword q = node_next(active_head);
while (q != active_head) {
p = node_next(q);
+ // tex_free_node(q, get_node_size(node_type(q))); // less overhead & testing
tex_flush_node(q);
q = p;
}
q = lmt_linebreak_state.passive;
while (q) {
p = node_next(q);
+ // tex_free_node(q, get_node_size(node_type(q))); // less overhead & testing
tex_flush_node(q);
q = p;
}
@@ -907,12 +917,13 @@ inline static void tex_aux_reset_disc_target(halfword adjust_spacing, scaled *ta
inline static void tex_aux_set_target_to_source(halfword adjust_spacing, scaled target[], const scaled source[])
{
+ // memcpy(&target[total_glue_amount], &source[total_glue_amount], font_shrink_amount * sizeof(halfword));
for (int i = total_glue_amount; i <= total_shrink_amount; i++) {
target[i] = source[i];
}
if (adjust_spacing) {
- target[font_shrink_amount] = source[font_shrink_amount];
target[font_stretch_amount] = source[font_stretch_amount];
+ target[font_shrink_amount] = source[font_shrink_amount];
}
}
@@ -1040,7 +1051,7 @@ static void tex_aux_add_to_widths(halfword s, int adjust_spacing, int adjust_spa
while (s) {
switch (node_type(s)) {
case glyph_node:
- widths[total_glue_amount] += tex_glyph_width(s);
+ widths[total_glue_amount] += tex_glyph_width_ex(s); // ex
if (adjust_spacing && ! tex_has_glyph_option(s, glyph_option_no_expansion) && tex_aux_check_expand_pars(adjust_spacing_step, glyph_font(s))) {
lmt_packaging_state.previous_char_ptr = s;
widths[font_stretch_amount] += tex_char_stretch(s);
@@ -1056,7 +1067,7 @@ static void tex_aux_add_to_widths(halfword s, int adjust_spacing, int adjust_spa
break;
case glue_node:
widths[total_glue_amount] += glue_amount(s);
- widths[2 + glue_stretch_order(s)] += glue_stretch(s);
+ widths[total_stretch_amount + glue_stretch_order(s)] += glue_stretch(s);
widths[total_shrink_amount] += glue_shrink(s);
break;
case kern_node:
@@ -1093,7 +1104,7 @@ static void tex_aux_sub_from_widths(halfword s, int adjust_spacing, int adjust_s
/*tex Subtract the width of node |s| from |break_width|; */
switch (node_type(s)) {
case glyph_node:
- widths[total_glue_amount] -= tex_glyph_width(s);
+ widths[total_glue_amount] -= tex_glyph_width_ex(s); // ex
if (adjust_spacing && ! tex_has_glyph_option(s, glyph_option_no_expansion) && tex_aux_check_expand_pars(adjust_spacing_step, glyph_font(s))) {
lmt_packaging_state.previous_char_ptr = s;
widths[font_stretch_amount] -= tex_char_stretch(s);
@@ -1108,9 +1119,9 @@ static void tex_aux_sub_from_widths(halfword s, int adjust_spacing, int adjust_s
widths[total_glue_amount] -= rule_width(s);
break;
case glue_node:
- widths[total_glue_amount] -= glue_amount(s);
- widths[2 + glue_stretch_order(s)] -= glue_stretch(s);
- widths[total_shrink_amount] -= glue_shrink(s);
+ widths[total_glue_amount] -= glue_amount(s);
+ widths[total_stretch_amount + glue_stretch_order(s)] -= glue_stretch(s);
+ widths[total_shrink_amount] -= glue_shrink(s);
break;
case kern_node:
widths[total_glue_amount] -= kern_amount(s);
@@ -1205,7 +1216,7 @@ static void tex_aux_compute_break_width(int break_type, int adjust_spacing, int
case glue_node:
/*tex Subtract glue from |break_width|; */
lmt_linebreak_state.break_width[total_glue_amount] -= glue_amount(s);
- lmt_linebreak_state.break_width[2 + glue_stretch_order(s)] -= glue_stretch(s);
+ lmt_linebreak_state.break_width[total_stretch_amount + glue_stretch_order(s)] -= glue_stretch(s);
lmt_linebreak_state.break_width[total_shrink_amount] -= glue_shrink(s);
break;
case penalty_node:
@@ -1222,7 +1233,7 @@ static void tex_aux_compute_break_width(int break_type, int adjust_spacing, int
lmt_linebreak_state.break_width[total_glue_amount] -= math_surround(s);
} else {
lmt_linebreak_state.break_width[total_glue_amount] -= math_amount(s);
- lmt_linebreak_state.break_width[2 + math_stretch_order(s)] -= math_stretch(s);
+ lmt_linebreak_state.break_width[total_stretch_amount + math_stretch_order(s)] -= math_stretch(s);
lmt_linebreak_state.break_width[total_shrink_amount] -= math_shrink(s);
}
break;
@@ -1233,30 +1244,94 @@ static void tex_aux_compute_break_width(int break_type, int adjust_spacing, int
}
}
-static void tex_aux_print_break_node(halfword q, halfword fit_class, halfword break_type, halfword cur_p, const line_break_properties *properties)
+static void tex_aux_initialize_show_break_node(int callback_id)
+{
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "d->", initialize_show_breaks_context);
+}
+
+static void tex_aux_start_show_break_node(int callback_id, int pass)
+{
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dd->", start_show_breaks_context, pass);
+}
+
+static void tex_aux_stop_show_break_node(int callback_id)
+{
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "d->", stop_show_breaks_context);
+}
+
+static void tex_aux_collect_show_break_node(int callback_id)
+{
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "d->", collect_show_breaks_context);
+}
+
+static void tex_aux_line_show_break_node(int callback_id)
+{
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dNdddd->", line_show_breaks_context,
+ lmt_linebreak_state.just_box, lmt_packaging_state.last_badness, lmt_packaging_state.last_overshoot,
+ lmt_packaging_state.total_shrink[normal_glue_order], lmt_packaging_state.total_stretch[normal_glue_order]
+ );
+}
+
+static void tex_aux_delete_break_node(halfword active, halfword passive, int callback_id)
+{
+ (void) active;
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dd->", delete_show_breaks_context,
+ passive_serial(passive)
+ );
+}
+
+static void tex_aux_wrapup_show_break_node(int callback_id)
+{
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "d->", wrapup_show_breaks_context);
+}
+
+static void tex_aux_show_break_node(halfword active, halfword passive, int callback_id, int pass, halfword *demerits)
+{
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "ddddddddNdd->r", report_show_breaks_context,
+ pass,
+ passive_serial(passive),
+ passive_prev_break(passive) ? passive_serial(passive_prev_break(passive)) : 0,
+ active_line_number(active) - 1,
+ node_type(active),
+ active_fitness(active),
+ active_total_demerits(active), /* demerits */
+ passive_cur_break(passive),
+ lmt_linebreak_state.do_last_line_fit ? active_short(active) : 0,
+ lmt_linebreak_state.do_last_line_fit ? active_glue(active) : 0,
+ demerits /* optionally changed */
+ );
+}
+
+static void tex_aux_list_break_node(halfword passive, int callback_id)
+{
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dd->", list_show_breaks_context,
+ passive_serial(passive)
+ );
+}
+
+static void tex_aux_print_break_node(halfword active, halfword passive)
{
- (void) properties;
/*tex Print a symbolic description of the new break node. */
tex_print_format(
"%l[break: serial %i, line %i.%i,%s demerits %i, ",
- passive_serial(lmt_linebreak_state.passive),
- active_line_number(q) - 1,
- fit_class,
- break_type == hyphenated_node ? " hyphenated, " : "",
- active_total_demerits(q)
+ passive_serial(passive),
+ active_line_number(active) - 1,
+ active_fitness(active),
+ node_type(active) == hyphenated_node ? " hyphenated, " : "",
+ active_total_demerits(active)
);
if (lmt_linebreak_state.do_last_line_fit) {
/*tex Print additional data in the new active node. */
tex_print_format(
" short %D, %s %D, ",
- active_short(q), pt_unit,
- cur_p ? "glue" : "active",
- active_glue(q), pt_unit
+ active_short(active), pt_unit,
+ passive_cur_break(passive) ? "glue" : "active",
+ active_glue(active), pt_unit
);
}
tex_print_format(
"previous %i]",
- passive_prev_break(lmt_linebreak_state.passive) ? passive_serial(passive_prev_break(lmt_linebreak_state.passive)) : 0
+ passive_prev_break(passive) ? passive_serial(passive_prev_break(passive)) : null
);
}
@@ -1303,9 +1378,6 @@ static void tex_aux_print_feasible_break(halfword cur_p, halfword r, halfword b,
);
}
-# define total_font_stretch cur_active_width[font_stretch_amount]
-# define total_font_shrink cur_active_width[font_shrink_amount]
-
/*tex We implement this one later on. */
/*
@@ -1313,7 +1385,7 @@ static void tex_aux_print_feasible_break(halfword cur_p, halfword r, halfword b,
trickery depending on it.
*/
-static void tex_aux_post_line_break(const line_break_properties *properties, halfword line_break_dir);
+static void tex_aux_post_line_break(const line_break_properties *properties, halfword line_break_dir, int callback_id);
/*tex
@@ -1363,28 +1435,52 @@ static void tex_aux_post_line_break(const line_break_properties *properties, hal
good estimates from Don Knuth here, it would be pretentious to suggest that I really did
research this fuzzy topic (if it was worth the effort at all).
+ Here |large_width_excess| is 110.32996pt while |small_stretchability| equals 25.38295pt.
+
+*/
+
+/*tex
+ Around 2023-05-24 Mikael Sundqvist and I did numerous tests with the badness function below in
+ comparison with the variant mentioned in Digital Typography (DEK) and we observed that indeed
+ both functions behave pretty close (emulations with lua, mathematica etc). In practice one can
+ get different badness values (especially low numbers). We ran some test on documents and on
+ hundreds of pages one can get a few different decisions. The main reason for looking into this
+ was that we were exploring a bit more visual approach to deciding on what penalties to use in
+ the math inter-atom spacing in \CONTEXT\ (where we use a more granular class model). In the end
+ the magic criteria became even more magic (and impressive). BTW, indeed we could get these 1095
+ different badness cases with as maximum calculated one 8189.
*/
halfword tex_badness(scaled t, scaled s)
{
- /*tex Approximation to $\alpha t/s$, where $\alpha^3\approx 100\cdot2^{18}$ */
+ /*tex Approximation to $\alpha t/s$, where $\alpha^3 \approx 100 \cdot 2^{18}$ */
if (t == 0) {
return 0;
} else if (s <= 0) {
return infinite_bad;
} else {
- /*tex $297^3=99.94\times2^{18}$ */
- if (t <= large_width_excess) {
- t = (t * 297) / s;
- } else if (s >= small_stretchability) {
- t = t / (s / 297);
- }
- if (t > 1290) {
- /*tex $1290^3<2^{31}<1291^3$ */
+ /*tex $297^3 = 99.94 \times 2^{18}$ */
+ if (t <= large_width_excess) {
+ t = (t * 297) / s; /* clipping by integer division */
+ } else if (s >= small_stretchability) {
+ t = t / (s / 297); /* clipping by integer division */
+ } else {
+ /*tex
+ When we end up here |t| is pretty large so we can as well save a test and return
+ immediately. (HH & MS: we tested this while cheating a bit because this function
+ is seldom entered with values that make us end up here.)
+ */
+ return infinite_bad;
+ }
+ if (t > 1290) {
+ /*tex As $1290^3 < 2^{31} < 1291^3$ we catch an overflow here. */ /* actually badness 8189 */
return infinite_bad;
} else {
- /*tex This is $t^3/2^{18}$, rounded to the nearest integer. */
- return ((t * t * t + 0400000) / 01000000);
+ /*tex 297*297*297 == 26198073 / 100 => 261981 */
+ /*tex This is $t^3 / 2^{18}$, rounded to the nearest integer */
+ return (t * t * t + 0400000) / 01000000; /* 0400000/01000000 == 1/2 */
+ // return (t * t * t + 0x20000) / 0x40000;
+ // return (t * t * t + 131072) / 262144;
}
}
}
@@ -1410,13 +1506,6 @@ inline static void tex_split_line_break_criterium(halfword criterium, halfword *
inline static halfword tex_normalized_loose_badness(halfword b, halfword loose, halfword semi_loose, halfword decent)
{
- // if (b > loose_criterium) {
- // return very_loose_fit;
- // } else if (b > decent_criterium) {
- // return loose_fit;
- // } else {
- // return decent_fit;
- // }
if (b > loose) {
return very_loose_fit;
} else if (b > semi_loose) {
@@ -1430,11 +1519,6 @@ inline static halfword tex_normalized_loose_badness(halfword b, halfword loose,
inline static halfword tex_normalized_tight_badness(halfword b, halfword decent, halfword semi_tight)
{
- // if (b > decent_criterium) {
- // return tight_fit;
- // } else {
- // return decent_fit;
- // }
if (b > semi_tight) {
return semi_tight_fit;
} else if (b > decent) {
@@ -1444,78 +1528,134 @@ inline static halfword tex_normalized_tight_badness(halfword b, halfword decent,
}
}
+static void tex_check_protrusion_shortfall(halfword r, halfword first_p, halfword cur_p, halfword *shortfall)
+{
+ // if (line_break_dir == dir_righttoleft) {
+ // /*tex Not now, we need to keep more track. */
+ // } else {
+ halfword o = null;
+ halfword l = active_break_node(r) ? passive_cur_break(active_break_node(r)) : first_p;
+ if (cur_p) {
+ o = node_prev(cur_p);
+ if (node_next(o) != cur_p) {
+ tex_normal_error("linebreak", "the node list is messed up");
+ }
+ }
+ /*tex
+
+ The last characters (hyphenation character) if these two list should always be
+ the same anyway, so we just look at |pre_break|. Let's look at the right margin
+ first.
+
+ */
+ if (cur_p && node_type(cur_p) == disc_node && disc_pre_break_head(cur_p)) {
+ /*tex
+ A |disc_node| with non-empty |pre_break|, protrude the last char of
+ |pre_break|:
+ */
+ o = disc_pre_break_tail(cur_p);
+ } else {
+ o = tex_aux_find_protchar_right(l, o);
+ }
+ if (o && node_type(o) == glyph_node) {
+ shortfall += tex_char_protrusion(o, right_margin_kern_subtype);
+ // char_pw_kern(o, right_margin_kern, &margin_kern_stretch, &margin_kern_shrink);
+ }
+ /*tex now the left margin */
+ if (l && (node_type(l) == disc_node) && (disc_post_break_head(l))) {
+ /*tex The first char could be a disc! Protrude the first char. */
+ o = disc_post_break_head(l);
+ } else {
+ o = tex_aux_find_protchar_left(l, 1);
+ }
+ if (o && node_type(o) == glyph_node) {
+ shortfall += tex_char_protrusion(o, left_margin_kern_subtype);
+ // char_pw_kern(o, left_margin_kern, &margin_kern_stretch, &margin_kern_shrink);
+ }
+ // }
+}
+
static void tex_aux_try_break(
const line_break_properties *properties,
- halfword pi, /* a penalty */
+ halfword penalty,
halfword break_type,
halfword first_p,
- halfword cur_p
+ halfword cur_p,
+ int callback_id,
+ int pass
)
{
- /*tex runs through the active list */
- halfword r;
/*tex stays a step behind |r| */
halfword prev_r = active_head;
/*tex a step behind |prev_r|, if |type(prev_r) = delta_node| */
halfword prev_prev_r = null;
+ /*tex distance from current active node */
+ scaled cur_active_width[n_of_glue_amounts] = { 0 };
+ /*tex
+ These status arrays are global to the main loop and will be initialized as we go.
+ */
+ halfword best_place[n_of_finess_values];
+ halfword best_place_line[n_of_finess_values];
+ scaled best_place_short[n_of_finess_values];
+ scaled best_place_glue[n_of_finess_values];
+ /*
+ These are more local but we keep them here because of readability.
+ */
+ /*tex badness of test line */
+ halfword badness = 0;
+ /*tex demerits of test line */
+ int demerits = 0;
+ /*tex glue stretch or shrink of test line, adjustment for last line */
+ scaled glue = 0;
+ /*tex used in badness calculations */
+ scaled shortfall = 0;
/*tex maximum line number in current equivalence class of lines */
- halfword old_l = 0;
+ halfword old_line = 0;
/*tex have we found a feasible break at |cur_p|? */
int no_break_yet = 1;
- /*tex line number of current active node */
- halfword l;
/*tex should node |r| remain in the active list? */
int node_r_stays_active;
- /*tex the current line will be justified to this width */
- scaled line_width = 0;
/*tex possible fitness class of test line */
halfword fit_class;
- /*tex badness of test line */
- halfword b;
- /*tex demerits of test line */
- int d;
/*tex has |d| been forced to zero? */
int artificial_demerits;
- /*tex used in badness calculations */
- scaled shortfall = 0;
- /*tex glue stretch or shrink of test line, adjustment for last line */
- scaled g = 0;
- /*tex distance from current active node */
- scaled cur_active_width[10] = { 0 };
- halfword best_place[n_of_finess_values];
- halfword best_place_line[n_of_finess_values];
- scaled best_place_short[n_of_finess_values];
- scaled best_place_glue[n_of_finess_values];
- /*tex Experiment */
+ /*tex the current line will be justified to this width */
+ scaled line_width = 0;
+ /*tex line number of current active node */
+ halfword line = 0;
+ /*tex
+ We have added an extra category, just as experiment. In practice there is very little
+ to gain here as it becomes kind of fuzzy and DEK values are quite okay.
+ */
halfword semi_tight, decent, semi_loose, loose;
- /* in par node */
+ /*tex in par node */
tex_split_line_break_criterium(line_break_criterium_par, &semi_tight, &decent, &semi_loose, &loose);
/*tex Make sure that |pi| is in the proper range; */
- if (pi >= infinite_penalty) {
+ if (penalty >= infinite_penalty) {
/*tex this breakpoint is inhibited by infinite penalty */
return;
- } else if (pi <= -infinite_penalty) {
+ } else if (penalty <= -infinite_penalty) {
/*tex this breakpoint will be forced */
- pi = eject_penalty;
+ penalty = eject_penalty;
}
tex_aux_set_target_to_source(properties->adjust_spacing, cur_active_width, lmt_linebreak_state.active_width);
while (1) {
- r = node_next(prev_r);
+ /*tex Here |r| runs through the active list: */
+ halfword r = node_next(prev_r);
/*tex
If node |r| is of type |delta_node|, update |cur_active_width|, set |prev_r| and
|prev_prev_r|, then |goto continue|. The following code uses the fact that |type
(active) <> delta_node|.
- Here we get: |unhyphenated_node|, |hyphenated_node, |delta_node|, |passive_node|
-
*/
if (node_type(r) == delta_node) {
- /*tex implicit */
tex_aux_add_to_target_from_delta(properties->adjust_spacing, cur_active_width, r);
prev_prev_r = prev_r;
prev_r = r;
continue;
+ } else {
+ /*tex We have an |unhyphenated_node| or |hyphenated_node|. */
}
/*tex
@@ -1528,10 +1668,10 @@ static void tex_aux_try_break(
that |r = active| and |line_number (active) > old_l|.
*/
- l = active_line_number(r);
- if (l > old_l) {
- /*tex now we are no longer in the inner loop */
- if ((lmt_linebreak_state.minimum_demerits < awful_bad) && ((old_l != lmt_linebreak_state.easy_line) || (r == active_head))) {
+ line = active_line_number(r);
+ if (line > old_line) {
+ /*tex Now we are no longer in the inner loop (well ...). */
+ if ((lmt_linebreak_state.minimum_demerits < awful_bad) && ((old_line != lmt_linebreak_state.easy_line) || (r == active_head))) {
/*tex
Create new active nodes for the best feasible breaks just found. It is not
@@ -1578,53 +1718,55 @@ static void tex_aux_try_break(
Insert a new active node from |best_place [fit_class]| to |cur_p|. When
we create an active node, we also create the corresponding passive node.
+ In the passive node we also keep track of the subparagraph penalties.
*/
- halfword q = tex_new_node(passive_node, (quarterword) very_loose_fit);
- node_next(q) = lmt_linebreak_state.passive;
- lmt_linebreak_state.passive = q;
- passive_cur_break(q) = cur_p;
- ++lmt_linebreak_state.pass_number;
- passive_serial(q) = lmt_linebreak_state.pass_number;
- passive_prev_break(q) = best_place[fit_class];
- /*tex
-
- Here we keep track of the subparagraph penalties in the break nodes.
-
- */
- passive_pen_inter(q) = lmt_linebreak_state.internal_penalty_interline;
- passive_pen_broken(q) = lmt_linebreak_state.internal_penalty_broken;
- passive_last_left_box(q) = lmt_linebreak_state.internal_left_box;
- passive_last_left_box_width(q) = lmt_linebreak_state.internal_left_box_width;
- if (passive_prev_break(q)) {
- passive_left_box(q) = passive_last_left_box(passive_prev_break(q));
- passive_left_box_width(q) = passive_last_left_box_width(passive_prev_break(q));
+ halfword passive = tex_new_node(passive_node, (quarterword) very_loose_fit);
+ halfword active = tex_new_node((quarterword) break_type, (quarterword) fit_class);
+ halfword prev_break = best_place[fit_class];
+ /*tex Initialize the passive node: */
+ passive_cur_break(passive) = cur_p;
+ passive_serial(passive) = ++lmt_linebreak_state.pass_number;
+ passive_prev_break(passive) = prev_break;
+ passive_pen_inter(passive) = lmt_linebreak_state.internal_penalty_interline;
+ passive_pen_broken(passive) = lmt_linebreak_state.internal_penalty_broken;
+ passive_last_left_box(passive) = lmt_linebreak_state.internal_left_box;
+ passive_last_left_box_width(passive) = lmt_linebreak_state.internal_left_box_width;
+ if (prev_break) {
+ passive_left_box(passive) = passive_last_left_box(prev_break);
+ passive_left_box_width(passive) = passive_last_left_box_width(prev_break);
} else {
- passive_left_box(q) = lmt_linebreak_state.init_internal_left_box;
- passive_left_box_width(q) = lmt_linebreak_state.init_internal_left_box_width;
+ passive_left_box(passive) = lmt_linebreak_state.init_internal_left_box;
+ passive_left_box_width(passive) = lmt_linebreak_state.init_internal_left_box_width;
}
- passive_right_box(q) = lmt_linebreak_state.internal_right_box;
- passive_right_box_width(q) = lmt_linebreak_state.internal_right_box_width;
- passive_middle_box(q) = lmt_linebreak_state.internal_middle_box;
- q = tex_new_node((quarterword) break_type, (quarterword) fit_class);
- active_break_node(q) = lmt_linebreak_state.passive;
- active_line_number(q) = best_place_line[fit_class] + 1;
- active_total_demerits(q) = lmt_linebreak_state.minimal_demerits[fit_class];
+ passive_right_box(passive) = lmt_linebreak_state.internal_right_box;
+ passive_right_box_width(passive) = lmt_linebreak_state.internal_right_box_width;
+ passive_middle_box(passive) = lmt_linebreak_state.internal_middle_box;
+ /*tex Initialize the active node: */
+ active_break_node(active) = passive;
+ active_line_number(active) = best_place_line[fit_class] + 1;
+ active_total_demerits(active) = lmt_linebreak_state.minimal_demerits[fit_class];
+ // active_reserved(active) = lmt_linebreak_state.pass_number;
if (lmt_linebreak_state.do_last_line_fit) {
- /*tex
-
- Store additional data in the new active node. Here we save these
- data in the active node representing a potential line break.
-
- */
- active_short(q) = best_place_short[fit_class];
- active_glue(q) = best_place_glue[fit_class];
+ /*tex Store additional data in the new active node. */
+ active_short(active) = best_place_short[fit_class];
+ active_glue(active) = best_place_glue[fit_class];
+ }
+ /*tex Append the passive node. */
+ node_next(passive) = lmt_linebreak_state.passive;
+ lmt_linebreak_state.passive = passive;
+ /*tex Append the active node. */
+ node_next(active) = r;
+ node_next(prev_r) = active;
+ prev_r = active;
+ /* */
+ if (callback_id) {
+ halfword demerits = active_total_demerits(active);
+ tex_aux_show_break_node(active, passive, callback_id, pass, &demerits);
+ active_total_demerits(active) = demerits;
}
- node_next(q) = r;
- node_next(prev_r) = q;
- prev_r = q;
if (properties->tracing_paragraphs > 0) {
- tex_aux_print_break_node(q, fit_class, break_type, cur_p, properties);
+ tex_aux_print_break_node(active, passive);
}
}
lmt_linebreak_state.minimal_demerits[fit_class] = awful_bad;
@@ -1638,12 +1780,12 @@ static void tex_aux_try_break(
*/
if (r != active_head) {
- halfword q = tex_new_node(delta_node, (quarterword) very_loose_fit);
- node_next(q) = r;
- tex_aux_set_delta_from_difference(properties->adjust_spacing, q, cur_active_width, lmt_linebreak_state.break_width);
- node_next(prev_r) = q;
+ halfword delta = tex_new_node(delta_node, (quarterword) very_loose_fit);
+ node_next(delta) = r;
+ tex_aux_set_delta_from_difference(properties->adjust_spacing, delta, cur_active_width, lmt_linebreak_state.break_width);
+ node_next(prev_r) = delta;
prev_prev_r = prev_r;
- prev_r = q;
+ prev_r = delta;
}
}
/*tex
@@ -1657,17 +1799,17 @@ static void tex_aux_try_break(
*/
if (r == active_head) {
return;
- } else if (l > lmt_linebreak_state.easy_line) {
- old_l = max_halfword - 1;
+ } else if (line > lmt_linebreak_state.easy_line) {
+ old_line = max_halfword - 1;
line_width = lmt_linebreak_state.second_width;
} else {
- old_l = l;
+ old_line = line;
/* if (properties->par_shape && specification_repeat(properties->par_shape)) {
line_width = get_specification_width(properties->par_shape, l);
- } else */ if (l > lmt_linebreak_state.last_special_line) {
+ } else */ if (line > lmt_linebreak_state.last_special_line) {
line_width = lmt_linebreak_state.second_width;
} else if (properties->par_shape) {
- line_width = tex_get_specification_width(properties->par_shape, l);
+ line_width = tex_get_specification_width(properties->par_shape, line);
} else {
line_width = lmt_linebreak_state.first_width;
}
@@ -1694,49 +1836,7 @@ static void tex_aux_try_break(
// halfword margin_kern_stretch = 0;
// halfword margin_kern_shrink = 0;
if (properties->protrude_chars) {
- // if (line_break_dir == dir_righttoleft) {
- // /*tex Not now, we need to keep more track. */
- // } else {
- halfword o = null;
- halfword l1 = active_break_node(r) ? passive_cur_break(active_break_node(r)) : first_p;
- if (cur_p) {
- o = node_prev(cur_p);
- if (node_next(o) != cur_p) {
- tex_normal_error("linebreak", "the node list is messed up");
- }
- }
- /*tex
-
- The last characters (hyphenation character) if these two list should always be
- the same anyway, so we just look at |pre_break|. Let's look at the right margin
- first.
-
- */
- if (cur_p && node_type(cur_p) == disc_node && disc_pre_break_head(cur_p)) {
- /*tex
- A |disc_node| with non-empty |pre_break|, protrude the last char of
- |pre_break|:
- */
- o = disc_pre_break_tail(cur_p);
- } else {
- o = tex_aux_find_protchar_right(l1, o);
- }
- if (o && node_type(o) == glyph_node) {
- shortfall += tex_char_protrusion(o, right_margin_kern_subtype);
- // char_pw_kern(o, right_margin_kern, &margin_kern_stretch, &margin_kern_shrink);
- }
- /*tex now the left margin */
- if (l1 && (node_type(l1) == disc_node) && (disc_post_break_head(l1))) {
- /*tex The first char could be a disc! Protrude the first char. */
- o = disc_post_break_head(l1);
- } else {
- o = tex_aux_find_protchar_left(l1, 1);
- }
- if (o && node_type(o) == glyph_node) {
- shortfall += tex_char_protrusion(o, left_margin_kern_subtype);
- // char_pw_kern(o, left_margin_kern, &margin_kern_stretch, &margin_kern_shrink);
- }
- // }
+ tex_check_protrusion_shortfall(r, first_p, cur_p, &shortfall);
}
/*tex
The only reason why we have a shared ratio is that we need to calculate the shortfall
@@ -1745,8 +1845,8 @@ static void tex_aux_try_break(
if (shortfall == 0) {
/*tex We're okay. */
} else if (shortfall > 0) {
- halfword total_stretch = total_font_stretch;
- // halfword total_stretch = total_font_stretch + margin_kern_stretch;
+ halfword total_stretch = cur_active_width[font_stretch_amount];
+ // halfword total_stretch = cur_active_width[font_stretch_amount] + margin_kern_stretch;
if (total_stretch > 0) {
if (total_stretch > shortfall) {
shortfall = (total_stretch / (lmt_linebreak_state.max_stretch_ratio / lmt_linebreak_state.current_font_step)) / 2;
@@ -1755,11 +1855,11 @@ static void tex_aux_try_break(
}
}
} else if (shortfall < 0) {
- halfword total_shrink = total_font_shrink;
- // halfword total_shrink = total_font_shrink + margin_kern_shrink;
+ halfword total_shrink = cur_active_width[font_shrink_amount];
+ // halfword total_shrink = cur_active_width[font_shrink_amount] + margin_kern_shrink;
if (total_shrink > 0) {
if (total_shrink > -shortfall) {
- shortfall = - (total_shrink / (lmt_linebreak_state.max_shrink_ratio / lmt_linebreak_state.current_font_step)) / 2;
+ shortfall = - (total_shrink / (lmt_linebreak_state.max_shrink_ratio / lmt_linebreak_state.current_font_step)) / 2;
} else {
shortfall += total_shrink;
}
@@ -1809,23 +1909,23 @@ static void tex_aux_try_break(
goto NOT_FOUND;
}
if (active_short(r) > 0) {
- g = cur_active_width[total_stretch_amount];
+ glue = cur_active_width[total_stretch_amount];
} else {
- g = cur_active_width[total_shrink_amount];
+ glue = cur_active_width[total_shrink_amount];
}
- if (g <= 0) {
+ if (glue <= 0) {
/*tex No finite stretch resp.\ no shrink. */
goto NOT_FOUND;
}
lmt_scanner_state.arithmic_error = 0;
- g = tex_fract(g, active_short(r), active_glue(r), max_dimen);
+ glue = tex_fract(glue, active_short(r), active_glue(r), max_dimen);
if (properties->last_line_fit < 1000) {
- g = tex_fract(g, properties->last_line_fit, 1000, max_dimen);
+ glue = tex_fract(glue, properties->last_line_fit, 1000, max_dimen);
}
if (lmt_scanner_state.arithmic_error) {
- g = (active_short(r) > 0) ? max_dimen : -max_dimen;
+ glue = (active_short(r) > 0) ? max_dimen : -max_dimen;
}
- if (g > 0) {
+ if (glue > 0) {
/*tex
Set the value of |b| to the badness of the last line for stretching,
@@ -1834,44 +1934,44 @@ static void tex_aux_try_break(
algorithm, with the adjustment amount |g| replacing the |shortfall|.
*/
- if (g > shortfall) {
- g = shortfall;
+ if (glue > shortfall) {
+ glue = shortfall;
}
- if (g > large_width_excess && (cur_active_width[total_stretch_amount] < small_stretchability)) {
- b = infinite_bad;
+ if (glue > large_width_excess && (cur_active_width[total_stretch_amount] < small_stretchability)) {
+ badness = infinite_bad;
fit_class = very_loose_fit;
- goto FOUND;
+ } else {
+ badness = tex_badness(glue, cur_active_width[total_stretch_amount]);
+ fit_class = tex_normalized_loose_badness(badness, loose, semi_loose, decent);
}
- b = tex_badness(g, cur_active_width[total_stretch_amount]);
- fit_class = tex_normalized_loose_badness(b, loose, semi_loose, decent);
goto FOUND;
- } else if (g < 0) {
+ } else if (glue < 0) {
/*tex
Set the value of |b| to the badness of the last line for shrinking,
compute the corresponding |fit_class, and |goto found||.
*/
- if (-g > cur_active_width[total_shrink_amount]) {
- g = -cur_active_width[total_shrink_amount];
+ if (-glue > cur_active_width[total_shrink_amount]) {
+ glue = -cur_active_width[total_shrink_amount];
}
- b = tex_badness(-g, cur_active_width[total_shrink_amount]);
- fit_class = tex_normalized_tight_badness(b, decent, semi_tight);
+ badness = tex_badness(-glue, cur_active_width[total_shrink_amount]);
+ fit_class = tex_normalized_tight_badness(badness, decent, semi_tight);
goto FOUND;
}
}
NOT_FOUND:
shortfall = 0;
}
- b = 0;
+ badness = 0;
/*tex Infinite stretch. */
fit_class = decent_fit;
} else if (shortfall > large_width_excess && cur_active_width[total_stretch_amount] < small_stretchability) {
- b = infinite_bad;
+ badness = infinite_bad;
fit_class = very_loose_fit;
} else {
- b = tex_badness(shortfall, cur_active_width[total_stretch_amount]);
- fit_class = tex_normalized_loose_badness(b, loose, semi_loose, decent);
+ badness = tex_badness(shortfall, cur_active_width[total_stretch_amount]);
+ fit_class = tex_normalized_loose_badness(badness, loose, semi_loose, decent);
}
} else {
/*tex
@@ -1883,27 +1983,27 @@ static void tex_aux_try_break(
*/
if (-shortfall > cur_active_width[total_shrink_amount]) {
- b = infinite_bad + 1;
+ badness = infinite_bad + 1;
} else {
- b = tex_badness(-shortfall, cur_active_width[total_shrink_amount]);
+ badness = tex_badness(-shortfall, cur_active_width[total_shrink_amount]);
}
- fit_class = tex_normalized_tight_badness(b, decent, semi_tight);
+ fit_class = tex_normalized_tight_badness(badness, decent, semi_tight);
}
if (lmt_linebreak_state.do_last_line_fit) {
/*tex Adjust the additional data for last line; */
if (! cur_p) {
shortfall = 0;
- g = 0;
+ glue = 0;
} else if (shortfall > 0) {
- g = cur_active_width[total_stretch_amount];
+ glue = cur_active_width[total_stretch_amount];
} else if (shortfall < 0) {
- g = cur_active_width[total_shrink_amount];
+ glue = cur_active_width[total_shrink_amount];
} else {
- g = 0;
+ glue = 0;
}
}
FOUND:
- if ((b > infinite_bad) || (pi == eject_penalty)) {
+ if ((badness > infinite_bad) || (penalty == eject_penalty)) {
/*tex
Prepare to deactivate node~|r|, and |goto deactivate| unless there is a reason to
@@ -1916,17 +2016,16 @@ static void tex_aux_try_break(
changes here.
*/
- if (lmt_linebreak_state.final_pass && (lmt_linebreak_state.minimum_demerits == awful_bad) &&
- (node_next(r) == active_head) && (prev_r == active_head)) {
+ if (lmt_linebreak_state.final_pass && (lmt_linebreak_state.minimum_demerits == awful_bad) && (node_next(r) == active_head) && (prev_r == active_head)) {
/*tex Set demerits zero, this break is forced. */
artificial_demerits = 1;
- } else if (b > lmt_linebreak_state.threshold) {
+ } else if (badness > lmt_linebreak_state.threshold) {
goto DEACTIVATE;
}
node_r_stays_active = 0;
} else {
prev_r = r;
- if (b > lmt_linebreak_state.threshold) {
+ if (badness > lmt_linebreak_state.threshold) {
continue;
} else {
node_r_stays_active = 1;
@@ -1942,27 +2041,27 @@ static void tex_aux_try_break(
*/
if (artificial_demerits) {
- d = 0;
+ demerits = 0;
} else {
/*tex Compute the demerits, |d|, from |r| to |cur_p|. */
- d = properties->line_penalty + b;
- if (abs(d) >= 10000) {
- d = 100000000;
+ demerits = properties->line_penalty + badness;
+ if (abs(demerits) >= 10000) {
+ demerits = 100000000;
} else {
- d = d * d;
+ demerits = demerits * demerits;
}
- if (pi != 0) {
- if (pi > 0) {
- d += (pi * pi);
- } else if (pi > eject_penalty) {
- d -= (pi * pi);
+ if (penalty != 0) {
+ if (penalty > 0) {
+ demerits += (penalty * penalty);
+ } else if (penalty > eject_penalty) {
+ demerits -= (penalty * penalty);
}
}
if (break_type == hyphenated_node && node_type(r) == hyphenated_node) {
if (cur_p) {
- d += properties->double_hyphen_demerits;
+ demerits += properties->double_hyphen_demerits;
} else {
- d += properties->final_hyphen_demerits;
+ demerits += properties->final_hyphen_demerits;
}
}
/*tex
@@ -1972,18 +2071,18 @@ static void tex_aux_try_break(
used.
*/
if (abs(fit_class - (halfword) active_fitness(r)) > 1) {
- d = d + properties->adj_demerits;
+ demerits = demerits + properties->adj_demerits;
}
}
if (properties->tracing_paragraphs > 0) {
- tex_aux_print_feasible_break(cur_p, r, b, pi, d, artificial_demerits, properties);
+ tex_aux_print_feasible_break(cur_p, r, badness, penalty, demerits, artificial_demerits, properties);
}
/*tex This is the minimum total demerits from the beginning to |cur_p| via |r|. */
- d += active_total_demerits(r);
- if (d <= lmt_linebreak_state.minimal_demerits[fit_class]) {
- lmt_linebreak_state.minimal_demerits[fit_class] = d;
+ demerits += active_total_demerits(r);
+ if (demerits <= lmt_linebreak_state.minimal_demerits[fit_class]) {
+ lmt_linebreak_state.minimal_demerits[fit_class] = demerits;
best_place[fit_class] = active_break_node(r);
- best_place_line[fit_class] = l;
+ best_place_line[fit_class] = line;
if (lmt_linebreak_state.do_last_line_fit) {
/*tex
@@ -1992,10 +2091,10 @@ static void tex_aux_try_break(
*/
best_place_short[fit_class] = shortfall;
- best_place_glue[fit_class] = g;
+ best_place_glue[fit_class] = glue;
}
- if (d < lmt_linebreak_state.minimum_demerits) {
- lmt_linebreak_state.minimum_demerits = d;
+ if (demerits < lmt_linebreak_state.minimum_demerits) {
+ lmt_linebreak_state.minimum_demerits = demerits;
}
}
/*tex Record a new feasible break. */
@@ -2013,6 +2112,9 @@ static void tex_aux_try_break(
*/
node_next(prev_r) = node_next(r);
+ if (callback_id) {
+ tex_aux_delete_break_node(r, active_break_node(r), callback_id);
+ }
tex_flush_node(r);
if (prev_r == active_head) {
/*tex
@@ -2054,9 +2156,10 @@ static halfword tex_aux_inject_orphan_penalty(halfword current, halfword amount)
halfword penalty = tex_new_penalty_node(amount, orphan_penalty_subtype);
tex_couple_nodes(previous, penalty);
tex_couple_nodes(penalty, current);
- current = previous;
+ return previous;
+ } else {
+ return current;
}
- return current;
}
inline static int tex_aux_valid_glue_break(halfword p)
@@ -2065,13 +2168,47 @@ inline static int tex_aux_valid_glue_break(halfword p)
return (prv && prv != temp_head && (node_type(prv) == glyph_node || precedes_break(prv) || precedes_kern(prv) || precedes_dir(prv)));
}
+inline static halfword tex_aux_upcoming_penalty(halfword p) {
+ halfword n = node_next(p);
+ return (n && node_type(n) == math_node && node_subtype(n) == begin_inline_math) ? math_penalty(n) : 0;
+}
+
+/*tex
+
+ I played a bit with a height driven hanging indentation. One can store |cur_p| in the active
+ node and progressively calculate the height + depth and then act on that but in the end
+ interline space, adjustsm etc. also have to be taken into account and that all happens later
+ so in the end it makes no sense. There are valdi reasons why \TEX\ can't do some things
+ reliable: user demands are unpredictable.
+
+*/
+
+/*tex
+
+ Here we pickup the line number from |prev_graf| which relates to display math inside a
+ paragraph. A display formula is then considered to span three lines. Of course this also
+ assume a constant baseline distance with lines heigths not exceeding that amount. It also
+ assumes that the shape and hang are not reset. We check the prevgraf for a large value
+ because when we're close to |max_integer| we can wrap around due to addition beyond that
+ and negative values has side effects (see musings-sideffects) but it's optional so that we
+ can actually use these side effects.
+
+*/
+
+# define max_prev_graf (max_integer/2)
+
void tex_do_line_break(line_break_properties *properties)
{
/*tex Miscellaneous nodes of temporary interest. */
- halfword cur_p, l, r;
int line_break_dir = properties->paragraph_dir;
+ int callback_id = lmt_callback_defined(show_break_callback);
int force_check_hyphenation = hyphenation_permitted(properties->hyphenation_mode, force_check_hyphenation_mode);
(void) (properties->inter_line_penalties); /* avoid not used message */
+ /*tex Fix a buglet that probably is a feature. */
+ if ((cur_list.prev_graf > max_prev_graf || cur_list.prev_graf < 0) && normalize_par_mode_permitted(normalize_par_mode_par, limit_prev_graf_mode)) {
+ tex_formatted_warning("tex", "clipping prev_graf %i to %i", cur_list.prev_graf, max_prev_graf);
+ cur_list.prev_graf = max_prev_graf;
+ }
/*tex Get ready to start */
lmt_linebreak_state.fewest_demerits = 0;
lmt_linebreak_state.actual_looseness = 0;
@@ -2228,17 +2365,19 @@ void tex_do_line_break(line_break_properties *properties)
lmt_linebreak_state.easy_line = max_halfword;
}
lmt_linebreak_state.no_shrink_error_yet = 1;
- l = properties->left_skip;
- r = properties->right_skip;
- lmt_linebreak_state.background[total_glue_amount] = glue_amount(l) + glue_amount(r);
- lmt_linebreak_state.background[total_stretch_amount] = 0;
- lmt_linebreak_state.background[total_fi_amount] = 0;
- lmt_linebreak_state.background[total_fil_amount] = 0;
- lmt_linebreak_state.background[total_fill_amount] = 0;
- lmt_linebreak_state.background[total_filll_amount] = 0;
- lmt_linebreak_state.background[total_stretch_amount + glue_stretch_order(l)] = glue_stretch(l);
- lmt_linebreak_state.background[total_stretch_amount + glue_stretch_order(r)] += glue_stretch(r);
- lmt_linebreak_state.background[total_shrink_amount] = tex_aux_checked_shrink(l) + tex_aux_checked_shrink(r);
+ {
+ halfword l = properties->left_skip;
+ halfword r = properties->right_skip;
+ lmt_linebreak_state.background[total_glue_amount] = glue_amount(l) + glue_amount(r);
+ lmt_linebreak_state.background[total_stretch_amount] = 0;
+ lmt_linebreak_state.background[total_fi_amount] = 0;
+ lmt_linebreak_state.background[total_fil_amount] = 0;
+ lmt_linebreak_state.background[total_fill_amount] = 0;
+ lmt_linebreak_state.background[total_filll_amount] = 0;
+ lmt_linebreak_state.background[total_stretch_amount + glue_stretch_order(l)] = glue_stretch(l);
+ lmt_linebreak_state.background[total_stretch_amount + glue_stretch_order(r)] += glue_stretch(r);
+ lmt_linebreak_state.background[total_shrink_amount] = tex_aux_checked_shrink(l) + tex_aux_checked_shrink(r);
+ }
if (properties->adjust_spacing) {
lmt_linebreak_state.background[font_stretch_amount] = 0;
lmt_linebreak_state.background[font_shrink_amount] = 0;
@@ -2283,7 +2422,6 @@ void tex_do_line_break(line_break_properties *properties)
tex_short_display(node_next(temp_head));
tex_end_diagnostic();
}
-
if (lmt_linebreak_state.threshold >= 0) {
if (properties->tracing_paragraphs > 0) {
tex_begin_diagnostic();
@@ -2299,354 +2437,373 @@ void tex_do_line_break(line_break_properties *properties)
tex_begin_diagnostic();
}
}
- while (1) {
- halfword first_p, q;
- halfword nest_stack[10];
- int nest_index = 0;
- if (lmt_linebreak_state.threshold > infinite_bad) {
- lmt_linebreak_state.threshold = infinite_bad;
- }
- /*tex Create an active breakpoint representing the beginning of the paragraph. */
- q = tex_new_node(unhyphenated_node, (quarterword) decent_fit);
- node_next(q) = active_head;
- active_break_node(q) = null;
- active_line_number(q) = cur_list.prev_graf + 1;
- active_total_demerits(q) = 0;
- active_short(q) = 0;
- active_glue(q) = 0;
- node_next(active_head) = q; /* we create a cycle */
- tex_aux_set_target_to_source(properties->adjust_spacing, lmt_linebreak_state.active_width, lmt_linebreak_state.background);
- lmt_linebreak_state.passive = null;
- lmt_linebreak_state.printed_node = temp_head;
- lmt_linebreak_state.pass_number = 0;
- lmt_print_state.font_in_short_display = null_font;
- /*tex Create an active breakpoint representing the beginning of the paragraph. */
- /* lmt_linebreak_state.auto_breaking = 1; */ /* gone */
- cur_p = node_next(temp_head);
- /*tex Initialize with first (or current) |par| node. */
- if (cur_p && node_type(cur_p) == par_node) {
- node_prev(cur_p) = temp_head;
- lmt_linebreak_state.internal_penalty_interline = tex_get_local_interline_penalty(cur_p);
- lmt_linebreak_state.internal_penalty_broken = tex_get_local_broken_penalty(cur_p);
- lmt_linebreak_state.init_internal_left_box = par_box_left(cur_p);
- lmt_linebreak_state.init_internal_left_box_width = tex_get_local_left_width(cur_p);
- lmt_linebreak_state.internal_right_box = par_box_right(cur_p);
- lmt_linebreak_state.internal_right_box_width = tex_get_local_right_width(cur_p);
- lmt_linebreak_state.internal_middle_box = par_box_middle(cur_p);
- } else {
- lmt_linebreak_state.internal_penalty_interline = 0;
- lmt_linebreak_state.internal_penalty_broken = 0;
- lmt_linebreak_state.init_internal_left_box = null;
- lmt_linebreak_state.init_internal_left_box_width = 0;
- lmt_linebreak_state.internal_right_box = null;
- lmt_linebreak_state.internal_right_box_width = 0;
- lmt_linebreak_state.internal_middle_box = null;
- }
- lmt_linebreak_state.internal_left_box = lmt_linebreak_state.init_internal_left_box;
- lmt_linebreak_state.internal_left_box_width = lmt_linebreak_state.init_internal_left_box_width;
- lmt_packaging_state.previous_char_ptr = null;
- first_p = cur_p;
- /*tex
+ if (callback_id) {
+ tex_aux_initialize_show_break_node(callback_id);
+ }
+ {
+ halfword cur_p = null;
+ int pass = 0;
+ while (++pass) {
+ halfword first_p = node_next(temp_head);
+ cur_p = first_p;
+ if (lmt_linebreak_state.threshold > infinite_bad) {
+ lmt_linebreak_state.threshold = infinite_bad;
+ }
+ if (callback_id) {
+ tex_aux_start_show_break_node(callback_id, pass);
+ }
+ /*tex Create an active breakpoint representing the beginning of the paragraph. */
+ {
+ halfword initial = tex_new_node(unhyphenated_node, (quarterword) decent_fit);
+ node_next(initial) = active_head;
+ active_break_node(initial) = null;
+ active_line_number(initial) = cur_list.prev_graf + 1;
+ active_total_demerits(initial) = 0; // default
+ active_short(initial) = 0; // default
+ active_glue(initial) = 0; // default
+ // active_reserved(initial) = 0; // default
+ node_next(active_head) = initial;
+ }
+ /*tex We now have created a cycle. */
+ tex_aux_set_target_to_source(properties->adjust_spacing, lmt_linebreak_state.active_width, lmt_linebreak_state.background);
+ lmt_linebreak_state.passive = null;
+ lmt_linebreak_state.printed_node = temp_head;
+ lmt_linebreak_state.pass_number = 0;
+ lmt_print_state.font_in_short_display = null_font;
+ /*tex Create an active breakpoint representing the beginning of the paragraph. */
+ /* lmt_linebreak_state.auto_breaking = 1; */ /* gone */
+ // cur_p = node_next(temp_head);
+ /*tex Initialize with first (or current) |par| node. */
+ if (cur_p && node_type(cur_p) == par_node) {
+ node_prev(cur_p) = temp_head;
+ lmt_linebreak_state.internal_penalty_interline = tex_get_local_interline_penalty(cur_p);
+ lmt_linebreak_state.internal_penalty_broken = tex_get_local_broken_penalty(cur_p);
+ lmt_linebreak_state.init_internal_left_box = par_box_left(cur_p);
+ lmt_linebreak_state.init_internal_left_box_width = tex_get_local_left_width(cur_p);
+ lmt_linebreak_state.internal_right_box = par_box_right(cur_p);
+ lmt_linebreak_state.internal_right_box_width = tex_get_local_right_width(cur_p);
+ lmt_linebreak_state.internal_middle_box = par_box_middle(cur_p);
+ } else {
+ lmt_linebreak_state.internal_penalty_interline = 0;
+ lmt_linebreak_state.internal_penalty_broken = 0;
+ lmt_linebreak_state.init_internal_left_box = null;
+ lmt_linebreak_state.init_internal_left_box_width = 0;
+ lmt_linebreak_state.internal_right_box = null;
+ lmt_linebreak_state.internal_right_box_width = 0;
+ lmt_linebreak_state.internal_middle_box = null;
+ }
+ lmt_linebreak_state.internal_left_box = lmt_linebreak_state.init_internal_left_box;
+ lmt_linebreak_state.internal_left_box_width = lmt_linebreak_state.init_internal_left_box_width;
+ lmt_packaging_state.previous_char_ptr = null;
+ // first_p = cur_p;
+ /*tex
- To access the first node of paragraph as the first active node has |break_node = null|.
+ To access the first node of paragraph as the first active node has |break_node = null|.
- Determine legal breaks: As we move through the hlist, we need to keep the |active_width|
- array up to date, so that the badness of individual lines is readily calculated by
- |try_break|. It is convenient to use the short name |active_width [1]| for the component
- of active width that represents real width as opposed to glue.
+ Determine legal breaks: As we move through the hlist, we need to keep the |active_width|
+ array up to date, so that the badness of individual lines is readily calculated by
+ |try_break|. It is convenient to use the short name |active_width [1]| for the component
+ of active width that represents real width as opposed to glue.
- Advance |cur_p| to the node following the present string of characters. The code that
- passes over the characters of words in a paragraph is part of \TEX's inner loop, so it
- has been streamlined for speed. We use the fact that |\parfillskip| glue appears at the
- end of each paragraph; it is therefore unnecessary to check if |vlink (cur_p) = null|
- when |cur_p| is a character node.
+ Advance |cur_p| to the node following the present string of characters. The code that
+ passes over the characters of words in a paragraph is part of \TEX's inner loop, so it
+ has been streamlined for speed. We use the fact that |\parfillskip| glue appears at the
+ end of each paragraph; it is therefore unnecessary to check if |vlink (cur_p) = null|
+ when |cur_p| is a character node.
- */
- while (cur_p && (node_next(active_head) != active_head)) { /* we check the cycle */
- switch (node_type(cur_p)) {
- case glyph_node:
- lmt_linebreak_state.active_width[total_glue_amount] += tex_glyph_width_ex(cur_p);
- if (properties->adjust_spacing && tex_aux_check_expand_pars(properties->adjust_spacing_step, glyph_font(cur_p))) {
- lmt_packaging_state.previous_char_ptr = cur_p;
- lmt_linebreak_state.active_width[font_stretch_amount] += tex_char_stretch(cur_p);
- lmt_linebreak_state.active_width[font_shrink_amount] += tex_char_shrink(cur_p);
- }
- break;
- case hlist_node:
- case vlist_node:
- lmt_linebreak_state.active_width[total_glue_amount] += box_width(cur_p);
- break;
- case rule_node:
- lmt_linebreak_state.active_width[total_glue_amount] += rule_width(cur_p);
- break;
- case dir_node:
- /*tex Adjust the dir stack for the |line_break| routine. */
- line_break_dir = tex_update_dir_state(cur_p, properties->paragraph_dir);
- break;
- case par_node:
- /*tex Advance past a |par| node. */
- lmt_linebreak_state.internal_penalty_interline = tex_get_local_interline_penalty(cur_p);
- lmt_linebreak_state.internal_penalty_broken = tex_get_local_broken_penalty(cur_p);
- lmt_linebreak_state.internal_left_box = par_box_left(cur_p);
- lmt_linebreak_state.internal_left_box_width = tex_get_local_left_width(cur_p);
- lmt_linebreak_state.internal_right_box = par_box_right(cur_p);
- lmt_linebreak_state.internal_right_box_width = tex_get_local_right_width(cur_p);
- lmt_linebreak_state.internal_middle_box = par_box_middle(cur_p);
- break;
- case glue_node:
- /*tex
+ */
+ while (cur_p && (node_next(active_head) != active_head)) { /* we check the cycle */
+ switch (node_type(cur_p)) {
+ case glyph_node:
+ /* why ex here and not in add/sub disc glyphs */
+ lmt_linebreak_state.active_width[total_glue_amount] += tex_glyph_width_ex(cur_p); // ex
+ if (properties->adjust_spacing && tex_aux_check_expand_pars(properties->adjust_spacing_step, glyph_font(cur_p))) {
+ lmt_packaging_state.previous_char_ptr = cur_p;
+ lmt_linebreak_state.active_width[font_stretch_amount] += tex_char_stretch(cur_p);
+ lmt_linebreak_state.active_width[font_shrink_amount] += tex_char_shrink(cur_p);
+ }
+ break;
+ case hlist_node:
+ case vlist_node:
+ lmt_linebreak_state.active_width[total_glue_amount] += box_width(cur_p);
+ break;
+ case rule_node:
+ lmt_linebreak_state.active_width[total_glue_amount] += rule_width(cur_p);
+ break;
+ case dir_node:
+ /*tex Adjust the dir stack for the |line_break| routine. */
+ line_break_dir = tex_update_dir_state(cur_p, properties->paragraph_dir);
+ break;
+ case par_node:
+ /*tex Advance past a |par| node. */
+ lmt_linebreak_state.internal_penalty_interline = tex_get_local_interline_penalty(cur_p);
+ lmt_linebreak_state.internal_penalty_broken = tex_get_local_broken_penalty(cur_p);
+ lmt_linebreak_state.internal_left_box = par_box_left(cur_p);
+ lmt_linebreak_state.internal_left_box_width = tex_get_local_left_width(cur_p);
+ lmt_linebreak_state.internal_right_box = par_box_right(cur_p);
+ lmt_linebreak_state.internal_right_box_width = tex_get_local_right_width(cur_p);
+ lmt_linebreak_state.internal_middle_box = par_box_middle(cur_p);
+ break;
+ case glue_node:
+ /*tex
- If node |cur_p| is a legal breakpoint, call |try_break|; then update the
- active widths by including the glue in |glue_ptr(cur_p)|.
+ If node |cur_p| is a legal breakpoint, call |try_break|; then update the
+ active widths by including the glue in |glue_ptr(cur_p)|.
- When node |cur_p| is a glue node, we look at the previous to see whether or
- not a breakpoint is legal at |cur_p|, as explained above.
+ When node |cur_p| is a glue node, we look at the previous to see whether
+ or not a breakpoint is legal at |cur_p|, as explained above.
- We only break after certain nodes (see texnodes.h), a font related kern and
- a dir node when |\breakafterdirmode = 1|.
+ We only break after certain nodes (see texnodes.h), a font related kern
+ and a dir node when |\breakafterdirmode = 1|.
- */
- if (tex_has_glue_option(cur_p, glue_option_no_auto_break)) {
- /*tex Glue in math is not a valid breakpoint. */
- } else if (tex_is_par_init_glue(cur_p)) {
- /*tex Of course we don't break here. */
- } else if (tex_aux_valid_glue_break(cur_p)) {
- tex_aux_try_break(properties, 0, unhyphenated_node, first_p, cur_p);
- }
- lmt_linebreak_state.active_width[total_glue_amount] += glue_amount(cur_p);
- lmt_linebreak_state.active_width[2 + glue_stretch_order(cur_p)] += glue_stretch(cur_p);
- lmt_linebreak_state.active_width[total_shrink_amount] += tex_aux_checked_shrink(cur_p);
- break;
- case kern_node:
- switch (node_subtype(cur_p)) {
- case explicit_kern_subtype:
- case italic_kern_subtype:
- {
- /* there used to a ! is_char_node(node_next(cur_p)) test */
- halfword nxt = node_next(cur_p);
- if (nxt && node_type(nxt) == glue_node && ! tex_has_glue_option(nxt, glue_option_no_auto_break)) {
- tex_aux_try_break(properties, 0, unhyphenated_node, first_p, cur_p);
+ */
+ if (tex_has_glue_option(cur_p, glue_option_no_auto_break)) {
+ /*tex Glue in math is not a valid breakpoint, unless we permit it. */
+ } else if (tex_is_par_init_glue(cur_p)) {
+ /*tex Of course we don't break here. */
+ } else if (tex_aux_valid_glue_break(cur_p)) {
+ tex_aux_try_break(properties, tex_aux_upcoming_penalty(cur_p), unhyphenated_node, first_p, cur_p, callback_id, pass);
+ }
+ lmt_linebreak_state.active_width[total_glue_amount] += glue_amount(cur_p);
+ lmt_linebreak_state.active_width[total_stretch_amount + glue_stretch_order(cur_p)] += glue_stretch(cur_p);
+ lmt_linebreak_state.active_width[total_shrink_amount] += tex_aux_checked_shrink(cur_p);
+ break;
+ case kern_node:
+ switch (node_subtype(cur_p)) {
+ case explicit_kern_subtype:
+ case italic_kern_subtype:
+ {
+ /* there used to a ! is_char_node(node_next(cur_p)) test */
+ halfword nxt = node_next(cur_p);
+ if (nxt && node_type(nxt) == glue_node && ! tex_has_glue_option(nxt, glue_option_no_auto_break)) {
+ tex_aux_try_break(properties, 0, unhyphenated_node, first_p, cur_p, callback_id, pass);
+ }
}
- }
- break;
- case font_kern_subtype:
- if (properties->adjust_spacing == adjust_spacing_full) {
- lmt_linebreak_state.active_width[font_stretch_amount] += tex_kern_stretch(cur_p);
- lmt_linebreak_state.active_width[font_shrink_amount] += tex_kern_shrink(cur_p);
- }
- break;
- }
- lmt_linebreak_state.active_width[total_glue_amount] += kern_amount(cur_p);
- break;
- case disc_node:
- /*tex
-
- Try to break after a discretionary fragment, then |goto done5|. The
- following code knows that discretionary texts contain only character
- nodes, kern nodes, box nodes, and rule nodes. This branch differs a bit
- from older engines because in \LUATEX\ we already have hyphenated the list.
- This means that we need to skip automatic disc nodes. Or better, we need
- to treat discretionaries and explicit hyphens always, even in the first
- pass.
-
- We used to have |init_disc| followed by |select disc| variants where the
- |select_disc|s were handled by the leading |init_disc|. The question is: should
- we bother about select nodes? Knuth indicates in the original source that only
- a very few cases need hyphenation so the exceptional case of >2 char ligatures
- having hyphenation points in between is rare. We'd better have proper compound
- word handling. Keep in mind that these (old) init and select subtypes always
- came in isolated pairs and that they only were meant for the simple (enforced)
- hyphenation discretionaries.
-
- Therefore, this feature has been dropped from \LUAMETATEX. It not only makes
- the code simpler, it also avoids having code on board for border cases that
- even when dealt with are suboptimal. It's better to have nothing that something
- fuzzy. It also makes dealing with (intermediate) node lists easier. If I want
- something like this it should be okay for any situation.
-
- */
- if (force_check_hyphenation || lmt_linebreak_state.second_pass || (node_subtype(cur_p) != syllable_discretionary_code)) {
- halfword actual_penalty = disc_penalty(cur_p);
- halfword s = disc_pre_break_head(cur_p);
- tex_aux_reset_disc_target(properties->adjust_spacing, lmt_linebreak_state.disc_width);
- if (s) {
- tex_aux_add_to_widths(s, properties->adjust_spacing, properties->adjust_spacing_step, lmt_linebreak_state.disc_width);
- tex_aux_add_disc_source_to_target(properties->adjust_spacing, lmt_linebreak_state.active_width, lmt_linebreak_state.disc_width);
- tex_aux_try_break(properties, actual_penalty, hyphenated_node, first_p, cur_p);
- tex_aux_sub_disc_target_from_source(properties->adjust_spacing, lmt_linebreak_state.active_width, lmt_linebreak_state.disc_width);
- } else {
- /*tex trivial pre-break */
- tex_aux_try_break(properties, actual_penalty, hyphenated_node, first_p, cur_p);
+ break;
+ case font_kern_subtype:
+ if (properties->adjust_spacing == adjust_spacing_full) {
+ lmt_linebreak_state.active_width[font_stretch_amount] += tex_kern_stretch(cur_p);
+ lmt_linebreak_state.active_width[font_shrink_amount] += tex_kern_shrink(cur_p);
+ }
+ break;
}
- }
- tex_aux_add_to_widths(disc_no_break_head(cur_p), properties->adjust_spacing, properties->adjust_spacing_step, lmt_linebreak_state.active_width);
- break;
- case penalty_node:
- tex_aux_try_break(properties, penalty_amount(cur_p), unhyphenated_node, first_p, cur_p);
- break;
- case math_node:
- {
- /* there used to a ! is_char_node(node_next(cur_p)) test */
- int finishing = node_subtype(cur_p) == end_inline_math;
- // lmt_linebreak_state.auto_breaking = finishing;
- if (tex_math_glue_is_zero(cur_p) || tex_ignore_math_skip(cur_p)) {
- /*tex
- When we end up here we assume |\mathsurround| but we only check for
- a break when we're ending math. Maybe this is something we need to
- open up. The math specific penalty only kicks in when we break.
- */
- if (finishing && node_type(node_next(cur_p)) == glue_node) {
- tex_aux_try_break(properties, math_penalty(cur_p), unhyphenated_node, first_p, cur_p);
+ lmt_linebreak_state.active_width[total_glue_amount] += kern_amount(cur_p);
+ break;
+ case disc_node:
+ /*tex
+
+ Try to break after a discretionary fragment, then |goto done5|. The
+ following code knows that discretionary texts contain only character
+ nodes, kern nodes, box nodes, and rule nodes. This branch differs a bit
+ from older engines because in \LUATEX\ we already have hyphenated the list.
+ This means that we need to skip automatic disc nodes. Or better, we need
+ to treat discretionaries and explicit hyphens always, even in the first
+ pass.
+
+ We used to have |init_disc| followed by |select disc| variants where the
+ |select_disc|s were handled by the leading |init_disc|. The question is: should
+ we bother about select nodes? Knuth indicates in the original source that only
+ a very few cases need hyphenation so the exceptional case of >2 char ligatures
+ having hyphenation points in between is rare. We'd better have proper compound
+ word handling. Keep in mind that these (old) init and select subtypes always
+ came in isolated pairs and that they only were meant for the simple (enforced)
+ hyphenation discretionaries.
+
+ Therefore, this feature has been dropped from \LUAMETATEX. It not only makes
+ the code simpler, it also avoids having code on board for border cases that
+ even when dealt with are suboptimal. It's better to have nothing that something
+ fuzzy. It also makes dealing with (intermediate) node lists easier. If I want
+ something like this it should be okay for any situation.
+
+ */
+ if (force_check_hyphenation || lmt_linebreak_state.second_pass || (node_subtype(cur_p) != syllable_discretionary_code)) {
+ halfword actual_penalty = disc_penalty(cur_p);
+ halfword pre = disc_pre_break_head(cur_p);
+ tex_aux_reset_disc_target(properties->adjust_spacing, lmt_linebreak_state.disc_width);
+ if (pre) {
+ tex_aux_add_to_widths(pre, properties->adjust_spacing, properties->adjust_spacing_step, lmt_linebreak_state.disc_width);
+ tex_aux_add_disc_source_to_target(properties->adjust_spacing, lmt_linebreak_state.active_width, lmt_linebreak_state.disc_width);
+ tex_aux_try_break(properties, actual_penalty, hyphenated_node, first_p, cur_p, callback_id, pass);
+ tex_aux_sub_disc_target_from_source(properties->adjust_spacing, lmt_linebreak_state.active_width, lmt_linebreak_state.disc_width);
+ } else {
+ /*tex trivial pre-break */
+ tex_aux_try_break(properties, actual_penalty, hyphenated_node, first_p, cur_p, callback_id, pass);
}
- lmt_linebreak_state.active_width[total_glue_amount] += math_surround(cur_p);
- } else {
- /*tex
- This one does quite some testing, is that still needed?
- */
- if (finishing && tex_aux_valid_glue_break(cur_p)) {
- tex_aux_try_break(properties, math_penalty(cur_p), unhyphenated_node, first_p, cur_p);
+ }
+ tex_aux_add_to_widths(disc_no_break_head(cur_p), properties->adjust_spacing, properties->adjust_spacing_step, lmt_linebreak_state.active_width);
+ break;
+ case penalty_node:
+ tex_aux_try_break(properties, penalty_amount(cur_p), unhyphenated_node, first_p, cur_p, callback_id, pass);
+ break;
+ case math_node:
+ {
+ /* there used to a ! is_char_node(node_next(cur_p)) test */
+ int finishing = node_subtype(cur_p) == end_inline_math;
+ // lmt_linebreak_state.auto_breaking = finishing;
+ if (tex_math_glue_is_zero(cur_p) || tex_ignore_math_skip(cur_p)) {
+ /*tex
+ When we end up here we assume |\mathsurround| but we only check for
+ a break when we're ending math. Maybe this is something we need to
+ open up. The math specific penalty only kicks in when we break.
+ */
+ if (finishing && node_type(node_next(cur_p)) == glue_node) {
+ tex_aux_try_break(properties, math_penalty(cur_p), unhyphenated_node, first_p, cur_p, callback_id, pass);
+ }
+ lmt_linebreak_state.active_width[total_glue_amount] += math_surround(cur_p);
+ } else {
+ /*tex
+ This one does quite some testing, is that still needed?
+ */
+ if (finishing && tex_aux_valid_glue_break(cur_p)) {
+ tex_aux_try_break(properties, math_penalty(cur_p), unhyphenated_node, first_p, cur_p, callback_id, pass);
+ }
+ lmt_linebreak_state.active_width[total_glue_amount] += math_amount(cur_p);
+ lmt_linebreak_state.active_width[total_stretch_amount + math_stretch_order(cur_p)] += math_stretch(cur_p);
+ lmt_linebreak_state.active_width[total_shrink_amount] += tex_aux_checked_shrink(cur_p);
}
- lmt_linebreak_state.active_width[total_glue_amount] += math_amount(cur_p);
- lmt_linebreak_state.active_width[2 + math_stretch_order(cur_p)] += math_stretch(cur_p);
- lmt_linebreak_state.active_width[total_shrink_amount] += tex_aux_checked_shrink(cur_p);
}
- }
- break;
- case boundary_node:
- case whatsit_node:
- case mark_node:
- case insert_node:
- case adjust_node:
- /*tex Advance past these nodes in the |line_break| loop. */
- break;
- default:
- tex_formatted_error("parbuilder", "weird node %d in paragraph", node_type(cur_p));
- }
- cur_p = node_next(cur_p);
- while (! cur_p && nest_index > 0) {
- cur_p = nest_stack[--nest_index];
+ break;
+ case boundary_node:
+ case whatsit_node:
+ case mark_node:
+ case insert_node:
+ case adjust_node:
+ /*tex Advance past these nodes in the |line_break| loop. */
+ break;
+ default:
+ tex_formatted_error("parbuilder", "weird node %d in paragraph", node_type(cur_p));
+ }
+ cur_p = node_next(cur_p);
}
- }
- if (! cur_p) {
- /*tex
-
- Try the final line break at the end of the paragraph, and |goto done| if the desired
- breakpoints have been found.
-
- The forced line break at the paragraph's end will reduce the list of breakpoints so
- that all active nodes represent breaks at |cur_p = null|. On the first pass, we
- insist on finding an active node that has the correct \quote {looseness.} On the
- final pass, there will be at least one active node, and we will match the desired
- looseness as well as we can.
+ if (! cur_p) {
+ /*tex
- The global variable |best_bet| will be set to the active node for the best way to
- break the paragraph, and a few other variables are used to help determine what is
- best.
+ Try the final line break at the end of the paragraph, and |goto done| if the desired
+ breakpoints have been found.
- */
- tex_aux_try_break(properties, eject_penalty, hyphenated_node, first_p, cur_p);
- if (node_next(active_head) != active_head) {
- /*tex Find an active node with fewest demerits. */
- r = node_next(active_head);
- lmt_linebreak_state.fewest_demerits = awful_bad;
- do {
- if ((node_type(r) != delta_node) && (active_total_demerits(r) < lmt_linebreak_state.fewest_demerits)) {
- lmt_linebreak_state.fewest_demerits = active_total_demerits(r);
- lmt_linebreak_state.best_bet = r;
- }
- r = node_next(r);
- } while (r != active_head);
- lmt_linebreak_state.best_line = active_line_number(lmt_linebreak_state.best_bet);
- /*tex Find an active node with fewest demerits. */
- if (properties->looseness == 0) {
- goto DONE;
- } else {
- /*tex
+ The forced line break at the paragraph's end will reduce the list of breakpoints so
+ that all active nodes represent breaks at |cur_p = null|. On the first pass, we
+ insist on finding an active node that has the correct \quote {looseness.} On the
+ final pass, there will be at least one active node, and we will match the desired
+ looseness as well as we can.
- Find the best active node for the desired looseness. The adjustment for a
- desired looseness is a slightly more complicated version of the loop just
- considered. Note that if a paragraph is broken into segments by displayed
- equations, each segment will be subject to the looseness calculation,
- independently of the other segments.
+ The global variable |best_bet| will be set to the active node for the best way to
+ break the paragraph, and a few other variables are used to help determine what is
+ best.
- */
- r = node_next(active_head); // can be local
- lmt_linebreak_state.actual_looseness = 0;
+ */
+ tex_aux_try_break(properties, eject_penalty, hyphenated_node, first_p, cur_p, callback_id, pass);
+ if (node_next(active_head) != active_head) {
+ /*tex Find an active node with fewest demerits. */
+ halfword r = node_next(active_head);
+ lmt_linebreak_state.fewest_demerits = awful_bad;
do {
- if (node_type(r) != delta_node) {
- lmt_linebreak_state.line_difference = active_line_number(r) - lmt_linebreak_state.best_line;
- if (((lmt_linebreak_state.line_difference < lmt_linebreak_state.actual_looseness) && (properties->looseness <= lmt_linebreak_state.line_difference))
- || ((lmt_linebreak_state.line_difference > lmt_linebreak_state.actual_looseness) && (properties->looseness >= lmt_linebreak_state.line_difference))) {
- lmt_linebreak_state.best_bet = r;
- lmt_linebreak_state.actual_looseness = lmt_linebreak_state.line_difference;
- lmt_linebreak_state.fewest_demerits = active_total_demerits(r);
- } else if ((lmt_linebreak_state.line_difference == lmt_linebreak_state.actual_looseness) && (active_total_demerits(r) < lmt_linebreak_state.fewest_demerits)) {
- lmt_linebreak_state.best_bet = r;
- lmt_linebreak_state.fewest_demerits = active_total_demerits(r);
- }
+ if ((node_type(r) != delta_node) && (active_total_demerits(r) < lmt_linebreak_state.fewest_demerits)) {
+ lmt_linebreak_state.fewest_demerits = active_total_demerits(r);
+ lmt_linebreak_state.best_bet = r;
}
r = node_next(r);
} while (r != active_head);
lmt_linebreak_state.best_line = active_line_number(lmt_linebreak_state.best_bet);
- /*tex
- Find the best active node for the desired looseness.
- */
- if ((lmt_linebreak_state.actual_looseness == properties->looseness) || lmt_linebreak_state.final_pass) {
+ /*tex Find an active node with fewest demerits. */
+ if (properties->looseness == 0) {
goto DONE;
+ } else {
+ /*tex
+
+ Find the best active node for the desired looseness. The adjustment for a
+ desired looseness is a slightly more complicated version of the loop just
+ considered. Note that if a paragraph is broken into segments by displayed
+ equations, each segment will be subject to the looseness calculation,
+ independently of the other segments.
+
+ */
+ r = node_next(active_head); // can be local
+ lmt_linebreak_state.actual_looseness = 0;
+ do {
+ if (node_type(r) != delta_node) {
+ lmt_linebreak_state.line_difference = active_line_number(r) - lmt_linebreak_state.best_line;
+ if (((lmt_linebreak_state.line_difference < lmt_linebreak_state.actual_looseness) && (properties->looseness <= lmt_linebreak_state.line_difference))
+ || ((lmt_linebreak_state.line_difference > lmt_linebreak_state.actual_looseness) && (properties->looseness >= lmt_linebreak_state.line_difference))) {
+ lmt_linebreak_state.best_bet = r;
+ lmt_linebreak_state.actual_looseness = lmt_linebreak_state.line_difference;
+ lmt_linebreak_state.fewest_demerits = active_total_demerits(r);
+ } else if ((lmt_linebreak_state.line_difference == lmt_linebreak_state.actual_looseness) && (active_total_demerits(r) < lmt_linebreak_state.fewest_demerits)) {
+ lmt_linebreak_state.best_bet = r;
+ lmt_linebreak_state.fewest_demerits = active_total_demerits(r);
+ }
+ }
+ r = node_next(r);
+ } while (r != active_head);
+ lmt_linebreak_state.best_line = active_line_number(lmt_linebreak_state.best_bet);
+ /*tex
+ Find the best active node for the desired looseness.
+ */
+ if ((lmt_linebreak_state.actual_looseness == properties->looseness) || lmt_linebreak_state.final_pass) {
+ goto DONE;
+ }
}
}
+ } else {
+ /*tex So we have cycled: |node_next(active_head) == active_head|. */
+ }
+ /*tex Clean up the memory by removing the break nodes. */
+ cur_p = tex_aux_clean_up_the_memory(cur_p);
+ if (! lmt_linebreak_state.second_pass) {
+ if (properties->tracing_paragraphs > 0) {
+ tex_print_format("%l[linebreak: second pass]"); /* @secondpass */;
+ }
+ lmt_linebreak_state.threshold = properties->tolerance;
+ lmt_linebreak_state.second_pass = 1;
+ lmt_linebreak_state.final_pass = (properties->emergency_stretch <= 0);
+ } else {
+ /*tex If at first you do not succeed, then: */
+ if (properties->tracing_paragraphs > 0) {
+ tex_print_format("%l[linebreak: emergency pass]"); /* @emergencypass */
+ }
+ lmt_linebreak_state.background[total_stretch_amount] += properties->emergency_stretch;
+ lmt_linebreak_state.final_pass = 1;
}
- }
- /*tex Clean up the memory by removing the break nodes. */
- cur_p = tex_aux_clean_up_the_memory(cur_p);
- if (! lmt_linebreak_state.second_pass) {
- if (properties->tracing_paragraphs > 0) {
- tex_print_str("%l[linebreak: second pass]"); /* @secondpass */;
+ if (callback_id) {
+ tex_aux_stop_show_break_node(callback_id);
}
- lmt_linebreak_state.threshold = properties->tolerance;
- lmt_linebreak_state.second_pass = 1;
- lmt_linebreak_state.final_pass = (properties->emergency_stretch <= 0);
- } else {
- /*tex If at first you do not succeed, then: */
- if (properties->tracing_paragraphs > 0) {
- tex_print_str("%l[linebreak: emergency pass]"); /* @emergencypass */
+ }
+ DONE:
+ if (properties->tracing_paragraphs > 0) {
+ tex_end_diagnostic();
+ /*tex
+ This is a bit weird, as only here: |normalize_selector()| while we have diagnostics
+ all over the place.
+ */
+ }
+ if (lmt_linebreak_state.do_last_line_fit) {
+ /*tex
+ Adjust the final line of the paragraph; here we either reset |do_last_line_fit| or
+ adjust the |par_fill_skip| glue.
+ */
+ if (active_short(lmt_linebreak_state.best_bet) == 0) {
+ lmt_linebreak_state.do_last_line_fit = 0;
+ } else {
+ glue_amount(lmt_linebreak_state.last_line_fill) += (active_short(lmt_linebreak_state.best_bet) - active_glue(lmt_linebreak_state.best_bet));
+ glue_stretch(lmt_linebreak_state.last_line_fill) = 0;
}
- lmt_linebreak_state.background[total_stretch_amount] += properties->emergency_stretch;
- lmt_linebreak_state.final_pass = 1;
}
- }
- DONE:
- if (properties->tracing_paragraphs > 0) {
- tex_end_diagnostic();
/*tex
- This is a bit weird, as only here: |normalize_selector()| while we have diagnostics
- all over the place.
+ Break the paragraph at the chosen. Once the best sequence of breakpoints has been found
+ (hurray), we call on the procedure |post_line_break| to finish the remainder of the work.
+ By introducing this subprocedure, we are able to keep |line_break| from getting extremely
+ long. The first thing |ext_post_line_break| does is reset |dir_ptr|.
*/
+ tex_flush_node_list(lmt_linebreak_state.dir_ptr);
+ lmt_linebreak_state.dir_ptr = null;
+ /*tex Here we still have a temp node as head. */
+ tex_aux_post_line_break(properties, line_break_dir, callback_id);
+ /*tex Clean up memory by removing the break nodes (maybe: |tex_flush_node_list(cur_p);|). */
+ tex_aux_clean_up_the_memory(cur_p);
}
- if (lmt_linebreak_state.do_last_line_fit) {
- /*tex
- Adjust the final line of the paragraph; here we either reset |do_last_line_fit| or
- adjust the |par_fill_skip| glue.
- */
- if (active_short(lmt_linebreak_state.best_bet) == 0) {
- lmt_linebreak_state.do_last_line_fit = 0;
- } else {
- glue_amount(lmt_linebreak_state.last_line_fill) += (active_short(lmt_linebreak_state.best_bet) - active_glue(lmt_linebreak_state.best_bet));
- glue_stretch(lmt_linebreak_state.last_line_fill) = 0;
- }
+ if (callback_id) {
+ tex_aux_wrapup_show_break_node(callback_id);
}
- /*tex
- Break the paragraph at the chosen. Once the best sequence of breakpoints has been found
- (hurray), we call on the procedure |post_line_break| to finish the remainder of the work.
- By introducing this subprocedure, we are able to keep |line_break| from getting extremely
- long. The first thing |ext_post_line_break| does is reset |dir_ptr|.
- */
- tex_flush_node_list(lmt_linebreak_state.dir_ptr);
- lmt_linebreak_state.dir_ptr = null;
- /*tex Here we still have a temp node as head. */
- tex_aux_post_line_break(properties, line_break_dir);
- /*tex Clean up the memory by removing the break nodes. */
- cur_p = tex_aux_clean_up_the_memory(cur_p);
}
void tex_get_linebreak_info(int *f, int *a)
@@ -2698,7 +2855,7 @@ static void tex_aux_trace_penalty(const char *what, int line, int index, halfwor
}
}
-static void tex_aux_post_line_break(const line_break_properties *properties, halfword line_break_dir)
+static void tex_aux_post_line_break(const line_break_properties *properties, halfword line_break_dir, int callback_id)
{
/*tex temporary registers for list manipulation */
halfword q, r;
@@ -2733,6 +2890,9 @@ static void tex_aux_post_line_break(const line_break_properties *properties, hal
and having |next_break| fields. Node |r| is the passive node being moved from stack to
stack.
*/
+ if (callback_id) {
+ tex_aux_collect_show_break_node(callback_id);
+ }
q = active_break_node(lmt_linebreak_state.best_bet);
do {
r = q;
@@ -2740,6 +2900,13 @@ static void tex_aux_post_line_break(const line_break_properties *properties, hal
passive_next_break(r) = cur_p;
cur_p = r;
} while (q);
+ if (callback_id) {
+ halfword p = cur_p;
+ while (p) {
+ tex_aux_list_break_node(p, callback_id);
+ p = passive_next_break(p);
+ }
+ }
/*tex prevgraf + 1 */
cur_line = cur_list.prev_graf + 1;
do {
@@ -3310,6 +3477,9 @@ static void tex_aux_post_line_break(const line_break_properties *properties, hal
}
/*tex Call the packaging subroutine, setting |just_box| to the justified box. */
node_subtype(lmt_linebreak_state.just_box) = line_list;
+ if (callback_id) {
+ tex_aux_line_show_break_node(callback_id);
+ }
/*tex Pending content (callback). */
if (node_next(contribute_head)) {
if (! lmt_page_builder_state.output_active) {
@@ -3504,6 +3674,10 @@ static void tex_aux_post_line_break(const line_break_properties *properties, hal
while (1) {
q = node_next(r);
if (node_type(q) == math_node) {
+ if (node_subtype(q) == begin_inline_math) {
+ /*tex We keep it for tracing. */
+ break;
+ }
/*tex begin mathskip code */
math_surround(q) = 0 ;
tex_reset_math_glue_to_zero(q);
@@ -3517,7 +3691,7 @@ static void tex_aux_post_line_break(const line_break_properties *properties, hal
/*tex Keep it. Can be tricky after a |\break| with no follow up (loops). */
break;
} else if (node_type(q) == par_node && node_subtype(q) == local_box_par_subtype) {
- /*tex weird, in the middle somewhere .. these local penalties do this */
+ /*tex Weird, in the middle somewhere .. these local penalties do this. */
break; /* if not we leak, so maybe this needs more testing */
} else if (non_discardable(q)) {
break;
diff --git a/source/luametatex/source/tex/texlinebreak.h b/source/luametatex/source/tex/texlinebreak.h
index 789101999..850d98da0 100644
--- a/source/luametatex/source/tex/texlinebreak.h
+++ b/source/luametatex/source/tex/texlinebreak.h
@@ -79,10 +79,10 @@ typedef struct linebreak_state_info {
halfword pass_number;
/* int auto_breaking; */ /* is gone */
/* int math_level; */ /* was never used */
- scaled active_width[10];
- scaled background[10];
- scaled break_width[10];
- scaled disc_width[10];
+ scaled active_width[n_of_glue_amounts];
+ scaled background[n_of_glue_amounts];
+ scaled break_width[n_of_glue_amounts];
+ scaled disc_width[n_of_glue_amounts];
scaled fill_width[4];
halfword internal_penalty_interline;
halfword internal_penalty_broken;
diff --git a/source/luametatex/source/tex/texlocalboxes.c b/source/luametatex/source/tex/texlocalboxes.c
index 0def018d4..1bcc25bc0 100644
--- a/source/luametatex/source/tex/texlocalboxes.c
+++ b/source/luametatex/source/tex/texlocalboxes.c
@@ -295,19 +295,23 @@ void tex_set_local_right_width(halfword p, scaled width)
halfword tex_get_local_interline_penalty(halfword p)
{
return par_penalty_interline(p);
+ // return par_inter_line_penalty(p);
}
halfword tex_get_local_broken_penalty(halfword p)
{
return par_penalty_broken(p);
+ // return par_broken_penalty(p);
}
void tex_set_local_interline_penalty(halfword p, halfword penalty)
{
par_penalty_interline(p) = penalty;
+ // par_inter_line_penalty(p) = penalty;
}
void tex_set_local_broken_penalty(halfword p, halfword penalty)
{
par_penalty_broken(p) = penalty;
+ // par_broken_penalty(p) = penalty;
}
diff --git a/source/luametatex/source/tex/texmaincontrol.c b/source/luametatex/source/tex/texmaincontrol.c
index 3989dfff0..0489b67ac 100644
--- a/source/luametatex/source/tex/texmaincontrol.c
+++ b/source/luametatex/source/tex/texmaincontrol.c
@@ -1161,9 +1161,9 @@ static void tex_aux_run_par_boundary(void) {
{
halfword n = tex_scan_int(0, NULL);
if (lmt_nest_state.nest_data.ptr == 0 && ! lmt_page_builder_state.output_active) {
- halfword n = tex_new_node(boundary_node, (quarterword) cur_chr);
- boundary_data(n) = n;
- tex_tail_append(n);
+ halfword boundary = tex_new_node(boundary_node, page_boundary);
+ boundary_data(boundary) = n;
+ tex_tail_append(boundary);
if (cur_list.mode == vmode) {
if (! lmt_page_builder_state.output_active) {
tex_page_boundary_message("callback triggered", n);
@@ -1182,9 +1182,9 @@ static void tex_aux_run_par_boundary(void) {
/*tex Not yet, first I need a proper use case. */ /*
case par_boundary:
{
- halfword n = tex_new_node(boundary_node, (quarterword) cur_chr);
- boundary_data(n) = tex_scan_int(0, NULL);
- tex_tail_append(n);
+ halfword boundary = tex_new_node(boundary_node, par_boundary);
+ boundary_data(boundary) = tex_scan_int(0, NULL);
+ tex_tail_append(boundary);
break;
}
*/
@@ -1196,20 +1196,20 @@ static void tex_aux_run_par_boundary(void) {
}
static void tex_aux_run_text_boundary(void) {
- halfword n = tex_new_node(boundary_node, (quarterword) cur_chr);
+ halfword boundary = tex_new_node(boundary_node, (quarterword) cur_chr);
switch (cur_chr) {
case user_boundary:
case protrusion_boundary:
- boundary_data(n) = tex_scan_int(0, NULL);
+ boundary_data(boundary) = tex_scan_int(0, NULL);
break;
case page_boundary:
- /* or maybe force vmode */
+ /*tex Maybe we should force vmode? For now we just ignore the value. */
tex_scan_int(0, NULL);
break;
default:
break;
}
- tex_tail_append(n);
+ tex_tail_append(boundary);
}
static void tex_aux_run_math_boundary(void) {
@@ -1223,6 +1223,7 @@ static void tex_aux_run_math_boundary(void) {
}
case protrusion_boundary:
case page_boundary:
+ /*tex We just ignore the values. */
tex_scan_int(0, NULL);
break;
}
@@ -1248,7 +1249,7 @@ static void tex_aux_run_paragraph_end_vmode(void) {
/*tex We could pass the group and context here if needed and set some parameter. */
-int tex_wrapped_up_paragraph(int context) {
+int tex_wrapped_up_paragraph(int context, int final) {
halfword par = tex_find_par_par(cur_list.head);
lmt_main_control_state.last_par_context = context;
if (par) {
@@ -1263,14 +1264,14 @@ int tex_wrapped_up_paragraph(int context) {
tex_delete_token_reference(eop);
done = 1;
}
- // if (end_of_par_par) {
- // if (! done) {
- // back_input(cur_tok);
- // }
- // begin_token_list(end_of_par_par, end_paragraph_text);
- // update_tex_end_of_par(null);
- // done = 1;
- // }
+ if (final && end_of_group_par) {
+ if (! done) {
+ tex_back_input(cur_tok);
+ }
+ tex_begin_token_list(end_of_group_par, end_paragraph_text);
+ update_tex_end_of_group(null);
+ done = 1;
+ }
return done;
} else {
return 0;
@@ -1278,7 +1279,7 @@ int tex_wrapped_up_paragraph(int context) {
}
static void tex_aux_run_paragraph_end_hmode(void) {
- if (! tex_wrapped_up_paragraph(normal_par_context)) {
+ if (! tex_wrapped_up_paragraph(normal_par_context, 0)) {
if (lmt_input_state.align_state < 0) {
/*tex This tries to recover from an alignment that didn't end properly. */
tex_off_save();
@@ -1585,7 +1586,7 @@ int tex_main_control(void)
return lmt_main_state.run_state == initializing_state && cur_chr == dump_code;
}
/*tex
- Give diagnostic information, if requested When a new token has just been fetched at
+ Give diagnostic information, if requested. When a new token has just been fetched at
|big_switch|, we have an ideal place to monitor \TEX's activity.
*/
if (tracing_commands_par > 0) {
@@ -2499,7 +2500,8 @@ inline static void tex_aux_finish_adjusted_hbox(void)
inline static void tex_aux_finish_vbox(void)
{
- if (! tex_wrapped_up_paragraph(vbox_par_context)) {
+
+ if (! tex_wrapped_up_paragraph(vbox_par_context, 1)) {
tex_end_paragraph(vbox_group, vbox_par_context);
tex_package(vbox_code);
}
@@ -2507,7 +2509,7 @@ inline static void tex_aux_finish_vbox(void)
inline static void tex_aux_finish_vtop(void)
{
- if (! tex_wrapped_up_paragraph(vtop_par_context)) {
+ if (! tex_wrapped_up_paragraph(vtop_par_context, 1)) {
tex_end_paragraph(vtop_group, vtop_par_context);
tex_package(vtop_code);
}
@@ -2515,7 +2517,7 @@ inline static void tex_aux_finish_vtop(void)
inline static void tex_aux_finish_dbox(void)
{
- if (! tex_wrapped_up_paragraph(dbox_par_context)) {
+ if (! tex_wrapped_up_paragraph(dbox_par_context, 1)) {
tex_end_paragraph(dbox_group, dbox_par_context);
tex_package(dbox_code);
}
@@ -2975,7 +2977,7 @@ static void tex_aux_run_kern(void)
{
halfword code = cur_chr;
switch (code) {
- /* not yet enabled and maybe it never will be */
+ /*tex Finally enabled: */
case h_kern_code:
if (cur_mode == vmode) {
tex_back_input(token_val(kern_cmd, normal_kern_code));
@@ -3072,13 +3074,35 @@ void tex_end_paragraph(int group, int context)
static void tex_aux_run_penalty(void)
{
- halfword value = tex_scan_int(0, NULL);
- tex_tail_append(tex_new_penalty_node(value, user_penalty_subtype));
- if (cur_list.mode == vmode) {
- if (! lmt_page_builder_state.output_active) {
- lmt_page_filter_callback(penalty_page_context, 0);
+ halfword code = cur_chr;
+ switch (code) {
+ /*tex Finally enabled: */
+ case h_penalty_code:
+ if (cur_mode == vmode) {
+ tex_back_input(token_val(penalty_cmd, normal_penalty_code));
+ tex_back_input(token_val(begin_paragraph_cmd, quitvmode_par_code));
+ return;
+ } else {
+ break;
+ }
+ case v_penalty_code:
+ if (cur_mode == hmode) {
+ tex_back_input(token_val(penalty_cmd, normal_penalty_code));
+ tex_back_input(token_val(end_paragraph_cmd, normal_end_paragraph_code));
+ return;
+ } else {
+ break;
+ }
+ }
+ {
+ halfword value = tex_scan_int(0, NULL);
+ tex_tail_append(tex_new_penalty_node(value, user_penalty_subtype));
+ if (cur_list.mode == vmode) {
+ if (! lmt_page_builder_state.output_active) {
+ lmt_page_filter_callback(penalty_page_context, 0);
+ }
+ tex_build_page();
}
- tex_build_page();
}
}
@@ -4259,7 +4283,7 @@ static void tex_aux_set_shorthand_def(int a, int force)
switch (code) {
case char_def_code:
{
- halfword chr = tex_scan_char_number(0); /* maybe 1 */
+ halfword chr = tex_scan_char_number(0);
tex_define_again(a, p, char_given_cmd, chr);
break;
}
@@ -4377,16 +4401,6 @@ static void tex_aux_set_shorthand_def(int a, int force)
tex_define(a, p, fontspec_cmd, v);
}
break;
- /*
- case string_def_code:
- {
- halfword t = scan_toks_expand(0, NULL);
- halfword s = tokens_to_string(t);
- define(a, p, string_cmd, s - cs_offset_value);
- flush_list(t);
- break;
- }
- */
default:
tex_confusion("shorthand definition");
break;
@@ -6403,8 +6417,8 @@ inline static void tex_aux_big_switch(int mode, int cmd)
switch (cmd) {
case arithmic_cmd:
- case internal_int_cmd :
- case register_int_cmd :
+ case internal_int_cmd:
+ case register_int_cmd:
case internal_attribute_cmd:
case register_attribute_cmd:
case internal_posit_cmd:
@@ -6692,6 +6706,10 @@ void tex_initialize_variables(void)
math_end_class_par = math_end_class;
math_left_class_par = unset_noad_class;
math_right_class_par = unset_noad_class;
+ pre_inline_penalty_par = max_integer;
+ post_inline_penalty_par = max_integer;
+ pre_short_inline_penalty_par = max_integer;
+ post_short_inline_penalty_par = max_integer;
variable_family_par = -1,
ignore_depth_criterium_par = ignore_depth;
aux_get_date_and_time(&time_par, &day_par, &month_par, &year_par, &lmt_engine_state.utc_time);
diff --git a/source/luametatex/source/tex/texmaincontrol.h b/source/luametatex/source/tex/texmaincontrol.h
index 558db148f..f5c79bfdc 100644
--- a/source/luametatex/source/tex/texmaincontrol.h
+++ b/source/luametatex/source/tex/texmaincontrol.h
@@ -42,7 +42,7 @@ extern int tex_main_control (void);
extern void tex_normal_paragraph (int context);
extern void tex_begin_paragraph (int doindent, int context);
extern void tex_end_paragraph (int group, int context);
-extern int tex_wrapped_up_paragraph (int context);
+extern int tex_wrapped_up_paragraph (int context, int final);
extern void tex_insert_paragraph_token (void);
diff --git a/source/luametatex/source/tex/texmath.c b/source/luametatex/source/tex/texmath.c
index 00e67942c..a4ec71e5d 100644
--- a/source/luametatex/source/tex/texmath.c
+++ b/source/luametatex/source/tex/texmath.c
@@ -300,6 +300,16 @@ int tex_math_has_class_option(halfword cls, int option)
return (value & option) == option;
}
+int tex_math_has_class_parent(halfword cls)
+{
+ halfword value = count_parameter(first_math_options_code + cls);
+ if (value == no_class_options) {
+ unsigned parent = (unsigned) count_parameter(first_math_parent_code + cls);
+ return (parent >> 16) & 0xFF;
+ }
+ return 0;
+}
+
static void tex_aux_unsave_math(void)
{
tex_unsave();
@@ -2363,11 +2373,23 @@ static void tex_aux_math_math_component(halfword target, int append)
}
break;
case 's': case 'S':
- if (tex_scan_mandate_keyword("source", 1)) {
- noad_source(target) = tex_scan_int(0, NULL);
+ switch (tex_scan_character("ioIO", 0, 0, 0)) {
+ case 'i': case 'I':
+ if (tex_scan_mandate_keyword("single", 2)) {
+ noad_options(target) |= noad_option_single;
+ }
+ break;
+ case 'o': case 'O':
+ if (tex_scan_mandate_keyword("source", 2)) {
+ noad_source(target) = tex_scan_int(0, NULL);
+ }
+ break;
+ default:
+ tex_aux_show_keyword_error("single|source");
+ goto DONE;
}
break;
- case 't': case 'T':
+ case 't': case 'T':
if (tex_scan_mandate_keyword("textfont", 1)) {
usetextfont = math_atom_text_font_option;
}
@@ -2928,6 +2950,7 @@ void tex_run_math_accent(void)
halfword code = cur_chr;
halfword accent = tex_new_node(accent_noad, bothflexible_accent_subtype);
quarterword subtype = ordinary_noad_subtype;
+ halfword mathclass = accent_noad_subtype;
halfword attrlist = null;
if (cur_cmd == accent_cmd) {
tex_handle_error(
@@ -2945,15 +2968,48 @@ void tex_run_math_accent(void)
case math_uaccent_code:
/*tex |\Umathaccent| */
while (1) {
- switch (tex_scan_character("abcnsftokABCNSFTOK", 0, 1, 0)) {
+ switch (tex_scan_character("abcensftokABCENSFTOK", 0, 1, 0)) {
case 'a': case 'A':
- if (tex_scan_mandate_keyword("attr", 1)) {
- attrlist = tex_scan_attribute(attrlist);
+ switch (tex_scan_character("txTX", 0, 0, 0)) {
+ case 't': case 'T':
+ if (tex_scan_mandate_keyword("attr", 2)) {
+ attrlist = tex_scan_attribute(attrlist);
+ }
+ break;
+ // case 'x': case 'X':
+ // if (tex_scan_mandate_keyword("axis", 2)) {
+ // noad_options(accent) |= noad_option_axis;
+ // }
+ // break;
+ default:
+ // tex_aux_show_keyword_error("attr|axis");
+ tex_aux_show_keyword_error("attr");
+ goto DONE;
}
break;
case 'c': case 'C':
- if (tex_scan_mandate_keyword("center", 1)) {
- noad_options(accent) |= noad_option_center;
+ switch (tex_scan_character("elEL", 0, 0, 0)) {
+ case 'e': case 'E':
+ if (tex_scan_mandate_keyword("center", 2)) {
+ noad_options(accent) |= noad_option_center;
+ }
+ break;
+ case 'l': case 'L':
+ if (tex_scan_mandate_keyword("class", 2)) {
+ halfword c = (quarterword) tex_scan_math_class_number(0);
+ if (valid_math_class_code(c)) {
+ mathclass = c;
+ }
+ }
+ break;
+ default:
+ tex_aux_show_keyword_error("center|class");
+ goto DONE;
+ }
+ break;
+ case 'e': case 'E':
+ if (tex_scan_mandate_keyword("exact", 1)) {
+ noad_options(accent) |= noad_option_exact;
}
break;
case 's': case 'S':
@@ -3104,6 +3160,7 @@ void tex_run_math_accent(void)
noad_nucleus(accent) = n;
tex_aux_scan_math(n, tex_math_style_variant(cur_list.math_style, math_parameter_accent_variant), 0, 0, 0, 0, unset_noad_class, unset_noad_class);
}
+ set_noad_main_class(accent, mathclass);
}
/*tex
@@ -4704,6 +4761,34 @@ static void tex_aux_finish_displayed_math(int atleft, halfword eqnumber, halfwor
*/
+static inline int tex_aux_class_from_glyph(halfword n) {
+ return node_subtype(n) - (node_subtype(n) > glyph_math_extra_subtype ? glyph_math_extra_subtype : glyph_math_ordinary_subtype);
+}
+
+static int tex_aux_short_math(halfword m)
+{
+ // tex_show_node_list(m,10000,10000);
+ if (m) {
+ /* kern[] glyph[subtype -> class] vlist[scripts] kern[] */
+ if (node_type(m) == kern_node) {
+ m = node_next(m);
+ }
+ if (m && node_type(m) == glyph_node && tex_math_has_class_option(tex_aux_class_from_glyph(m), short_inline_class_option)) {
+ m = node_next(m);
+ } else {
+ return 0;
+ }
+ if (m && node_type(m) == vlist_node && node_subtype(m) == math_scripts_list) {
+ m = node_next(m);
+ }
+ if (m && node_type(m) == kern_node) {
+ m = node_next(m);
+ }
+ return ! m;
+ }
+ return 0;
+}
+
void tex_run_math_shift(void)
{
switch (cur_group) {
@@ -4719,7 +4804,7 @@ void tex_run_math_shift(void)
int mode = cur_list.mode;
int mathmode = cur_list.math_mode;
/*tex this pops the nest, the formula */
- halfword p = tex_aux_finish_math_list(null);
+ halfword mathlist = tex_aux_finish_math_list(null);
int mathleft = cur_list.math_begin;
int mathright = cur_list.math_end;
if (cur_cmd == math_shift_cs_cmd) {
@@ -4745,7 +4830,7 @@ void tex_run_math_shift(void)
tex_aux_check_display_math_end();
break;
}
- tex_run_mlist_to_hlist(p, 0, text_style, unset_noad_class, unset_noad_class);
+ tex_run_mlist_to_hlist(mathlist, 0, text_style, unset_noad_class, unset_noad_class);
eqnumber = tex_hpack(node_next(temp_head), 0, packing_additional, direction_unknown, holding_none_option);
attach_current_attribute_list(eqnumber);
tex_aux_unsave_math();
@@ -4754,7 +4839,7 @@ void tex_run_math_shift(void)
if (saved_type(saved_equation_number_item_location) == equation_number_location_save_type) {
atleft = saved_value(saved_equation_number_item_location) == left_location_code;
mode = cur_list.mode;
- p = tex_aux_finish_math_list(null);
+ mathlist = tex_aux_finish_math_list(null);
} else {
tex_confusion("after math");
}
@@ -4769,7 +4854,9 @@ void tex_run_math_shift(void)
the space above that display.
*/
- halfword math = tex_new_node(math_node, begin_inline_math);
+ halfword beginmath = tex_new_node(math_node, begin_inline_math);
+ halfword endmath = tex_new_node(math_node, end_inline_math);
+ halfword shortmath = 0;
if (mathmode) {
switch (cur_cmd) {
case math_shift_cs_cmd:
@@ -4784,68 +4871,81 @@ void tex_run_math_shift(void)
} else if (cur_cmd == math_shift_cs_cmd) {
tex_aux_check_inline_math_end();
}
- tex_tail_append(math);
- math_penalty(math) = pre_inline_penalty_par;
+ tex_tail_append(beginmath);
+ if (pre_inline_penalty_par != max_integer) {
+ math_penalty(beginmath) = pre_inline_penalty_par;
+ }
/*tex begin mathskip code */
switch (math_skip_mode_par) {
case math_skip_surround_when_zero:
if (! tex_glue_is_zero(math_skip_par)) {
- tex_copy_glue_values(math, math_skip_par);
+ tex_copy_glue_values(beginmath, math_skip_par);
} else {
- math_surround(math) = math_surround_par;
+ math_surround(beginmath) = math_surround_par;
}
break ;
case math_skip_always_left:
case math_skip_always_both:
case math_skip_only_when_skip:
- tex_copy_glue_values(math, math_skip_par);
+ tex_copy_glue_values(beginmath, math_skip_par);
break ;
case math_skip_always_right:
case math_skip_ignore:
break ;
case math_skip_always_surround:
default:
- math_surround(math) = math_surround_par;
+ math_surround(beginmath) = math_surround_par;
break;
}
/*tex end mathskip code */
if (cur_list.math_dir) {
tex_tail_append(tex_new_dir(normal_dir_subtype, math_direction_par));
}
- tex_run_mlist_to_hlist(p, cur_list.mode > nomode, is_valid_math_style(cur_list.math_main_style) ? cur_list.math_main_style : text_style, cur_list.math_begin, cur_list.math_end);
+ tex_run_mlist_to_hlist(mathlist, cur_list.mode > nomode, is_valid_math_style(cur_list.math_main_style) ? cur_list.math_main_style : text_style, cur_list.math_begin, cur_list.math_end);
+ shortmath = tex_aux_short_math(node_next(temp_head));
tex_try_couple_nodes(cur_list.tail, node_next(temp_head));
cur_list.tail = tex_tail_of_node_list(cur_list.tail);
if (cur_list.math_dir) {
tex_tail_append(tex_new_dir(cancel_dir_subtype, math_direction_par));
}
cur_list.math_dir = 0;
- math = tex_new_node(math_node, end_inline_math);
- tex_tail_append(math);
- math_penalty(math) = post_inline_penalty_par;
+ tex_tail_append(endmath);
+ /* */
+ if (post_inline_penalty_par != max_integer) {
+ math_penalty(endmath) = post_inline_penalty_par;
+ }
/*tex begin mathskip code */
switch (math_skip_mode_par) {
case math_skip_surround_when_zero :
if (! tex_glue_is_zero(math_skip_par)) {
- tex_copy_glue_values(math, math_skip_par);
- math_surround(math) = 0;
+ tex_copy_glue_values(endmath, math_skip_par);
+ math_surround(endmath) = 0;
} else {
- math_surround(math) = math_surround_par;
+ math_surround(endmath) = math_surround_par;
}
break;
case math_skip_always_right:
case math_skip_always_both:
case math_skip_only_when_skip:
- tex_copy_glue_values(math, math_skip_par);
+ tex_copy_glue_values(endmath, math_skip_par);
break;
case math_skip_always_left:
case math_skip_ignore:
break;
case math_skip_always_surround:
default:
- math_surround(math) = math_surround_par;
+ math_surround(endmath) = math_surround_par;
break;
}
/*tex end mathskip code */
+ if (shortmath) {
+ if (pre_short_inline_penalty_par != max_integer) {
+ math_penalty(beginmath) = pre_short_inline_penalty_par;
+ }
+ if (post_short_inline_penalty_par != max_integer) {
+ math_penalty(endmath) = post_short_inline_penalty_par;
+ }
+ }
cur_list.space_factor = default_space_factor;
mathleft = cur_list.math_begin;
mathright = cur_list.math_end;
@@ -4858,7 +4958,7 @@ void tex_run_math_shift(void)
tex_aux_check_display_math_end();
}
}
- tex_run_mlist_to_hlist(p, 0, display_style, cur_list.math_begin, cur_list.math_end);
+ tex_run_mlist_to_hlist(mathlist, 0, display_style, cur_list.math_begin, cur_list.math_end);
mathleft = cur_list.math_begin;
mathright = cur_list.math_end;
tex_aux_finish_displayed_math(atleft, eqnumber, node_next(temp_head));
diff --git a/source/luametatex/source/tex/texmath.h b/source/luametatex/source/tex/texmath.h
index ba02e8373..65f706a3c 100644
--- a/source/luametatex/source/tex/texmath.h
+++ b/source/luametatex/source/tex/texmath.h
@@ -272,10 +272,12 @@ typedef enum math_class_options {
auto_inject_class_option = 0x0100000,
remove_italic_correction_class_option = 0x0200000,
operator_italic_correction_class_option = 0x0400000,
+ short_inline_class_option = 0x0800000,
no_class_options = 0xF000000,
} math_class_options;
extern int tex_math_has_class_option(halfword cls, int option);
+extern int tex_math_has_class_parent(halfword cls);
typedef enum math_atom_font_options {
math_atom_no_font_option = 0,
diff --git a/source/luametatex/source/tex/texmlist.c b/source/luametatex/source/tex/texmlist.c
index c5613d90a..69de1c8c6 100644
--- a/source/luametatex/source/tex/texmlist.c
+++ b/source/luametatex/source/tex/texmlist.c
@@ -542,12 +542,10 @@ inline static int tex_aux_checked_left_kern_fnt_chr(halfword fnt, halfword chr,
halfword hastop = (state & prime_script_state) || (state & post_super_script_state);
halfword hasbot = state & post_sub_script_state;
if (hastop && tex_math_has_class_option(subtype, left_top_kern_class_option)) {
-// top = tex_char_top_left_kern_from_font(fnt, chr);
-top = tex_aux_math_x_size_scaled(fnt, tex_char_top_left_kern_from_font(fnt, chr), size);
+ top = tex_aux_math_x_size_scaled(fnt, tex_char_top_left_kern_from_font(fnt, chr), size);
}
if (hasbot && tex_math_has_class_option(subtype, left_bottom_kern_class_option)) {
-// bot = tex_char_bottom_left_kern_from_font(fnt, chr);
-bot = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_left_kern_from_font(fnt, chr), size);
+ bot = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_left_kern_from_font(fnt, chr), size);
}
if (hastop && hasbot) {
return top > bot ? top : bot;
@@ -574,12 +572,10 @@ inline static int tex_aux_checked_right_kern_fnt_chr(halfword fnt, halfword chr,
halfword hastop = state & pre_super_script_state;
halfword hasbot = state & pre_sub_script_state;
if (hastop && tex_math_has_class_option(subtype, right_top_kern_class_option)) {
-// top = tex_char_top_right_kern_from_font(fnt, chr);
-top = tex_aux_math_x_size_scaled(fnt, tex_char_top_right_kern_from_font(fnt, chr), size);
+ top = tex_aux_math_x_size_scaled(fnt, tex_char_top_right_kern_from_font(fnt, chr), size);
}
if (hasbot && tex_math_has_class_option(subtype, right_bottom_kern_class_option)) {
-// bot = tex_char_bottom_right_kern_from_font(fnt, chr);
-bot = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_right_kern_from_font(fnt, chr), size);
+ bot = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_right_kern_from_font(fnt, chr), size);
}
if (hastop && hasbot) {
return top < bot ? bot : top;
@@ -783,7 +779,7 @@ static halfword tex_aux_fraction_rule(scaled width, scaled height, halfword att,
if (! rule) {
if (math_rules_mode_par) {
rule = tex_new_rule_node(ruletype);
- rule_data(rule) = tex_fam_fnt(fam, size);
+ rule_data(rule) = tex_fam_fnt(fam, size); // we have font/fam/chr fields, why not use these
} else {
rule = tex_new_rule_node(normal_rule_subtype);
}
@@ -3154,7 +3150,14 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
}
} else { /* if (flags & overlay_accent_code) { */
/*tex Center the accent vertically around base: */
- delta = tex_half_scaled(box_total(accent) + box_total(base));
+ if (has_noad_option_exact(target)) {
+ delta = box_height(base) + box_depth(accent);
+ } else {
+ delta = tex_half_scaled(box_total(accent) + box_total(base));
+ }
+ // if (has_noad_option_axis(target)) {
+ // delta -= tex_aux_math_axis(size);
+ // }
}
if (accenttotal) {
*accenttotal = box_total(accent);
@@ -3175,7 +3178,11 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
baseheight = box_height(base);
}
/*tex The top accents of both characters are aligned. */
- {
+ if (flags & overlay_accent_code) {
+ /* We ignore overshoot here, at leats for now. */
+ box_shift_amount(accent) = tex_half_scaled(basewidth - box_width(accent));
+ box_width(accent) = 0; /* in gyre zero anyway */
+ } else {
halfword accentwidth = box_width(accent);
if (accentwidth > basewidth && has_noad_option_nooverflow(target)) {
/*tex
@@ -3201,9 +3208,9 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
} else {
/*tex When we scale we center. */
if (flags & top_accent_code) {
- anchor = tex_char_unchecked_top_anchor_from_font(accentfnt, accentchr); /* no bot accent key */
+ anchor = tex_char_unchecked_top_anchor_from_font(accentfnt, accentchr);
} else if (flags & bot_accent_code) {
- anchor = tex_char_unchecked_bottom_anchor_from_font(accentfnt, accentchr); /* no bot accent key */
+ anchor = tex_char_unchecked_bottom_anchor_from_font(accentfnt, accentchr);
} else {
anchor = INT_MIN;
}
@@ -5070,12 +5077,18 @@ static void tex_aux_make_scripts(halfword target, halfword kernel, scaled italic
shift_down = 0;
break;
default:
- /*tex Used for optimizing accents. */
- kernelsize.ht -= supdrop;
- /*tex These parameters are only applied in an assembly (and often some 0.5 .. 1.5 pt on 12pt). */
- prime_up = kernelsize.ht - tex_get_math_y_parameter_default(style, math_parameter_prime_shift_drop, 0);
- shift_up = kernelsize.ht - tex_get_math_y_parameter_checked(style, math_parameter_superscript_shift_drop);
- shift_down = kernelsize.dp + tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_drop);
+ if (has_noad_option_single(target)) {
+ prime_up = 0;
+ shift_up = 0;
+ shift_down = 0;
+ } else {
+ /*tex Used for optimizing accents. */
+ kernelsize.ht -= supdrop;
+ /*tex These parameters are only applied in an assembly (and often some 0.5 .. 1.5 pt on 12pt). */
+ prime_up = kernelsize.ht - tex_get_math_y_parameter_default(style, math_parameter_prime_shift_drop, 0);
+ shift_up = kernelsize.ht - tex_get_math_y_parameter_checked(style, math_parameter_superscript_shift_drop);
+ shift_down = kernelsize.dp + tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_drop);
+ }
break;
}
/*tex
@@ -6965,7 +6978,8 @@ static void tex_mlist_to_hlist_finalize_list(mliststate *state)
break;
case accent_noad:
current_type = simple_noad; /*tex Same kind of fields. */
- current_subtype = accent_noad_subtype;
+ // current_subtype = accent_noad_subtype;
+ current_subtype = get_noad_main_class(current);
current_left_slack = noad_left_slack(current);
current_right_slack = noad_right_slack(current);
break;
diff --git a/source/luametatex/source/tex/texnodes.c b/source/luametatex/source/tex/texnodes.c
index 63cf9e4c3..39dedb97f 100644
--- a/source/luametatex/source/tex/texnodes.c
+++ b/source/luametatex/source/tex/texnodes.c
@@ -157,12 +157,14 @@ void lmt_nodelib_initialize(void) {
set_value_entry_key(subtypes_glue, g_leaders, gleaders)
set_value_entry_key(subtypes_glue, u_leaders, uleaders)
- subtypes_boundary = lmt_aux_allocate_value_info(word_boundary);
+ subtypes_boundary = lmt_aux_allocate_value_info(par_boundary);
set_value_entry_key(subtypes_boundary, cancel_boundary, cancel)
set_value_entry_key(subtypes_boundary, user_boundary, user)
set_value_entry_key(subtypes_boundary, protrusion_boundary, protrusion)
set_value_entry_key(subtypes_boundary, word_boundary, word)
+ set_value_entry_key(subtypes_boundary, page_boundary, page)
+ set_value_entry_key(subtypes_boundary, par_boundary, par)
subtypes_penalty = lmt_aux_allocate_value_info(equation_number_penalty_subtype);
@@ -2724,11 +2726,38 @@ void tex_show_node_list(halfword p, int threshold, int max)
if (rule_depth(p)) {
tex_print_format(", depth %R", rule_depth(p));
}
- if (rule_left(p)) {
- tex_print_format(", left / top %R", rule_left(p));
- }
- if (rule_right(p)) {
- tex_print_format(", right / bottom %R", rule_right(p));
+ switch (node_subtype(p)) {
+ case virtual_rule_subtype:
+ if (rule_virtual_width(p)) {
+ tex_print_format(", virtual width %R", rule_virtual_width(p));
+ }
+ if (rule_virtual_height(p)) {
+ tex_print_format(", virtual height %R", rule_virtual_height(p));
+ }
+ if (rule_virtual_depth(p)) {
+ tex_print_format(", virtual depth %R", rule_virtual_depth(p));
+ }
+ break;
+ case strut_rule_subtype:
+ if (rule_strut_font(p)) {
+ if (rule_strut_font(p) >= rule_font_fam_offset) {
+ tex_print_format(", family %i", rule_strut_font(p) - rule_font_fam_offset);
+ } else {
+ tex_print_format(", font %F", rule_strut_font(p) < 0 ? 0 : rule_strut_font(p));
+ }
+ }
+ if (rule_strut_character(p)) {
+ tex_print_format(", character %U", rule_strut_character(p));
+ }
+ /* fall through */
+ default:
+ if (rule_left(p)) {
+ tex_print_format(", left / top %R", rule_left(p));
+ }
+ if (rule_right(p)) {
+ tex_print_format(", right / bottom %R", rule_right(p));
+ }
+ break;
}
if (rule_x_offset(p)) {
tex_print_format(", xoffset %R", rule_x_offset(p));
@@ -2736,15 +2765,8 @@ void tex_show_node_list(halfword p, int threshold, int max)
if (rule_y_offset(p)) {
tex_print_format(", yoffset %R", rule_y_offset(p));
}
- if (rule_font(p)) {
- if (rule_font(p) >= rule_font_fam_offset) {
- tex_print_format(", family %i", rule_font(p) - rule_font_fam_offset);
- } else {
- tex_print_format(", font %F", rule_font(p) < 0 ? 0 : rule_font(p));
- }
- }
- if (rule_character(p)) {
- tex_print_format(", character %U", rule_character(p));
+ if (rule_data(p)) {
+ tex_print_format(", data %R", rule_data(p));
}
break;
case insert_node:
diff --git a/source/luametatex/source/tex/texnodes.h b/source/luametatex/source/tex/texnodes.h
index 7fa050428..9e7d3ef13 100644
--- a/source/luametatex/source/tex/texnodes.h
+++ b/source/luametatex/source/tex/texnodes.h
@@ -140,7 +140,9 @@ typedef enum node_types {
/*tex These two are active nodes. */
unhyphenated_node,
hyphenated_node,
+ /*tex This one can also be in the active list. */
delta_node,
+ /*tex While this is an indirect one carrying data. */
passive_node,
} node_types;
@@ -631,9 +633,9 @@ inline static int tex_is_par_init_glue(halfword n)
typedef enum kern_subtypes {
font_kern_subtype,
- explicit_kern_subtype, /*tex |subtype| of kern nodes from |\kern| and |\/| */
+ explicit_kern_subtype, /*tex |subtype| of kern nodes from |\kern| */
accent_kern_subtype, /*tex |subtype| of kern nodes from accents */
- italic_kern_subtype,
+ italic_kern_subtype, /*tex |subtype| of kern nodes from |\/| */
left_margin_kern_subtype,
right_margin_kern_subtype,
explicit_math_kern_subtype,
@@ -1001,10 +1003,18 @@ typedef enum rule_codes {
# define rule_y_offset(a) vinfo(a,3)
# define rule_height(a) vlink(a,4)
# define rule_data(a) vinfo(a,4)
-# define rule_left(a) vinfo(a,5)
-# define rule_right(a) vlink(a,5)
-# define rule_font(a) vinfo(a,6)
-# define rule_character(a) vlink(a,6)
+# define rule_left(a) vinfo(a,5) /* depends on subtype */
+# define rule_right(a) vlink(a,5) /* depends on subtype */
+# define rule_extra_1(a) vinfo(a,6) /* depends on subtype */
+# define rule_extra_2(a) vlink(a,6) /* depends on subtype */
+
+# define rule_strut_font rule_extra_1
+# define rule_strut_character rule_extra_2
+
+# define rule_virtual_width rule_left
+# define rule_virtual_height rule_right
+# define rule_virtual_depth rule_extra_1
+# define rule_virtual_unused rule_extra_2
# define rule_total(a) (rule_height(a) + rule_depth(a))
@@ -1160,6 +1170,8 @@ typedef enum glyph_subtypes {
glyph_math_accent_subtype,
glyph_math_fenced_subtype,
glyph_math_ghost_subtype,
+ /* bogus subtype */
+ glyph_math_vcenter_subtype,
/* extra math, user classes, set but anonymous */
glyph_math_extra_subtype = 31,
} glyph_subtypes;
@@ -1793,6 +1805,7 @@ typedef enum noad_options {
# define noad_option_center (uint64_t) 0x04000000000
# define noad_option_scale (uint64_t) 0x08000000000
# define noad_option_keep_base (uint64_t) 0x10000000000
+# define noad_option_single (uint64_t) 0x20000000000
# define has_option(a,b) (((a) & (b)) == (b))
# define unset_option(a,b) ((a) & ~(b))
@@ -1856,6 +1869,7 @@ inline static int has_noad_no_script_option(halfword n, halfword option)
# define has_noad_option_auto_base(a) (has_option(noad_options(a), noad_option_auto_base))
# define has_noad_option_scale(a) (has_option(noad_options(a), noad_option_scale))
# define has_noad_option_keep_base(a) (has_option(noad_options(a), noad_option_keep_base))
+# define has_noad_option_single(a) (has_option(noad_options(a), noad_option_single))
/*tex
In the meantime the codes and subtypes are in sync. The variable component does not really
@@ -2118,7 +2132,7 @@ typedef enum math_kernel_options {
typedef enum boundary_subtypes {
cancel_boundary,
user_boundary,
- protrusion_boundary,
+ protrusion_boundary, /* 1=left, 2=right, 3=both */
word_boundary,
page_boundary,
par_boundary,
@@ -2283,7 +2297,7 @@ static int par_category_to_codes[] = {
/*tex
Todo: make the fields 6+ into a par_state node so that local box ones can be
small. Also, penalty and broken fields now are duplicate. Do we need to keep
- these?
+ these?
*/
# define par_node_size 28
@@ -2312,12 +2326,12 @@ static int par_category_to_codes[] = {
# define par_looseness(a) vinfo(a,13)
# define par_last_line_fit(a) vlink(a,13)
# define par_line_penalty(a) vinfo(a,14)
-# define par_inter_line_penalty(a) vlink(a,14)
+# define par_inter_line_penalty(a) vlink(a,14) /* */
# define par_club_penalty(a) vinfo(a,15)
# define par_widow_penalty(a) vlink(a,15)
# define par_display_widow_penalty(a) vinfo(a,16)
# define par_orphan_penalty(a) vlink(a,16)
-# define par_broken_penalty(a) vinfo(a,17)
+# define par_broken_penalty(a) vinfo(a,17) /* */
# define par_adj_demerits(a) vlink(a,17)
# define par_double_hyphen_demerits(a) vinfo(a,18)
# define par_final_hyphen_demerits(a) vlink(a,18)
@@ -2338,7 +2352,15 @@ static int par_category_to_codes[] = {
# define par_shaping_penalties_mode(a) vinfo(a,26)
# define par_shaping_penalty(a) vlink(a,26)
# define par_par_init_left_skip(a) vlink(a,27)
-# define par_par_init_right_skip(a) vinfo(a,27)
+# define par_par_init_right_skip(a) vinfo(a,27)
+
+/*
+ At some point we will have this (array with double values), depends on the outcome of an
+ experiment but I want to reserve this. We then also patch |texlocalboxes.c| line 295+.
+*/
+
+// define par_lousyness(a) vinfo(a,2) /* par_penalty_interline */
+// define par_reserved(a) vlink(a,2) /* par_penalty_broken */
typedef enum par_subtypes {
vmode_par_par_subtype,
@@ -2403,15 +2425,19 @@ inline static int tex_par_to_be_set (halfword state, halfword what) { re
spot.
*/
-/* is vinfo(a,2) used? it not we can have fitness there and hyphenated/unyphenates as subtype */
+/*tex
+ We can use vinfo(a,2) for fitness instead the subtype field. But then we also need to set
+ it explicitly because now that happens in the allocator.
+*/
# define active_node_size 4 /*tex |hyphenated_node| or |unhyphenated_node| */
# define active_fitness node_subtype /*tex |very_loose_fit..tight_fit| on final line for this break */
# define active_break_node(a) vlink(a,1) /*tex pointer to the corresponding passive node */
# define active_line_number(a) vinfo(a,1) /*tex line that begins at this breakpoint */
# define active_total_demerits(a) vlink(a,2) /*tex the quantity that \TEX\ minimizes */
-# define active_short(a) vinfo(a,3) /*tex |shortfall| of this line */
+# define active_reserved(a) vinfo(a,2)
# define active_glue(a) vlink(a,3) /*tex corresponding glue stretch or shrink */
+# define active_short(a) vinfo(a,3) /*tex |shortfall| of this line */
# define passive_node_size 7
# define passive_cur_break(a) vlink(a,1) /*tex in passive node, points to position of this breakpoint */
@@ -2670,6 +2696,11 @@ typedef enum glue_amounts {
total_shrink_amount = 7, // 2 //
font_stretch_amount = 8, // 8 //
font_shrink_amount = 9, // 9 //
+ /* */
+ max_height_amount = 10,
+ max_depth_amount = 11,
+ /* */
+ n_of_glue_amounts = 12,
} glue_amounts;
# define min_glue_order normal_glue_order
diff --git a/source/luametatex/source/tex/texpackaging.c b/source/luametatex/source/tex/texpackaging.c
index ad1db455c..dbc569246 100644
--- a/source/luametatex/source/tex/texpackaging.c
+++ b/source/luametatex/source/tex/texpackaging.c
@@ -641,7 +641,7 @@ scaled tex_right_marginkern(halfword p)
/*tex
Character protrusion is something we inherited from \PDFTEX\ and the next helper calculates
- the extend.
+ the extend. Is this |last_*_char| logic still valid?
*/
@@ -1488,40 +1488,40 @@ halfword tex_hpack(halfword p, scaled w, int m, singleword pack_direction, int r
box_glue_sign(r) = normal_glue_sign;
box_glue_set(r) = 0.0;
}
- if ((lmt_packaging_state.total_shrink[o] < -x) && (o == normal_glue_order) && (box_list(r))) {
- int overshoot = -x - lmt_packaging_state.total_shrink[normal_glue_order];
- lmt_packaging_state.last_badness = 1000000;
- lmt_packaging_state.last_overshoot = overshoot;
- /*tex Use the maximum shrinkage */
- box_glue_set(r) = 1.0;
- /*tex Report an overfull hbox and |goto common_ending|, if this box is sufficiently bad. */
- if ((overshoot > hfuzz_par) || (hbadness_par < 100)) {
- int callback_id = lmt_callback_defined(hpack_quality_callback);
- halfword rule = null;
- if (callback_id > 0) {
- lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "SdNddS->N",
- "overfull",
- overshoot,
- r,
- abs(lmt_packaging_state.pack_begin_line),
- lmt_input_state.input_line,
- tex_current_input_file_name(),
- &rule);
- } else if (q && overfull_rule_par > 0) {
- rule = tex_new_rule_node(normal_rule_subtype);
- rule_width(rule) = overfull_rule_par;
- }
- if (rule && rule != r) {
- tex_aux_append_diagnostic_rule(r, rule);
- }
- if (callback_id == 0) {
- tex_print_nlp();
- tex_print_format("%l[package: overfull \\hbox (%D too wide)", overshoot, pt_unit);
- goto COMMON_ENDING;
+ if (o == normal_glue_order && box_list(r)) {
+ if (lmt_packaging_state.total_shrink[o] < -x) {
+ int overshoot = -x - lmt_packaging_state.total_shrink[normal_glue_order];
+ lmt_packaging_state.last_badness = 1000000;
+ lmt_packaging_state.last_overshoot = overshoot;
+ /*tex Use the maximum shrinkage */
+ box_glue_set(r) = 1.0;
+ /*tex Report an overfull hbox and |goto common_ending|, if this box is sufficiently bad. */
+ if ((overshoot > hfuzz_par) || (hbadness_par < 100)) {
+ int callback_id = lmt_callback_defined(hpack_quality_callback);
+ halfword rule = null;
+ if (callback_id > 0) {
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "SdNddS->N",
+ "overfull",
+ overshoot,
+ r,
+ abs(lmt_packaging_state.pack_begin_line),
+ lmt_input_state.input_line,
+ tex_current_input_file_name(),
+ &rule);
+ } else if (q && overfull_rule_par > 0) {
+ rule = tex_new_rule_node(normal_rule_subtype);
+ rule_width(rule) = overfull_rule_par;
+ }
+ if (rule && rule != r) {
+ tex_aux_append_diagnostic_rule(r, rule);
+ }
+ if (callback_id == 0) {
+ tex_print_nlp();
+ tex_print_format("%l[package: overfull \\hbox (%D too wide)", overshoot, pt_unit);
+ goto COMMON_ENDING;
+ }
}
- }
- } else if (o == normal_glue_order) {
- if (box_list(r)) {
+ } else {
/*tex Report a tight hbox and |goto common_ending|, if this box is sufficiently bad. */
lmt_packaging_state.last_badness = tex_badness(-x, lmt_packaging_state.total_shrink[normal_glue_order]);
if (lmt_packaging_state.last_badness > hbadness_par) {
@@ -2232,33 +2232,33 @@ halfword tex_vpack(halfword p, scaled h, int m, scaled l, singleword pack_direct
box_glue_sign(r) = normal_glue_sign;
box_glue_set(r) = 0.0;
}
- if ((lmt_packaging_state.total_shrink[o] < -x) && (o == normal_glue_order) && (box_list(r))) {
- int overshoot = -x - lmt_packaging_state.total_shrink[normal_glue_order];
- lmt_packaging_state.last_badness = 1000000;
- lmt_packaging_state.last_overshoot = overshoot;
- /*tex Use the maximum shrinkage */
- box_glue_set(r) = 1.0;
- /*tex Report an overfull vbox and |goto common_ending|, if this box is sufficiently bad. */
- if ((overshoot > vfuzz_par) || (vbadness_par < 100)) {
- int callback_id = lmt_callback_defined(vpack_quality_callback);
- if (callback_id > 0) {
- lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "SdNddS->",
- "overfull",
- overshoot,
- r,
- abs(lmt_packaging_state.pack_begin_line),
- lmt_input_state.input_line,
- tex_current_input_file_name()
- );
- goto EXIT;
- } else {
- tex_print_nlp();
- tex_print_format("%l[package: overfull \\vbox (%D too high)", - x - lmt_packaging_state.total_shrink[normal_glue_order], pt_unit);
- goto COMMON_ENDING;
+ if (o == normal_glue_order && box_list(r)) {
+ if (lmt_packaging_state.total_shrink[o] < -x) {
+ int overshoot = -x - lmt_packaging_state.total_shrink[normal_glue_order];
+ lmt_packaging_state.last_badness = 1000000;
+ lmt_packaging_state.last_overshoot = overshoot;
+ /*tex Use the maximum shrinkage */
+ box_glue_set(r) = 1.0;
+ /*tex Report an overfull vbox and |goto common_ending|, if this box is sufficiently bad. */
+ if ((overshoot > vfuzz_par) || (vbadness_par < 100)) {
+ int callback_id = lmt_callback_defined(vpack_quality_callback);
+ if (callback_id > 0) {
+ lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "SdNddS->",
+ "overfull",
+ overshoot,
+ r,
+ abs(lmt_packaging_state.pack_begin_line),
+ lmt_input_state.input_line,
+ tex_current_input_file_name()
+ );
+ goto EXIT;
+ } else {
+ tex_print_nlp();
+ tex_print_format("%l[package: overfull \\vbox (%D too high)", - x - lmt_packaging_state.total_shrink[normal_glue_order], pt_unit);
+ goto COMMON_ENDING;
+ }
}
- }
- } else if (o == normal_glue_order) {
- if (box_list(r)) {
+ } else {
/*tex Report a tight vbox and |goto common_ending|, if this box is sufficiently bad. */
lmt_packaging_state.last_badness = tex_badness(-x, lmt_packaging_state.total_shrink[normal_glue_order]);
if (lmt_packaging_state.last_badness > vbadness_par) {
@@ -2382,7 +2382,7 @@ void tex_run_vcenter(void)
void tex_finish_vcenter_group(void)
{
- if (! tex_wrapped_up_paragraph(vcenter_par_context)) {
+ if (! tex_wrapped_up_paragraph(vcenter_par_context, 1)) {
halfword p;
tex_end_paragraph(vcenter_group, vcenter_par_context);
tex_package(vbox_code); /* todo: vcenter_code */
diff --git a/source/luametatex/source/tex/texprimitive.c b/source/luametatex/source/tex/texprimitive.c
index 027f62d23..54ef9b1b1 100644
--- a/source/luametatex/source/tex/texprimitive.c
+++ b/source/luametatex/source/tex/texprimitive.c
@@ -899,12 +899,6 @@ void tex_print_cmd_chr(singleword cmd, halfword chr)
/*tex Kind of special. */
tex_print_str_esc("notexpanded");
break;
- /*
- case string_cmd:
- print_str("string:->");
- print(cs_offset_value + chr);
- break;
- */
case internal_box_reference_cmd:
tex_print_str_esc("hiddenlocalbox");
break;
diff --git a/source/luametatex/source/tex/texprinting.c b/source/luametatex/source/tex/texprinting.c
index 9e502fbdf..518f1cf43 100644
--- a/source/luametatex/source/tex/texprinting.c
+++ b/source/luametatex/source/tex/texprinting.c
@@ -223,6 +223,8 @@ void tex_print_char(int s)
*/
+/* no_print terminal | logfile | terminal_and_logfile | pseudo | new_string | luabuffer */
+
static void tex_aux_uprint(int s)
{
/*tex We're not sure about this so it's disabled for now! */
@@ -235,7 +237,6 @@ static void tex_aux_uprint(int s)
*/
if (s == new_line_char_par && lmt_print_state.selector < pseudo_selector_code) {
tex_print_ln();
- return;
} else if (s <= 0x7F) {
tex_print_char(s);
} else if (s <= 0x7FF) {
diff --git a/source/luametatex/source/tex/texrules.c b/source/luametatex/source/tex/texrules.c
index db993585b..560ca73df 100644
--- a/source/luametatex/source/tex/texrules.c
+++ b/source/luametatex/source/tex/texrules.c
@@ -67,25 +67,41 @@ halfword tex_aux_scan_rule_spec(rule_types type, halfword code)
}
break;
case 'l': case 'L':
- if (tex_scan_mandate_keyword("left", 1)) {
- rule_left(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
+ if (node_subtype(rule) != virtual_rule_subtype) {
+ if (tex_scan_mandate_keyword("left", 1)) {
+ rule_left(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
+ }
+ break;
+ } else {
+ goto DONE;
}
- break;
case 'r': case 'R':
- if (tex_scan_mandate_keyword("right", 1)) {
- rule_right(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
+ if (node_subtype(rule) != virtual_rule_subtype) {
+ if (tex_scan_mandate_keyword("right", 1)) {
+ rule_right(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
+ }
+ break;
+ } else {
+ goto DONE;
}
- break;
case 't': case 'T': /* just because it's nicer */
- if (tex_scan_mandate_keyword("top", 1)) {
- rule_left(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
+ if (node_subtype(rule) != virtual_rule_subtype) {
+ if (tex_scan_mandate_keyword("top", 1)) {
+ rule_left(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
+ }
+ break;
+ } else {
+ goto DONE;
}
- break;
case 'b': case 'B': /* just because it's nicer */
- if (tex_scan_mandate_keyword("bottom", 1)) {
- rule_right(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
+ if (node_subtype(rule) != virtual_rule_subtype) {
+ if (tex_scan_mandate_keyword("bottom", 1)) {
+ rule_right(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
+ }
+ break;
+ } else {
+ goto DONE;
}
- break;
case 'x': case 'X':
if (tex_scan_mandate_keyword("xoffset", 1)) {
rule_x_offset(rule) = tex_scan_dimen(0, 0, 0, 0, NULL);
@@ -97,44 +113,56 @@ halfword tex_aux_scan_rule_spec(rule_types type, halfword code)
}
break;
case 'f': case 'F':
- switch (tex_scan_character("aoAO", 0, 0, 0)) {
- case 'o': case 'O':
- if (tex_scan_mandate_keyword("font", 2)) {
- tex_set_rule_font(rule, tex_scan_font_identifier(NULL));
- }
- break;
- case 'a': case 'A':
- if (tex_scan_mandate_keyword("fam", 2)) {
- tex_set_rule_family(rule, tex_scan_math_family_number());
- }
- break;
- default:
- tex_aux_show_keyword_error("font|fam");
- goto DONE;
+ if (node_subtype(rule) != virtual_rule_subtype) {
+ switch (tex_scan_character("aoAO", 0, 0, 0)) {
+ case 'o': case 'O':
+ if (tex_scan_mandate_keyword("font", 2)) {
+ tex_set_rule_font(rule, tex_scan_font_identifier(NULL));
+ }
+ break;
+ case 'a': case 'A':
+ if (tex_scan_mandate_keyword("fam", 2)) {
+ tex_set_rule_family(rule, tex_scan_math_family_number());
+ }
+ break;
+ default:
+ tex_aux_show_keyword_error("font|fam");
+ goto DONE;
+ }
+ break;
+ } else {
+ goto DONE;
}
- break;
case 'c': case 'C':
- if (tex_scan_mandate_keyword("char", 1)) {
- rule_character(rule) = tex_scan_char_number(0);
+ if (node_subtype(rule) != virtual_rule_subtype) {
+ if (tex_scan_mandate_keyword("char", 1)) {
+ rule_strut_character(rule) = tex_scan_char_number(0);
+ }
+ break;
+ } else {
+ goto DONE;
}
- break;
default:
goto DONE;
}
}
DONE:
node_attr(rule) = attr;
- if (type == v_rule_type && code == strut_rule_code) {
- tex_aux_check_text_strut_rule(rule, text_style);
- }
- if (code == virtual_rule_code) {
- rule_data(rule) = rule_width(rule);
- rule_left(rule) = rule_height(rule);
- rule_right(rule) = rule_depth(rule);
- rule_width(rule) = 0;
- rule_height(rule) = 0;
- rule_depth(rule) = 0;
- node_subtype(rule) = virtual_rule_subtype;
+ switch (code) {
+ case strut_rule_code:
+ if (type == v_rule_type) {
+ tex_aux_check_text_strut_rule(rule, text_style);
+ }
+ break;
+ case virtual_rule_code:
+ rule_virtual_width(rule) = rule_width(rule);
+ rule_virtual_height(rule) = rule_height(rule);
+ rule_virtual_depth(rule) = rule_depth(rule);
+ rule_width(rule) = 0;
+ rule_height(rule) = 0;
+ rule_depth(rule) = 0;
+ node_subtype(rule) = virtual_rule_subtype;
+ break;
}
return rule;
}
@@ -163,7 +191,7 @@ void tex_aux_check_math_strut_rule(halfword rule, halfword style)
scaled dp = rule_depth(rule);
if (ht == null_flag || dp == null_flag) {
halfword fnt = tex_get_rule_font(rule, style);
- halfword chr = rule_character(rule);
+ halfword chr = rule_strut_character(rule);
if (fnt > 0 && chr && tex_char_exists(fnt, chr)) {
if (ht == null_flag) {
ht = tex_math_font_char_ht(fnt, chr, style);
@@ -192,7 +220,7 @@ void tex_aux_check_text_strut_rule(halfword rule, halfword style)
scaled dp = rule_depth(rule);
if (ht == null_flag || dp == null_flag) {
halfword fnt = tex_get_rule_font(rule, style);
- halfword chr = rule_character(rule);
+ halfword chr = rule_strut_character(rule);
if (fnt > 0 && chr && tex_char_exists(fnt, chr)) {
scaledwhd whd = tex_char_whd_from_font(fnt, chr);
if (ht == null_flag) {
@@ -208,47 +236,81 @@ void tex_aux_check_text_strut_rule(halfword rule, halfword style)
halfword tex_get_rule_font(halfword n, halfword style)
{
- halfword fnt = rule_font(n);
- if (fnt >= rule_font_fam_offset) {
- halfword fam = fnt - rule_font_fam_offset;
- if (fam_par_in_range(fam)) {
- fnt = tex_fam_fnt(fam, tex_size_of_style(style));
+ if (node_subtype(n) == virtual_rule_subtype) {
+ halfword fnt = rule_strut_font(n);
+ if (fnt >= rule_font_fam_offset) {
+ halfword fam = fnt - rule_font_fam_offset;
+ if (fam_par_in_range(fam)) {
+ fnt = tex_fam_fnt(fam, tex_size_of_style(style));
+ }
+ }
+ if (fnt < 0 || fnt >= max_n_of_fonts) {
+ return null_font;
+ } else {
+ return fnt;
}
- }
- if (fnt < 0 || fnt >= max_n_of_fonts) {
+ } else {
return null_font;
- } else {
- return fnt;
}
}
halfword tex_get_rule_family(halfword n)
{
- halfword fnt = rule_font(n);
- if (fnt >= rule_font_fam_offset) {
- halfword fam = fnt - rule_font_fam_offset;
- if (fam_par_in_range(fam)) {
- return fam;
+ if (node_subtype(n) == virtual_rule_subtype) {
+ halfword fnt = rule_strut_font(n);
+ if (fnt >= rule_font_fam_offset) {
+ halfword fam = fnt - rule_font_fam_offset;
+ if (fam_par_in_range(fam)) {
+ return fam;
+ }
}
- }
- return 0;
+ }
+ return 0;
}
void tex_set_rule_font(halfword n, halfword fnt)
{
- if (fnt < 0 || fnt >= rule_font_fam_offset) {
- rule_font(n) = 0;
- } else {
- rule_font(n) = fnt;
+ if (node_subtype(n) == virtual_rule_subtype) {
+ if (fnt < 0 || fnt >= rule_font_fam_offset) {
+ rule_strut_font(n) = 0;
+ } else {
+ rule_strut_font(n) = fnt;
+ }
}
}
void tex_set_rule_family(halfword n, halfword fam)
{
- if (fam < 0 || fam >= max_n_of_math_families) {
- rule_font(n) = rule_font_fam_offset;
- } else {
- rule_font(n) = rule_font_fam_offset + fam;
+ if (node_subtype(n) == virtual_rule_subtype) {
+ if (fam < 0 || fam >= max_n_of_math_families) {
+ rule_strut_font(n) = rule_font_fam_offset;
+ } else {
+ rule_strut_font(n) = rule_font_fam_offset + fam;
+ }
+ }
+}
+
+halfword tex_get_rule_left(halfword n)
+{
+ return node_subtype(n) == virtual_rule_subtype ? 0 : rule_left(n);
+}
+
+halfword tex_get_rule_right(halfword n)
+{
+ return node_subtype(n) == virtual_rule_subtype ? 0 : rule_right(n);
+}
+
+void tex_set_rule_left(halfword n, halfword value)
+{
+ if (node_subtype(n) != virtual_rule_subtype) {
+ rule_left(n) = value;
+ }
+}
+
+void tex_set_rule_right(halfword n, halfword value)
+{
+ if (node_subtype(n) != virtual_rule_subtype) {
+ rule_right(n) = value;
}
}
diff --git a/source/luametatex/source/tex/texrules.h b/source/luametatex/source/tex/texrules.h
index 8a01ac847..444c6d645 100644
--- a/source/luametatex/source/tex/texrules.h
+++ b/source/luametatex/source/tex/texrules.h
@@ -24,4 +24,9 @@ extern halfword tex_get_rule_family (halfword n);
extern void tex_set_rule_font (halfword n, halfword fnt);
extern void tex_set_rule_family (halfword n, halfword fam);
+extern halfword tex_get_rule_left (halfword n);
+extern halfword tex_get_rule_right (halfword n);
+extern void tex_set_rule_left (halfword n, halfword value);
+extern void tex_set_rule_right (halfword n, halfword value);
+
# endif
diff --git a/source/luametatex/source/tex/texscanning.c b/source/luametatex/source/tex/texscanning.c
index 675186681..9559a4040 100644
--- a/source/luametatex/source/tex/texscanning.c
+++ b/source/luametatex/source/tex/texscanning.c
@@ -1513,7 +1513,7 @@ static halfword tex_aux_scan_something_internal(halfword cmd, halfword chr, int
case math_parameter_set_atom_rule:
case math_parameter_let_atom_rule:
case math_parameter_copy_atom_rule:
- case math_parameter_let_parent:
+ // case math_parameter_let_parent:
case math_parameter_copy_parent:
case math_parameter_set_defaults:
{
@@ -1521,6 +1521,15 @@ static halfword tex_aux_scan_something_internal(halfword cmd, halfword chr, int
// cur_val_level = int_val_level;
break;
}
+ case math_parameter_let_parent:
+ {
+ halfword mathclass = tex_scan_math_class_number(0);
+ if (valid_math_class_code(mathclass)) {
+ cur_val = tex_math_has_class_parent(mathclass);
+ cur_val_level = int_val_level;
+ }
+ break;
+ }
case math_parameter_set_pre_penalty:
case math_parameter_set_post_penalty:
case math_parameter_set_display_pre_penalty:
@@ -1893,16 +1902,6 @@ static halfword tex_aux_scan_something_internal(halfword cmd, halfword chr, int
}
break;
/*
- case string_cmd:
- {
- halfword head = str_toks(str_lstring(cs_offset_value + chr), NULL);
- begin_inserted_list(head);
- cur_val = 0;
- cur_val_level = no_val_level;
- break;
- }
- */
- /*
case special_box_cmd:
switch (chr) {
case left_box_code:
@@ -3292,6 +3291,14 @@ halfword tex_the_value_toks(int code, halfword *tail, halfword property) /* mayb
return null;
}
+void tex_detokenize_list(halfword head)
+{
+ int saved_selector;
+ push_selector;
+ tex_show_token_list(head, 0);
+ pop_selector;
+}
+
halfword tex_the_detokenized_toks(halfword *tail)
{
halfword head = tex_scan_general_text(tail);
diff --git a/source/luametatex/source/tex/texscanning.h b/source/luametatex/source/tex/texscanning.h
index 34e118d93..ed11b8f4c 100644
--- a/source/luametatex/source/tex/texscanning.h
+++ b/source/luametatex/source/tex/texscanning.h
@@ -131,7 +131,8 @@ extern halfword tex_scan_bytecode_reference (int optional_equal);
extern halfword tex_the_value_toks (int unit, halfword *tail, halfword property); /* returns head */
extern halfword tex_the_toks (int code, halfword *tail); /* returns head */
-extern halfword tex_the_detokenized_toks (halfword *head);
+extern halfword tex_the_detokenized_toks (halfword *tail);
+extern void tex_detokenize_list (halfword head);
extern strnumber tex_the_scanned_result (void);
extern void tex_set_font_dimen (void);
diff --git a/source/luametatex/source/tex/textoken.c b/source/luametatex/source/tex/textoken.c
index e3aa90c0f..7580d72d3 100644
--- a/source/luametatex/source/tex/textoken.c
+++ b/source/luametatex/source/tex/textoken.c
@@ -2942,6 +2942,7 @@ void tex_run_convert_tokens(halfword code)
break;
*/
case detokenized_code:
+ /*tex Sort of like |\meaningles| but without the explanationart text. */
{
int saved_selector;
int saved_scanner_status = lmt_input_state.scanner_status;
@@ -2956,6 +2957,60 @@ void tex_run_convert_tokens(halfword code)
pop_selector;
break;
}
+ case detokened_code:
+ /*tex Takes a control sequence or token list. Probably a bad name but so be it. */
+ {
+ int saved_selector;
+ int saved_scanner_status = lmt_input_state.scanner_status;
+ halfword list = null;
+ lmt_input_state.scanner_status = scanner_is_normal;
+ tex_get_token();
+ lmt_input_state.scanner_status = saved_scanner_status;
+ switch (cur_cmd) {
+ case call_cmd:
+ case protected_call_cmd:
+ case semi_protected_call_cmd:
+ case tolerant_call_cmd:
+ case tolerant_protected_call_cmd:
+ case tolerant_semi_protected_call_cmd:
+ if (cur_chr) {
+ /* We only serialize macros with no arguments. */
+ list = token_link(cur_chr);
+ break;
+ } else {
+ goto WHATEVER;
+ }
+ case internal_toks_cmd:
+ case register_toks_cmd:
+ list = token_link(eq_value(cur_chr));
+ break;
+ case register_cmd:
+ if (cur_chr == tok_val_level) {
+ halfword n = tex_scan_toks_register_number();
+ list = token_link(toks_register(n));
+ break;
+ } else {
+ goto WHATEVER;
+ }
+ break;
+ default:
+ WHATEVER:
+ {
+ halfword t = tex_get_available_token(cur_tok);
+ push_selector;
+ tex_show_token_list(t, 0);
+ pop_selector;
+ tex_put_available_token(t);
+ }
+ break;
+ }
+ if (list) {
+ push_selector;
+ tex_show_token_list(list, 2);
+ pop_selector;
+ }
+ break;
+ }
case roman_numeral_code:
{
int saved_selector;
@@ -3304,7 +3359,7 @@ char *tex_tokenlist_to_tstring(int pp, int inhibit_par, int *siz, int skippreamb
} else {
int infop = token_info(p);
if (infop < 0) {
- /* unlikely, will go after checking */
+ /*tex Unlikely, will go after checking (maybe \LUA\ user mess up). */
tex_aux_append_str_to_buffer(error_string_bad(32));
} else if (infop < cs_token_flag) {
/*tex We nearly always end up here because otherwise we have an error. */
@@ -3370,7 +3425,7 @@ char *tex_tokenlist_to_tstring(int pp, int inhibit_par, int *siz, int skippreamb
}
break;
case end_match_cmd:
- if (skippreamble ==2) {
+ if (skippreamble == 2) {
goto EXIT;
} else if (chr == 0) {
if (! skip) {
@@ -3380,15 +3435,6 @@ char *tex_tokenlist_to_tstring(int pp, int inhibit_par, int *siz, int skippreamb
skip = 0 ;
}
break;
- /*
- case string_cmd:
- c = c + cs_offset_value;
- do_make_room((int) str_length(c));
- for (int i = 0; i < str_length(c); i++) {
- token_state.buffer[token_state.bufloc++] = str_string(c)[i];
- }
- break;
- */
case end_paragraph_cmd:
if (! inhibit_par && (auto_paragraph_mode(auto_paragraph_text))) {
tex_aux_append_esc_to_buffer("par");
diff --git a/source/luametatex/source/tex/textypes.h b/source/luametatex/source/tex/textypes.h
index d2bb77972..1e83a975f 100644
--- a/source/luametatex/source/tex/textypes.h
+++ b/source/luametatex/source/tex/textypes.h
@@ -170,6 +170,7 @@ extern halfword tex_badness(
# define semi_loose_criterium 12 /* same as |decent_criterium| */
# define decent_criterium 12
# define semi_tight_criterium 12 /* same as |decent_criterium| */
+# define max_calculated_badness 8189
# define default_rule 26214 /*tex 0.4pt */
# define ignore_depth -65536000 /*tex The magic dimension value to mean \quote {ignore me}: -1000pt */