texlive[65617] trunk: fix for r2l multiline link etc rectangles

commits+lscarso at tug.org commits+lscarso at tug.org
Tue Jan 24 17:49:03 CET 2023


Revision: 65617
          http://tug.org/svn/texlive?view=revision&revision=65617
Author:   lscarso
Date:     2023-01-24 17:49:02 +0100 (Tue, 24 Jan 2023)
Log Message:
-----------
fix for r2l multiline link etc rectangles (H.Hagen)

Modified Paths:
--------------
    trunk/Build/source/texk/web2c/luatexdir/ChangeLog
    trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfannot.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdflink.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.h
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.h
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfthread.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h
    trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.h
    trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c
    trunk/Master/texmf-dist/doc/luatex/base/luatex-modifications.tex
    trunk/Master/texmf-dist/doc/luatex/base/luatex.pdf

Modified: trunk/Build/source/texk/web2c/luatexdir/ChangeLog
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/ChangeLog	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/ChangeLog	2023-01-24 16:49:02 UTC (rev 65617)
@@ -1,3 +1,6 @@
+2023-01-24  Luigi Scarso <luigi.scarso at gmail.com> 
+    *  fix for r2l multiline link etc rectangles (H.Hagen)
+
 2023-01-17  Luigi Scarso <luigi.scarso at gmail.com> 
     * \pdfvariable omitmediabox 1 (H.Hagen)
     * luatex 1.16.0

Modified: trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h	2023-01-24 16:49:02 UTC (rev 65617)
@@ -1,4 +1,4 @@
 #ifndef luatex_svn_revision_h
 #define luatex_svn_revision_h
-#define luatex_svn_revision 7556
+#define luatex_svn_revision 7557
 #endif

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdfannot.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdfannot.c	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdfannot.c	2023-01-24 16:49:02 UTC (rev 65617)
@@ -37,7 +37,7 @@
     alt_rule.wd = width(p);
     alt_rule.ht = height(p);
     alt_rule.dp = depth(p);
-    set_rect_dimens(pdf, p, parent_box, cur, alt_rule, 0);
+    set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
     obj_annot_ptr(pdf, pdf_annot_objnum(p)) = p;
     addto_page_resources(pdf, obj_type_annot, pdf_annot_objnum(p));
 }

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c	2023-01-24 16:49:02 UTC (rev 65617)
@@ -105,10 +105,11 @@
         The different branches for matrixused is somewhat strange and should
         always be used
     */
+    pdf_ann_margin(p) = pdf_dest_margin;
     switch (pdf_dest_type(p)) {
     case pdf_dest_xyz:
         if (matrixused())
-            set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
+            set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
         else {
             pdf_ann_left(p) = pos.h;
             pdf_ann_top(p) = pos.v;
@@ -117,7 +118,7 @@
     case pdf_dest_fith:
     case pdf_dest_fitbh:
         if (matrixused())
-            set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
+            set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
         else
             pdf_ann_top(p) = pos.v;
         break;
@@ -124,7 +125,7 @@
     case pdf_dest_fitv:
     case pdf_dest_fitbv:
         if (matrixused())
-            set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
+            set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
         else
             pdf_ann_left(p) = pos.h;
         break;
@@ -132,7 +133,8 @@
     case pdf_dest_fitb:
         break;
     case pdf_dest_fitr:
-        set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
+        set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
+        break;
     }
 }
 

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c	2023-01-24 16:49:02 UTC (rev 65617)
@@ -929,10 +929,10 @@
 void pdf_add_rect_spec(PDF pdf, halfword r)
 {
     /* the check is now here */
-    pdf_add_bp(pdf, pdf_ann_left(r)   < pdf_ann_right(r) ? pdf_ann_left(r)   : pdf_ann_right(r));
-    pdf_add_bp(pdf, pdf_ann_bottom(r) < pdf_ann_top(r)   ? pdf_ann_bottom(r) : pdf_ann_top(r));
-    pdf_add_bp(pdf, pdf_ann_left(r)   < pdf_ann_right(r) ? pdf_ann_right(r)  : pdf_ann_left(r));
-    pdf_add_bp(pdf, pdf_ann_bottom(r) < pdf_ann_top(r)   ? pdf_ann_top(r)    : pdf_ann_bottom(r));
+    pdf_add_bp(pdf, (pdf_ann_left(r)   < pdf_ann_right(r) ? pdf_ann_left(r)   : pdf_ann_right(r) ) - pdf_ann_margin(r));
+    pdf_add_bp(pdf, (pdf_ann_bottom(r) < pdf_ann_top(r)   ? pdf_ann_bottom(r) : pdf_ann_top(r)   ) - pdf_ann_margin(r));
+    pdf_add_bp(pdf, (pdf_ann_left(r)   < pdf_ann_right(r) ? pdf_ann_right(r)  : pdf_ann_left(r)  ) + pdf_ann_margin(r));
+    pdf_add_bp(pdf, (pdf_ann_bottom(r) < pdf_ann_top(r)   ? pdf_ann_top(r)    : pdf_ann_bottom(r)) + pdf_ann_margin(r));
 }
 
 void pdf_rectangle(PDF pdf, halfword r)

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdflink.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdflink.c	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdflink.c	2023-01-24 16:49:02 UTC (rev 65617)
@@ -47,6 +47,8 @@
     pdf->link_stack[pdf->link_stack_ptr].nesting_level = cur_s;
     pdf->link_stack[pdf->link_stack_ptr].link_node = copy_node_list(p);
     pdf->link_stack[pdf->link_stack_ptr].ref_link_node = p;
