summaryrefslogtreecommitdiff
path: root/source/luametatex/source/tex/texlocalboxes.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/luametatex/source/tex/texlocalboxes.c')
-rw-r--r--source/luametatex/source/tex/texlocalboxes.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/source/luametatex/source/tex/texlocalboxes.c b/source/luametatex/source/tex/texlocalboxes.c
new file mode 100644
index 000000000..0def018d4
--- /dev/null
+++ b/source/luametatex/source/tex/texlocalboxes.c
@@ -0,0 +1,313 @@
+/*
+ See license.txt in the root of this project.
+*/
+
+# include "luametatex.h"
+
+/*tex
+ The concept of local left and right boxes originates in \OMEGA\ but in \LUATEX\ it already was
+ adapted and made more robust. Here we use an upgraded version with more features. These boxes
+ are sort of a mix between marks (states) and inserts (with dimensions).
+
+ We have linked lists of left or right boxes. This permits selective updating and multiple usage
+ of these boxes. It also means that we need to do additional packing and width calculations.
+
+ When we were in transition local boxes were handled as special boxes (alongside leader and
+ shipout boxes but they got their own cmd again when we were done).
+*/
+
+/*tex
+ Here we set fields in a new par node. We could have an extra width |_par| hut it doesn't really
+ pay off (now).
+*/
+
+inline static scaled tex_aux_local_boxes_width(halfword n)
+{
+ scaled width = 0;
+ while (n) {
+ if (node_type(n) == hlist_node) {
+ width += box_width(n);
+ } else {
+ /*tex Actually this is an error. */
+ }
+ n = node_next(n);
+ }
+ return width;
+}
+
+void tex_add_local_boxes(halfword p)
+{
+ if (local_left_box_par) {
+ halfword copy = tex_copy_node_list(local_left_box_par, null);
+ tex_set_local_left_width(p, tex_aux_local_boxes_width(copy));
+ par_box_left(p) = copy;
+ }
+ if (local_right_box_par) {
+ halfword copy = tex_copy_node_list(local_right_box_par, null);
+ tex_set_local_right_width(p, tex_aux_local_boxes_width(copy));
+ par_box_right(p) = copy;
+ }
+ if (local_middle_box_par) {
+ halfword copy = tex_copy_node_list(local_middle_box_par, null);
+ par_box_middle(p) = copy;
+ }
+}
+
+/*tex
+ Pass on to Lua or inject in the current list. So, we still have a linked list here
+ with only boxes.
+*/
+
+halfword tex_get_local_boxes(halfword location)
+{
+ switch (location) {
+ case local_left_box_code : return tex_use_local_boxes(local_left_box_par, local_left_box_code);
+ case local_right_box_code : return tex_use_local_boxes(local_right_box_par, local_right_box_code);
+ case local_middle_box_code: return tex_use_local_boxes(local_middle_box_par, local_middle_box_code);
+ }
+ return null;
+}
+
+/*tex Set them from Lua, watch out; not an eq update */
+
+void tex_set_local_boxes(halfword b, halfword location)
+{
+ switch (location) {
+ case local_left_box_code : tex_flush_node_list(local_left_box_par); local_left_box_par = b; break;
+ case local_right_box_code : tex_flush_node_list(local_right_box_par); local_right_box_par = b; break;
+ case local_middle_box_code: tex_flush_node_list(local_middle_box_par); local_middle_box_par = b; break;
+ }
+}
+
+/*tex Set them from TeX, watch out; this is an eq update */
+
+static halfword tex_aux_reset_boxes(halfword head, halfword index)
+{
+ if (head && index) {
+ halfword current = head;
+ while (current) {
+ halfword next = node_next(current);
+ if (node_type(current) == hlist_node && box_index(current) == index) {
+ if (current == head) {
+ head = node_next(head);
+ node_prev(head) = null;
+ next = head;
+ } else {
+ tex_try_couple_nodes(node_prev(current), next);
+ }
+ tex_flush_node(current);
+ break;
+ } else {
+ current = next;
+ }
+ }
+ return head;
+ } else {
+ tex_flush_node_list(head);
+ return null;
+ }
+}
+
+void tex_reset_local_boxes(halfword index, halfword location)
+{
+ switch (location) {
+ case local_left_box_code : local_left_box_par = tex_aux_reset_boxes(local_left_box_par, index); break;
+ case local_right_box_code : local_right_box_par = tex_aux_reset_boxes(local_right_box_par, index); break;
+ case local_middle_box_code: local_right_box_par = tex_aux_reset_boxes(local_middle_box_par, index); break;
+ }
+}
+
+static halfword tex_aux_update_boxes(halfword head, halfword b, halfword index)
+{
+ if (head && index) {
+ halfword current = head;
+ while (current) {
+ halfword next = node_next(current);
+ if (node_type(current) == hlist_node && box_index(current) == index) {
+ tex_try_couple_nodes(b, node_next(current));
+ if (current == head) {
+ head = b;
+ } else {
+ tex_couple_nodes(node_prev(current), b);
+ }
+ tex_flush_node(current);
+ break;
+ } else if (next) {
+ current = next;
+ } else {
+ tex_couple_nodes(current, b);
+ break;
+ }
+ }
+ return head;
+ }
+ return b;
+}
+
+void tex_update_local_boxes(halfword b, halfword index, halfword location) /* todo: avoid copying */
+{
+ switch (location) {
+ case local_left_box_code:
+ if (b) {
+ halfword c = local_left_box_par ? tex_copy_node_list(local_left_box_par, null) : null;
+ b = tex_aux_update_boxes(c, b, index);
+ } else if (index) {
+ halfword c = local_left_box_par ? tex_copy_node_list(local_left_box_par, null) : null;
+ b = tex_aux_reset_boxes(c, index);
+ }
+ update_tex_local_left_box(b);
+ break;
+ case local_right_box_code:
+ if (b) {
+ halfword c = local_right_box_par ? tex_copy_node_list(local_right_box_par, null) : null;
+ b = tex_aux_update_boxes(c, b, index);
+ } else if (index) {
+ halfword c = local_right_box_par ? tex_copy_node_list(local_right_box_par, null) : null;
+ b = tex_aux_reset_boxes(c, index);
+ }
+ update_tex_local_right_box(b);
+ break;
+ default:
+ if (b) {
+ halfword c = local_middle_box_par ? tex_copy_node_list(local_middle_box_par, null) : null;
+ b = tex_aux_update_boxes(c, b, index);
+ } else if (index) {
+ halfword c = local_middle_box_par ? tex_copy_node_list(local_middle_box_par, null) : null;
+ b = tex_aux_reset_boxes(c, index);
+ }
+ update_tex_local_middle_box(b);
+ break;
+ }
+}
+
+/*tex The |par| option: */
+
+/* todo: use helper */
+
+static halfword tex_aux_replace_local_box(halfword b, halfword index, halfword par_box)
+{
+ if (b) {
+ halfword c = par_box ? tex_copy_node_list(par_box, null) : null;
+ b = tex_aux_update_boxes(c, b, index);
+ } else if (index) {
+ halfword c = par_box ? tex_copy_node_list(par_box, null) : null;
+ b = tex_aux_reset_boxes(c, index);
+ }
+ if (par_box) {
+ tex_flush_node_list(par_box);
+ }
+ return b;
+}
+
+void tex_replace_local_boxes(halfword par, halfword b, halfword index, halfword location) /* todo: avoid copying */
+{
+ switch (location) {
+ case local_left_box_code:
+ par_box_left(par) = tex_aux_replace_local_box(b, index, par_box_left(par));
+ par_box_left_width(par) = tex_aux_local_boxes_width(b);
+ break;
+ case local_right_box_code:
+ par_box_right(par) = tex_aux_replace_local_box(b, index, par_box_right(par));
+ par_box_right_width(par) = tex_aux_local_boxes_width(b);
+ break;
+ case local_middle_box_code:
+ par_box_middle(par) = tex_aux_replace_local_box(b, index, par_box_middle(par));
+ /*tex We keep the zero width! */
+ break;
+ }
+}
+
+/*tex Get them for line injection. */
+
+halfword tex_use_local_boxes(halfword p, halfword location)
+{
+ if (p) {
+ p = tex_hpack(tex_copy_node_list(p, null), 0, packing_additional, direction_unknown, holding_none_option);
+ switch (location) {
+ case local_left_box_code : node_subtype(p) = local_left_list ; break;
+ case local_right_box_code : node_subtype(p) = local_right_list ; break;
+ case local_middle_box_code: node_subtype(p) = local_middle_list; break;
+ }
+ }
+ return p;
+}
+
+/* */
+
+void tex_scan_local_boxes_keys(quarterword *options, halfword *index)
+{
+ *options = 0;
+ *index = 0;
+ while (1) {
+ switch (tex_scan_character("iklpIKLP", 0, 1, 0)) {
+ case 'i': case 'I':
+ if (tex_scan_mandate_keyword("index", 1)) {
+ *index = tex_scan_box_index();
+ }
+ break;
+ case 'k': case 'K':
+ if (tex_scan_mandate_keyword("keep", 1)) {
+ *options |= local_box_keep_option;
+ }
+ break;
+ case 'l': case 'L':
+ if (tex_scan_mandate_keyword("local", 1)) {
+ *options |= local_box_local_option;
+ }
+ break;
+ case 'p': case 'P':
+ if (tex_scan_mandate_keyword("par", 1)) {
+ *options |= local_box_par_option;
+ }
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+halfword tex_valid_box_index(halfword n)
+{
+ return box_index_in_range(n);
+}
+
+
+scaled tex_get_local_left_width(halfword p)
+{
+ return par_box_left_width(p);
+}
+
+scaled tex_get_local_right_width(halfword p)
+{
+ return par_box_right_width(p);
+}
+
+void tex_set_local_left_width(halfword p, scaled width)
+{
+ par_box_left_width(p) = width;
+}
+
+void tex_set_local_right_width(halfword p, scaled width)
+{
+ par_box_right_width(p) = width;
+}
+
+halfword tex_get_local_interline_penalty(halfword p)
+{
+ return par_penalty_interline(p);
+}
+
+halfword tex_get_local_broken_penalty(halfword p)
+{
+ return par_penalty_broken(p);
+}
+
+void tex_set_local_interline_penalty(halfword p, halfword penalty)
+{
+ par_penalty_interline(p) = penalty;
+}
+
+void tex_set_local_broken_penalty(halfword p, halfword penalty)
+{
+ par_penalty_broken(p) = penalty;
+}