diff --git a/manual/luatex-modifications.tex b/manual/luatex-modifications.tex index d6dffe27400ecbf63997b9d9a5bfbf60d1d32781..1dd85597aa04e26b051f3c8a22a68f9ca37919b4 100644 --- a/manual/luatex-modifications.tex +++ b/manual/luatex-modifications.tex @@ -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 @@ so a separate grouping related stack is used. A side effect is that there can be 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 @@ incompatible. We already expose some more details. \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 diff --git a/manual/luatex.pdf b/manual/luatex.pdf index a64c02e0399a8117e8dd1c27d2b8a84059ba5654..2df0e1617cd1ebb2499319c3483a86527f4bc834 100644 Binary files a/manual/luatex.pdf and b/manual/luatex.pdf differ diff --git a/source/texk/web2c/luatexdir/ChangeLog b/source/texk/web2c/luatexdir/ChangeLog index 91c534452059441e02115893b57d1afbd59df7d7..268589a75edd67c8599b0558a13b96ec419ab1db 100644 --- a/source/texk/web2c/luatexdir/ChangeLog +++ b/source/texk/web2c/luatexdir/ChangeLog @@ -1,3 +1,6 @@ +2023-01-24 Luigi Scarso <luigi.scarso@gmail.com> + * fix for r2l multiline link etc rectangles (H.Hagen) + 2023-01-17 Luigi Scarso <luigi.scarso@gmail.com> * \pdfvariable omitmediabox 1 (H.Hagen) * luatex 1.16.0 diff --git a/source/texk/web2c/luatexdir/luatex_svnversion.h b/source/texk/web2c/luatexdir/luatex_svnversion.h index cfbc8af82abfe5cf8345c492c53f913449871890..a6eb6c1a29221106f3a999b79c1a698bf039fca3 100644 --- a/source/texk/web2c/luatexdir/luatex_svnversion.h +++ b/source/texk/web2c/luatexdir/luatex_svnversion.h @@ -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 diff --git a/source/texk/web2c/luatexdir/pdf/pdfannot.c b/source/texk/web2c/luatexdir/pdf/pdfannot.c index e501947c78f01cd313010dbd908c3b220a3f95b9..d2a1cb2688e318c75df6ba3f9da2771bf598f99c 100644 --- a/source/texk/web2c/luatexdir/pdf/pdfannot.c +++ b/source/texk/web2c/luatexdir/pdf/pdfannot.c @@ -37,7 +37,7 @@ void do_annot(PDF pdf, halfword p, halfword parent_box, scaledpos cur) 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)); } diff --git a/source/texk/web2c/luatexdir/pdf/pdfdest.c b/source/texk/web2c/luatexdir/pdf/pdfdest.c index ca3c76faa3c569af7283b7a9a13f403fd89f28c1..0a0da0f89ff2e12f9cf620b8261891eb614e6bed 100644 --- a/source/texk/web2c/luatexdir/pdf/pdfdest.c +++ b/source/texk/web2c/luatexdir/pdf/pdfdest.c @@ -105,10 +105,11 @@ void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur) 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,14 +118,14 @@ void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur) 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; 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 @@ void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur) 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; } } diff --git a/source/texk/web2c/luatexdir/pdf/pdfgen.c b/source/texk/web2c/luatexdir/pdf/pdfgen.c index 52d771bc36be1d8b5faf64203c863725e2729f1b..076b324e3347b6fa12a409fa8f62cea247978a16 100644 --- a/source/texk/web2c/luatexdir/pdf/pdfgen.c +++ b/source/texk/web2c/luatexdir/pdf/pdfgen.c @@ -929,10 +929,10 @@ void pdf_add_rect_spec(PDF pdf, halfword r) 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) diff --git a/source/texk/web2c/luatexdir/pdf/pdflink.c b/source/texk/web2c/luatexdir/pdf/pdflink.c index b5bad7a682b2f08bdc37b354ad3c226d3ca51235..ed908e6456cb51ea4b7b83b721da5c03e9326e33 100644 --- a/source/texk/web2c/luatexdir/pdf/pdflink.c +++ b/source/texk/web2c/luatexdir/pdf/pdflink.c @@ -47,6 +47,8 @@ void push_link_level(PDF pdf, halfword p) 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 @@ void do_link(PDF pdf, halfword p, halfword parent_box, scaledpos cur) 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 @@ void end_link(PDF pdf, halfword p) 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 @@ void end_link(PDF pdf, halfword p) 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 @@ void append_link(PDF pdf, halfword parent_box, scaledpos cur, small_number i) 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)); diff --git a/source/texk/web2c/luatexdir/pdf/pdflistout.c b/source/texk/web2c/luatexdir/pdf/pdflistout.c index 02c7025c3301e223574bb8560f278d05df51fbcf..6561626d8ba7de67c75ce377a215a36dcd8094f0 100644 --- a/source/texk/web2c/luatexdir/pdf/pdflistout.c +++ b/source/texk/web2c/luatexdir/pdf/pdflistout.c @@ -154,6 +154,110 @@ static halfword calculate_width_to_enddir(halfword p, real cur_glue, scaled cur_ 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,13 +364,14 @@ void hlist_out(PDF pdf, halfword this_box, int rule_callback_id) 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.) 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 @@ void hlist_out(PDF pdf, halfword this_box, int rule_callback_id) 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: diff --git a/source/texk/web2c/luatexdir/pdf/pdflistout.h b/source/texk/web2c/luatexdir/pdf/pdflistout.h index dd3775816a3ecfac104b72aee88922ae77fa7c18..5d873979a980d651e2060eef7028628ec5a25ca7 100644 --- a/source/texk/web2c/luatexdir/pdf/pdflistout.h +++ b/source/texk/web2c/luatexdir/pdf/pdflistout.h @@ -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 diff --git a/source/texk/web2c/luatexdir/pdf/pdftables.c b/source/texk/web2c/luatexdir/pdf/pdftables.c index f7a0df0063ab90b63c408202ca7f9457314ee76e..66f25ecd7c019dabe1824bd40b14c75681f357b8 100644 --- a/source/texk/web2c/luatexdir/pdf/pdftables.c +++ b/source/texk/web2c/luatexdir/pdf/pdftables.c @@ -221,22 +221,56 @@ void check_obj_type(PDF pdf, int t, int objnum) } } -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 @@ void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, sc 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) diff --git a/source/texk/web2c/luatexdir/pdf/pdftables.h b/source/texk/web2c/luatexdir/pdf/pdftables.h index 57fdec1ce9a23274dd025c4b6629a8ac2f0697e1..578b44aa7788a455cc9cb43dec776877f7961624 100644 --- a/source/texk/web2c/luatexdir/pdf/pdftables.h +++ b/source/texk/web2c/luatexdir/pdf/pdftables.h @@ -108,7 +108,7 @@ extern void check_obj_exists(PDF pdf, int objnum); 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 @@ typedef enum { c_pdf_omit_charset, c_pdf_omit_infodict, c_pdf_omit_mediabox, + c_pdf_linking, } pdf_backend_counters ; typedef enum { @@ -195,6 +196,7 @@ extern int pdf_cur_form; # 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 @@ extern int pdf_cur_form; # 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) diff --git a/source/texk/web2c/luatexdir/pdf/pdfthread.c b/source/texk/web2c/luatexdir/pdf/pdfthread.c index 20cc7bf0a45b97084b70c222b03199dcecff3a92..27dbc557435a8fa58f9216b5e1137954f1750771 100644 --- a/source/texk/web2c/luatexdir/pdf/pdfthread.c +++ b/source/texk/web2c/luatexdir/pdf/pdfthread.c @@ -76,7 +76,8 @@ void do_thread(PDF pdf, halfword p, halfword parent_box, scaledpos cur) 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 @@ void append_thread(PDF pdf, halfword parent_box, scaledpos cur) 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 @@ void end_thread(PDF pdf, halfword p) 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); diff --git a/source/texk/web2c/luatexdir/pdf/pdftypes.h b/source/texk/web2c/luatexdir/pdf/pdftypes.h index f9e1d3ba347d83a822dce18ef630f242bcc28852..d724d1c3492c8018d08615757c0e7cedbf6dce8a 100644 --- a/source/texk/web2c/luatexdir/pdf/pdftypes.h +++ b/source/texk/web2c/luatexdir/pdf/pdftypes.h @@ -190,6 +190,8 @@ typedef struct pdf_link_stack_record { 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 */ diff --git a/source/texk/web2c/luatexdir/tex/texnodes.h b/source/texk/web2c/luatexdir/tex/texnodes.h index a5549deb963bf5e27df1d5475297f90e17b5dbd1..b65efe7b8bc09f2218cb8a78f193e3a73e03a863 100644 --- a/source/texk/web2c/luatexdir/tex/texnodes.h +++ b/source/texk/web2c/luatexdir/tex/texnodes.h @@ -876,9 +876,9 @@ typedef enum { # 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 @@ typedef enum { # 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) diff --git a/source/texk/web2c/luatexdir/tex/textoken.c b/source/texk/web2c/luatexdir/tex/textoken.c index b6f8bbb8c7c2984e7f62fb3fb23d45d2b6f827cd..4abe6377b551bac78431d9f3a91182874e8f9aed 100644 --- a/source/texk/web2c/luatexdir/tex/textoken.c +++ b/source/texk/web2c/luatexdir/tex/textoken.c @@ -2619,10 +2619,11 @@ static int do_variable_pdf(halfword c) 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); }