+    pdf->link_stack[pdf->link_stack_ptr].direction = pdf->posstruct->dir;
+    pdf->link_stack[pdf->link_stack_ptr].count =  0;
 }
 
 void pop_link_level(PDF pdf)
@@ -69,7 +71,9 @@
     alt_rule.wd = width(p);
     alt_rule.ht = height(p);
     alt_rule.dp = depth(p);
-    set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_link_margin);
+    pdf->link_stack[pdf->link_stack_ptr].count++;
+    set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
+    pdf_ann_margin(p) = pdf_link_margin;
     /*tex The reference for the annot object must be set here. */
     obj_annot_ptr(pdf, pdf_link_objnum(p)) = p;
     k = pdf_link_objnum(p);
@@ -95,15 +99,15 @@
     if (is_running(width(pdf->link_stack[pdf->link_stack_ptr].link_node))) {
         q = pdf->link_stack[pdf->link_stack_ptr].ref_link_node;
         if (global_shipping_mode == SHIPPING_PAGE && matrixused()) {
-            matrixrecalculate(pos.h + pdf_link_margin);
-            pdf_ann_left(q) = getllx() - pdf_link_margin;
-            pdf_ann_top(q) = getlly() - pdf_link_margin;
-            pdf_ann_right(q) = geturx() + pdf_link_margin;
-            pdf_ann_bottom(q) = getury() + pdf_link_margin;
+            matrixrecalculate(pos.h);
+            pdf_ann_left(q) = getllx();
+            pdf_ann_top(q) = getlly();
+            pdf_ann_right(q) = geturx();
+            pdf_ann_bottom(q) = getury();
         } else {
             switch (pdf->posstruct->dir) {
                 case dir_TLT:
-                    pdf_ann_right(q) = pos.h + pdf_link_margin;
+                    pdf_ann_right(q) = pos.h;
                     break;
                 case dir_TRT:
                     /*tex 
@@ -111,19 +115,35 @@
                        to the moment we write the rectangle, but it did not
                        consider this case.
                     */ 
+                    if (pdf_linking) {
+                        /* begin of experiment, can be simplified */
+                        if (pdf->link_stack[pdf->link_stack_ptr].count > 1) { 
+                            pdf_ann_right(q) = pdf_ann_right(q) - pdf_ann_left(q) + pos.h;
+                            pdf_ann_left(q) = pos.h;
+                            if (pdf_ann_left(q) > pdf_ann_right(q)) {
+                                halfword r = pdf_ann_right(q);
+                                halfword l = pdf_ann_left(q);
+                                pdf_ann_right(q) = pos.h - r;
+                                pdf_ann_left(q) = pos.h;
+                            }
+                            break;
+                        }
+                        /* end of experiment */
+                    }
                     if (pdf_ann_left(q)<pdf_ann_right(q)) {
-                      pdf_ann_left(q) = pos.h - pdf_link_margin;
+                        pdf_ann_left(q) = pos.h;
                     } else {
-                      pdf_ann_right(q) = pos.h - pdf_link_margin;
+                        pdf_ann_right(q) = pos.h;
                     } 
                     break;
                 case dir_LTL:
                 case dir_RTT:
-                    pdf_ann_bottom(q) = pos.v - pdf_link_margin;
+                    pdf_ann_bottom(q) = pos.v;
                     break;
                 default:
-                    pdf_ann_right(q) = pos.h + pdf_link_margin;
+                    pdf_ann_right(q) = pos.h;
                     formatted_warning("pdf backend","forcing bad dir %i to TLT in link",pdf->posstruct->dir);
+                    break;
             }
         }
     }
@@ -147,12 +167,13 @@
     scaled_whd alt_rule;
     p = copy_node(pdf->link_stack[(int) i].link_node);
     pdf->link_stack[(int) i].ref_link_node = p;
+    pdf->link_stack[(int) i].count++;
     /*tex This node is not a normal link node. */
     subtype(p) = pdf_link_data_node;
     alt_rule.wd = width(p);
     alt_rule.ht = height(p);
     alt_rule.dp = depth(p);
-    set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_link_margin);
+    set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
     k = pdf_create_obj(pdf, obj_type_others, 0);
     obj_annot_ptr(pdf, k) = p;
     set_obj_scheduled(pdf, pdf_link_objnum(p));

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.c	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.c	2023-01-24 16:49:02 UTC (rev 65617)
@@ -154,6 +154,110 @@
     return enddir_ptr;
 }
 
+/*tex 
+    With |\pdfvariable linking = 1| a few alternative code paths witll be used that try to compensate 
+    for multiline side effects as well as left- and right skip (no other skips yet). After days of 
+    looking for better ways I settled on this hackery approach. After all for > 15 years we had the 
+    old handling and so a flag makes sense. I (HH) don't use this code myself so it's a it of a 
+    gamble wrt usage scenarios. 
+*/
+
+halfword calculate_width_to_endlink(halfword p, halfword this_box, halfword *leftskip, halfword *rightskip)
+{
+    halfword q = p;
+    scaled w = 0;
+    /*tex The glue value before rounding: */
+    real glue_temp;
+    real cur_glue = 0.0;
+    int level = 0; 
+    /*tex rounded equivalent of |cur_glue| times the glue ratio */
+    scaled cur_g = 0;
+    int g_sign = glue_sign(this_box);
+    int g_order = glue_order(this_box);
+    *leftskip = 0;
+    while (q != null) {
+        if (is_char_node(q))
+            w += pack_width(box_dir(this_box), dir_TRT, q, true);
+        else {
+            switch (type(q)) {
+                case hlist_node:
+                case vlist_node:
+                    w += pack_width(box_dir(this_box), box_dir(q), q, false);
+                    break;
+                case rule_node:
+                case margin_kern_node:
+                    w += width(q);
+                    break;
+                case kern_node:
+                    /*tex Officially we should check the subtype. */
+                    w += kern_width(q);
+                    break;
+                case math_node:
+                    /*tex Begin of |mathskip| code. */
+                    if (glue_is_zero(q)) {
+                        w += surround(q);
+                        break;
+                    } else {
+                        /*tex Fall through |mathskip|. */
+                    }
+                    /*tex End of |mathskip| code. */
+                case glue_node:
+                    /* this is a terrible hack related to multiline links with directions */
+                    {
+                        halfword ww = w; 
+
+                        w += width(q) - cur_g;
+                        if (g_sign != normal) {
+                            if (g_sign == stretching) {
+                                if (stretch_order(q) == g_order) {
+                                    cur_glue = cur_glue + stretch(q);
+                                    vet_glue(float_cast(glue_set(this_box)) * cur_glue);
+                                    cur_g = float_round(glue_temp);
+                                }
+                            } else if (shrink_order(q) == g_order) {
+                                cur_glue = cur_glue - shrink(q);
+                                vet_glue(float_cast(glue_set(this_box)) * cur_glue);
+                                cur_g = float_round(glue_temp);
+                            }
+                        }
+                        w += cur_g;
+                        /* also experiment */
+                        if (type(q) == glue_node) { 
+                            if (subtype(q) == left_skip_glue) { 
+                                *leftskip = w - ww; 
+                                w = ww; 
+                            } else if (subtype(q) == right_skip_glue) { 
+                                *rightskip = w - ww; 
+                                w = ww; 
+                            }
+                        }
+                    }
+                    break;
+                case disc_node:
+                    /* (HH): The frontend should append already. */
+                    if (vlink(no_break(q)) != null)
+                        w += simple_advance_width(no_break(q));
+                    break;
+                case whatsit_node:
+                    if (subtype(q) == pdf_end_link_node) {
+                        if (level == 0) {
+                            return w;
+                        } else {
+                            --level;
+                        }
+                    } else if (subtype(q) == pdf_start_link_node) {
+                        ++level;
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+        q = vlink(q);
+    }
+    return w;
+}
+
 /*tex
 
     The |out_what| procedure takes care of outputting the whatsit nodes for
@@ -260,7 +364,7 @@
                 We ignore this link. This is a compatibility-with-pdftex feature needed for latex. It
                 is suboptimal in the sense that when the whatsit is set, the next box is influenced,
                 so there there can be side effects when used in the middle of a line, when using
-                vadjust, etc. But we can assume that tha macro package knows when and where this
+                vadjust, etc. But we can assume that the macro package knows when and where this
                 mechanism is triggered, so a more sophisticated solution is not needed (and would be
                 confusing in its own anyway.)
 
@@ -267,6 +371,7 @@
                 I would not be surprised of we have some leak here but it's harmless.
            */
         } else if (pdf->link_stack[i].nesting_level == cur_s) {
+            /* hm, cur is zero */
             append_link(pdf, this_box, cur, (small_number) i);
         }
     }
@@ -413,130 +518,130 @@
                                 vet_glue(float_cast(glue_set(this_box)) * cur_glue);
                                 cur_g = float_round(glue_temp);
                             }
-                    }
-                    rule.wd = rule.wd + cur_g;
-                    if (subtype(p) >= a_leaders) {
-                        /*tex
-                            Output leaders in an hlist, |goto fin_rule| if a rule
-                            or to |next_p| if done.
-                        */
-                        leader_box = leader_ptr(p);
-                        if (type(leader_box) == rule_node) {
-                            rule.ht = height(leader_box);
-                            rule.dp = depth(leader_box);
-                            rleft = 0;
-                            rright = 0;
-                            goto FIN_RULE;
                         }
-                        if (textdir_parallel(box_dir(leader_box), localpos.dir))
-                            leader_wd = width(leader_box);
-                        else
-                            leader_wd = height(leader_box) + depth(leader_box);
-                        if ((leader_wd > 0) && (rule.wd > 0)) {
-                            /*tex Compensate for floating-point rounding. */
-                            rule.wd = rule.wd + 10;
-                            edge = cur.h + rule.wd;
-                            lx = 0;
+                        rule.wd = rule.wd + cur_g;
+                        if (subtype(p) >= a_leaders) {
                             /*tex
-                                Let |cur.h| be the position of the first box, and
-                                set |leader_wd+lx| to the spacing between
-                                corresponding parts of boxes.
+                                Output leaders in an hlist, |goto fin_rule| if a rule
+                                or to |next_p| if done.
                             */
-                            if (subtype(p) == g_leaders) {
-                                save_h = cur.h;
-                                switch (localpos.dir) {
-                                    case dir_TLT:
-                                        cur.h += refpos->pos.h - shipbox_refpos.h;
-                                        cur.h = leader_wd * (cur.h / leader_wd);
-                                        cur.h -= refpos->pos.h - shipbox_refpos.h;
-                                        break;
-                                    case dir_TRT:
-                                        cur.h = refpos->pos.h - shipbox_refpos.h - cur.h;
-                                        cur.h = leader_wd * (cur.h / leader_wd);
-                                        cur.h = refpos->pos.h - shipbox_refpos.h - cur.h;
-                                        break;
-                                    case dir_LTL:
-                                    case dir_RTT:
-                                        cur.h = refpos->pos.v - shipbox_refpos.v - cur.h;
-                                        cur.h = leader_wd * (cur.h / leader_wd);
-                                        cur.h = refpos->pos.v - shipbox_refpos.v - cur.h;
-                                        break;
-                                    default:
-                                        formatted_warning("pdf backend","forcing bad dir %i to TLT in hlist case 1",localpos.dir);
-                                        localpos.dir = dir_TLT;
-                                        cur.h += refpos->pos.h - shipbox_refpos.h;
-                                        cur.h = leader_wd * (cur.h / leader_wd);
-                                        cur.h -= refpos->pos.h - shipbox_refpos.h;
-                                        break;
-                                }
-                                if (cur.h < save_h)
-                                    cur.h += leader_wd;
-                            } else if (subtype(p) == a_leaders) {
-                                save_h = cur.h;
-                                cur.h = leader_wd * (cur.h / leader_wd);
-                                if (cur.h < save_h)
-                                    cur.h += leader_wd;
-                            } else {
-                                /*tex The number of box copies: */
-                                lq = rule.wd / leader_wd;
-                                /*tex The remaining space: */
-                                lr = rule.wd % leader_wd;
-                                if (subtype(p) == c_leaders) {
-                                    cur.h += lr / 2;
-                                } else {
-                                    lx = lr / (lq + 1);
-                                    cur.h += (lr - (lq - 1) * lx) / 2;
-                                }
+                            leader_box = leader_ptr(p);
+                            if (type(leader_box) == rule_node) {
+                                rule.ht = height(leader_box);
+                                rule.dp = depth(leader_box);
+                                rleft = 0;
+                                rright = 0;
+                                goto FIN_RULE;
                             }
-                            while (cur.h + leader_wd <= edge) {
+                            if (textdir_parallel(box_dir(leader_box), localpos.dir))
+                                leader_wd = width(leader_box);
+                            else
+                                leader_wd = height(leader_box) + depth(leader_box);
+                            if ((leader_wd > 0) && (rule.wd > 0)) {
+                                /*tex Compensate for floating-point rounding. */
+                                rule.wd = rule.wd + 10;
+                                edge = cur.h + rule.wd;
+                                lx = 0;
                                 /*tex
-                                    Output a leader box at |cur.h|, then advance
-                                    |cur.h| by |leader_wd+lx|.
+                                    Let |cur.h| be the position of the first box, and
+                                    set |leader_wd+lx| to the spacing between
+                                    corresponding parts of boxes.
                                 */
-                                if (pardir_parallel(box_dir(leader_box), localpos.dir)) {
-                                    basepoint.v = 0;
-                                    if (textdir_opposite(box_dir(leader_box), localpos.dir))
-                                        basepoint.h = width(leader_box);
-                                    else
-                                        basepoint.h = 0;
+                                if (subtype(p) == g_leaders) {
+                                    save_h = cur.h;
+                                    switch (localpos.dir) {
+                                        case dir_TLT:
+                                            cur.h += refpos->pos.h - shipbox_refpos.h;
+                                            cur.h = leader_wd * (cur.h / leader_wd);
+                                            cur.h -= refpos->pos.h - shipbox_refpos.h;
+                                            break;
+                                        case dir_TRT:
+                                            cur.h = refpos->pos.h - shipbox_refpos.h - cur.h;
+                                            cur.h = leader_wd * (cur.h / leader_wd);
+                                            cur.h = refpos->pos.h - shipbox_refpos.h - cur.h;
+                                            break;
+                                        case dir_LTL:
+                                        case dir_RTT:
+                                            cur.h = refpos->pos.v - shipbox_refpos.v - cur.h;
+                                            cur.h = leader_wd * (cur.h / leader_wd);
+                                            cur.h = refpos->pos.v - shipbox_refpos.v - cur.h;
+                                            break;
+                                        default:
+                                            formatted_warning("pdf backend","forcing bad dir %i to TLT in hlist case 1",localpos.dir);
+                                            localpos.dir = dir_TLT;
+                                            cur.h += refpos->pos.h - shipbox_refpos.h;
+                                            cur.h = leader_wd * (cur.h / leader_wd);
+                                            cur.h -= refpos->pos.h - shipbox_refpos.h;
+                                            break;
+                                    }
+                                    if (cur.h < save_h)
+                                        cur.h += leader_wd;
+                                } else if (subtype(p) == a_leaders) {
+                                    save_h = cur.h;
+                                    cur.h = leader_wd * (cur.h / leader_wd);
+                                    if (cur.h < save_h)
+                                        cur.h += leader_wd;
                                 } else {
-                                    if (!is_mirrored(box_dir(leader_box))) {
-                                        if (partextdir_eq(box_dir(leader_box), localpos.dir))
-                                            basepoint.h = height(leader_box);
+                                    /*tex The number of box copies: */
+                                    lq = rule.wd / leader_wd;
+                                    /*tex The remaining space: */
+                                    lr = rule.wd % leader_wd;
+                                    if (subtype(p) == c_leaders) {
+                                        cur.h += lr / 2;
+                                    } else {
+                                        lx = lr / (lq + 1);
+                                        cur.h += (lr - (lq - 1) * lx) / 2;
+                                    }
+                                }
+                                while (cur.h + leader_wd <= edge) {
+                                    /*tex
+                                        Output a leader box at |cur.h|, then advance
+                                        |cur.h| by |leader_wd+lx|.
+                                    */
+                                    if (pardir_parallel(box_dir(leader_box), localpos.dir)) {
+                                        basepoint.v = 0;
+                                        if (textdir_opposite(box_dir(leader_box), localpos.dir))
+                                            basepoint.h = width(leader_box);
                                         else
-                                            basepoint.h = depth(leader_box);
+                                            basepoint.h = 0;
                                     } else {
-                                        if (partextdir_eq(box_dir(leader_box), localpos.dir))
-                                            basepoint.h = depth(leader_box);
+                                        if (!is_mirrored(box_dir(leader_box))) {
+                                            if (partextdir_eq(box_dir(leader_box), localpos.dir))
+                                                basepoint.h = height(leader_box);
+                                            else
+                                                basepoint.h = depth(leader_box);
+                                        } else {
+                                            if (partextdir_eq(box_dir(leader_box), localpos.dir))
+                                                basepoint.h = depth(leader_box);
+                                            else
+                                                basepoint.h = height(leader_box);
+                                        }
+                                        if (partextdir_eq(localpos.dir, box_dir(leader_box)))
+                                            basepoint.v = -(width(leader_box) / 2);
                                         else
-                                            basepoint.h = height(leader_box);
+                                            basepoint.v = (width(leader_box) / 2);
                                     }
-                                    if (partextdir_eq(localpos.dir, box_dir(leader_box)))
-                                        basepoint.v = -(width(leader_box) / 2);
+                                    if (!is_mirrored(localpos.dir))
+                                        basepoint.v = basepoint.v + shift_amount(leader_box); /* shift the box down */
                                     else
-                                        basepoint.v = (width(leader_box) / 2);
+                                        basepoint.v = basepoint.v - shift_amount(leader_box); /* shift the box up */
+                                    tmpcur.h = cur.h + basepoint.h;
+                                    tmpcur.v = basepoint.v;
+                                    synch_pos_with_cur(pdf->posstruct, refpos, tmpcur);
+                                    outer_doing_leaders = doing_leaders;
+                                    doing_leaders = true;
+                                    if (type(leader_box) == vlist_node)
+                                        vlist_out(pdf, leader_box, rule_callback_id);
+                                    else
+                                        hlist_out(pdf, leader_box, rule_callback_id);
+                                    doing_leaders = outer_doing_leaders;
+                                    cur.h += leader_wd + lx;
                                 }
-                                if (!is_mirrored(localpos.dir))
-                                    basepoint.v = basepoint.v + shift_amount(leader_box); /* shift the box down */
-                                else
-                                    basepoint.v = basepoint.v - shift_amount(leader_box); /* shift the box up */
-                                tmpcur.h = cur.h + basepoint.h;
-                                tmpcur.v = basepoint.v;
-                                synch_pos_with_cur(pdf->posstruct, refpos, tmpcur);
-                                outer_doing_leaders = doing_leaders;
-                                doing_leaders = true;
-                                if (type(leader_box) == vlist_node)
-                                    vlist_out(pdf, leader_box, rule_callback_id);
-                                else
-                                    hlist_out(pdf, leader_box, rule_callback_id);
-                                doing_leaders = outer_doing_leaders;
-                                cur.h += leader_wd + lx;
+                                cur.h = edge - 10;
+                                goto NEXTP;
                             }
-                            cur.h = edge - 10;
-                            goto NEXTP;
                         }
                     }
-                    }
                     goto MOVE_PAST;
                     break;
                 case kern_node:

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.h	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.h	2023-01-24 16:49:02 UTC (rev 65617)
@@ -29,4 +29,6 @@
 extern void hlist_out(PDF pdf, halfword this_box, int rule_callback_id);
 extern void vlist_out(PDF pdf, halfword this_box, int rule_callback_id);
 
+extern halfword calculate_width_to_endlink(halfword p, halfword this_box, halfword *leftskip, halfword *rightskip);
+
 #endif

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c	2023-01-24 16:49:02 UTC (rev 65617)
@@ -221,22 +221,56 @@
     }
 }
 
-void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, scaled_whd alt_rule, scaled margin)
+/* 
+    The next helper is needed for multiline TRT links. Several variants were tried but in the end 
+    this one is the most reliable: we calculate the width till we meet an endlink or the end of 
+    the line. When we have an inline one, for now we just use the old method and keep the running
+    property (that way we're compatible). For practical purposes this calculation resides in the 
+    file that handles the list. By moving the code here instead of dealing with it in lists we 
+    handle all rectangles but we'll see where that fails in which case we will have a parameter 
+    passed to |set_rect_dimens| and have control per feature, maybe even under parameter control.
+*/
+
+void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, scaled_whd alt_rule)
 {
-    /*tex The positions relative to cur: */
+    /*tex 
+        The positions relative to cur: |pdf| contains current point on page):
+    */
     scaledpos ll, ur, pos_ll, pos_ur;
     posstructure localpos;
     localpos.dir = pdf->posstruct->dir;
-    /*tex |pdf| contains current point on page: */
-    ll.h = 0;
+
+    halfword lcrap = 0;
+    halfword rcrap = 0;
+    halfword lskip = 0;
+    halfword rskip = 0;
+
+    if (pdf_linking) {
+        /* begin of experiment */
+        if (subtype(p) == pdf_link_data_node) { 
+            alt_rule.wd = calculate_width_to_endlink(list_ptr(parent_box), parent_box, &lskip, &rskip);
+            if (pdf->link_stack[pdf->link_stack_ptr].direction == dir_TRT) {
+                alt_rule.wd = -alt_rule.wd;
+                localpos.dir = dir_TRT;
+                lcrap = lskip;
+            } else { 
+                lcrap = -lskip;
+            }
+        } else if (subtype(p) == pdf_start_link_node) { 
+            alt_rule.wd = calculate_width_to_endlink(p, parent_box, &lskip, &rskip);
+        }
+        /* end of experiment */
+    }
+
+    ll.h = - lcrap - rcrap;
+    if (is_running(alt_rule.wd))
+        ur.h = width(parent_box) - cur.h;
+    else
+        ur.h = alt_rule.wd - lcrap - rcrap;
     if (is_running(alt_rule.dp))
         ll.v = depth(parent_box) - cur.v;
     else
         ll.v = alt_rule.dp;
-    if (is_running(alt_rule.wd))
-        ur.h = width(parent_box) - cur.h;
-    else
-        ur.h = alt_rule.wd;
     if (is_running(alt_rule.ht))
         ur.v = -height(parent_box) - cur.v;
     else
@@ -257,10 +291,10 @@
         pos_ur.h = geturx();
         pos_ur.v = getury();
     }
-    pdf_ann_left(p) = pos_ll.h - margin;
-    pdf_ann_bottom(p) = pos_ll.v - margin;
-    pdf_ann_right(p) = pos_ur.h + margin;
-    pdf_ann_top(p) = pos_ur.v + margin;
+    pdf_ann_left(p) = pos_ll.h;
+    pdf_ann_bottom(p) = pos_ll.v;
+    pdf_ann_right(p) = pos_ur.h;
+    pdf_ann_top(p) = pos_ur.v;
 }
 
 void libpdffinish(PDF pdf)

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.h	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.h	2023-01-24 16:49:02 UTC (rev 65617)
@@ -108,7 +108,7 @@
 extern void check_obj_type(PDF pdf, int t, int objnum);
 extern int pdf_get_obj(PDF pdf, int t, int i, boolean byname);
 extern int pdf_create_obj(PDF pdf, int t, int i);
-extern void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, scaled_whd alt_rule, scaled margin);
+extern void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, scaled_whd alt_rule);
 extern void libpdffinish(PDF);
 
 #  define set_width(A,B)  width(A)=(B)
@@ -143,6 +143,7 @@
     c_pdf_omit_charset,
     c_pdf_omit_infodict,
     c_pdf_omit_mediabox,
+    c_pdf_linking,
 } pdf_backend_counters ;
 
 typedef enum {
@@ -195,6 +196,7 @@
 #  define pdf_omit_infodict             get_tex_extension_count_register(c_pdf_omit_infodict)
 #  define pdf_omit_mediabox             get_tex_extension_count_register(c_pdf_omit_mediabox)
 #  define pdf_recompress                get_tex_extension_count_register(c_pdf_recompress)
+#  define pdf_linking                   get_tex_extension_count_register(c_pdf_linking)
 
 #  define pdf_h_origin                  get_tex_extension_dimen_register(d_pdf_h_origin)
 #  define pdf_v_origin                  get_tex_extension_dimen_register(d_pdf_v_origin)
@@ -221,6 +223,7 @@
 #  define set_pdf_omit_mediabox(i)      set_tex_extension_count_register(c_pdf_omit_mediabox,i)
 #  define set_pdf_gen_tounicode(i)      set_tex_extension_count_register(c_pdf_gen_tounicode,i)
 #  define set_pdf_recompress(i)         set_tex_extension_count_register(c_pdf_recompress,i)
+#  define set_pdf_linking(i)            set_tex_extension_count_register(c_pdf_linking,i)
 
 #  define set_pdf_decimal_digits(i)     set_tex_extension_count_register(c_pdf_decimal_digits,i)
 #  define set_pdf_pk_resolution(i)      set_tex_extension_count_register(c_pdf_pk_resolution,i)

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdfthread.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdfthread.c	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdfthread.c	2023-01-24 16:49:02 UTC (rev 65617)
@@ -76,7 +76,8 @@
     alt_rule.wd = width(p);
     alt_rule.ht = height(p);
     alt_rule.dp = depth(p);
-    set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_thread_margin);
+    pdf_ann_margin(p) = pdf_thread_margin;
+    set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
     append_bead(pdf, p);
     pdf->last_thread = p;
 }
@@ -99,7 +100,7 @@
     alt_rule.wd = width(p);
     alt_rule.ht = height(p);
     alt_rule.dp = depth(p);
-    set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_thread_margin);
+    set_rect_dimens(pdf, p, parent_box, cur, alt_rule);
     append_bead(pdf, p);
     pdf->last_thread = p;
 }
@@ -115,13 +116,13 @@
         switch (pdf->posstruct->dir) {
             case dir_TLT:
             case dir_TRT:
-                pdf_ann_bottom(pdf->last_thread) = pos.v - pdf_thread_margin;
+                pdf_ann_bottom(pdf->last_thread) = pos.v;
                 break;
             case dir_LTL:
-                pdf_ann_right(pdf->last_thread) = pos.h + pdf_thread_margin;
+                pdf_ann_right(pdf->last_thread) = pos.h;
                 break;
             case dir_RTT:
-                pdf_ann_left(pdf->last_thread) = pos.h - pdf_thread_margin;
+                pdf_ann_left(pdf->last_thread) = pos.h;
                 break;
             default:
                 formatted_warning("pdf backend","forcing bad dir %i to TLT in end tread",pdf->posstruct->dir);

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h	2023-01-24 16:49:02 UTC (rev 65617)
@@ -190,6 +190,8 @@
     int ref_link_node;          /* points to original |pdf_start_link_node|, or a
                                    copy of |link_node| created by |append_link| in
                                    case of multi-line link */
+    int direction;
+    int count; 
 } pdf_link_stack_record;
 
 /* types of objects */

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.h	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.h	2023-01-24 16:49:02 UTC (rev 65617)
@@ -876,9 +876,9 @@
 
 #  define pdf_obj_objnum(a) vinfo((a) + 2)
 
-#  define pdf_annot_node_size 8
-#  define pdf_dest_node_size 8
-#  define pdf_thread_node_size 8
+#  define pdf_annot_node_size  9 /* all need the same size, rect margin related ! */
+#  define pdf_dest_node_size   9
+#  define pdf_thread_node_size 9
 
 /*
     when a whatsit node representing annotation is created, words |1..3| are
@@ -895,6 +895,7 @@
 #  define pdf_ann_top(a)            varmem[(a) + 3].cint
 #  define pdf_ann_right(a)          varmem[(a) + 4].cint
 #  define pdf_ann_bottom(a)         varmem[(a) + 5].cint
+#  define pdf_ann_margin(a)         varmem[(a) + 8].cint  /* so all need to have the same size */
 
 #  define pdf_literal_data(a)       vlink((a)+2)
 #  define pdf_literal_mode(a)       type((a)+2)

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c	2023-01-24 16:49:02 UTC (rev 65617)
@@ -2619,10 +2619,11 @@
     else if (scan_keyword("pkfixeddpi"))           { do_variable_backend_int(c_pdf_pk_fixed_dpi); }
     else if (scan_keyword("suppressoptionalinfo")) { do_variable_backend_int(c_pdf_suppress_optional_info); }
     else if (scan_keyword("omitcidset"))           { do_variable_backend_int(c_pdf_omit_cidset); }
+    else if (scan_keyword("recompress"))           { do_variable_backend_int(c_pdf_recompress); }
     else if (scan_keyword("omitcharset"))          { do_variable_backend_int(c_pdf_omit_charset); }
     else if (scan_keyword("omitinfodict"))         { do_variable_backend_int(c_pdf_omit_infodict); }
     else if (scan_keyword("omitmediabox"))         { do_variable_backend_int(c_pdf_omit_mediabox); }
-    else if (scan_keyword("recompress"))           { do_variable_backend_int(c_pdf_recompress); }
+    else if (scan_keyword("linking"))              { do_variable_backend_int(c_pdf_linking); }
 
     else if (scan_keyword("horigin"))              { do_variable_backend_dimen(d_pdf_h_origin); }
     else if (scan_keyword("vorigin"))              { do_variable_backend_dimen(d_pdf_v_origin); }

Modified: trunk/Master/texmf-dist/doc/luatex/base/luatex-modifications.tex
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/base/luatex-modifications.tex	2023-01-24 00:50:53 UTC (rev 65616)
+++ trunk/Master/texmf-dist/doc/luatex/base/luatex-modifications.tex	2023-01-24 16:49:02 UTC (rev 65617)
@@ -1,4 +1,4 @@
-% language=uk engine=luatex runpath=texruns:manuals/luatex
+% language=us engine=luatex runpath=texruns:manuals/luatex
 
 \environment luatex-style
 
@@ -1146,7 +1146,7 @@
 paragraphs with only a local par node followed by direction synchronization
 nodes. Paragraphs like that are seen as empty paragraphs and therefore ignored.
 Because \type {\noindent} doesn't inject anything but a \type {\indent} injects
-an box, paragraphs with only an indent and directions are handles as paragraphs
+an box, paragraphs with only an indent and directions are handled as paragraphs
 with content.
 
 \stopsubsection
@@ -1407,6 +1407,26 @@
 
 \stopsubsection
 
+\startsubsection[title=Hyperlinks]
+
+\topicindex {hyperlinks}
+
+There is an experimental feature that makes multi|-|line hyper links behave a
+little better, fixing some side effects that showed up in r2l typesetting but
+also can surface in l2r. Because this got unnoticed till 2023, and because it
+depends bit on how macro packages deal with hyper links, the fix is currently
+under parameter control:
+
+\starttyping
+\pdfvariable linking = 1
+\stoptyping
+
+That way (we hope) legacy documents come out as expected, whatever those
+expectations are. One of the aspects dealt with concerns (unusual) left and right
+skips.
+
+\stopsubsection
+
 \stopsection
 
 \stopchapter

Modified: trunk/Master/texmf-dist/doc/luatex/base/luatex.pdf
===================================================================
(Binary files differ)



More information about the tex-live-commits mailing list.