From 1bc23706fb56fd497a1519809308bacc9d64bc3d Mon Sep 17 00:00:00 2001 From: Ulrike Fischer Date: Wed, 3 Apr 2024 13:47:04 +0200 Subject: [PATCH] backend support for indexed structure destinations --- CHANGELOG.md | 3 +- l3backend-testphase.dtx | 259 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 255 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f3c34f3..10faf8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ this project uses date-based 'snapshot' version identifiers. ### Changed - use \pdf_object_ref:n instead of backend command as preparation of l3kernel changes regarding object storing. - + - support for structure destination if indexed objects are used + ## [2024-03-26] Version: 2024-03-26, 0.96g diff --git a/l3backend-testphase.dtx b/l3backend-testphase.dtx index 74039a3a..2e817e13 100644 --- a/l3backend-testphase.dtx +++ b/l3backend-testphase.dtx @@ -1808,7 +1808,7 @@ { \cs_gset_eq:NN \@@_backend_destination:nn \@@_backend_indexed_structure_destination:nn \cs_gset_eq:NN \@@_backend_destination:nnnn \@@_backend_indexed_structure_destination:nnnn - \cs_gset_eq:NN \@@_backend_link_begin_goto:nnw \@@_backend_indexed_link_begin_structure_goto:nnw + \cs_gset_eq:NN \@@_backend_link_begin_goto:nnw \@@_backend_link_begin_structure_goto:nnw } % % \end{macrocode} @@ -1821,13 +1821,15 @@ % \begin{macrocode} %<*drivers> \cs_set_eq:NN \@@_backend_structure_destination:nn \@@_backend_destination:nn -\cs_set_eq:NN \@@_backend_structure_destination:nnnn \@@_backend_destination:nnnn +\cs_set_eq:NN \@@_backend_structure_destination:nnnn \@@_backend_destination:nnnn \cs_set_eq:NN \@@_backend_link_begin_structure_goto:nnw \@@_backend_link_begin_goto:nnw % % \end{macrocode} -% \begin{macro}{\@@_backend_structure_destination:nn} -% This command is the backend command to create a destination. -% It should in parallel create also a structure destination. +% \begin{macro}{\@@_backend_structure_destination:nn, +% \@@_backend_structure_destination:nnnn, +% \@@_backend_link_begin_structure_goto:nnw} +% These commands are the backend commands to create a destination. +% which create also a structure destination. % At first xetex/dvipdfmx. % The structure destination is an array, so we use obj for it % so that we can reference it: @@ -1952,7 +1954,6 @@ } % % \end{macrocode} -% \end{macro} % Now pdftex. We only redefine for version 1.40 revision 24 or later. % \begin{macrocode} %<*pdftex> @@ -2099,6 +2100,252 @@ } % % \end{macrocode} +% \end{macro} + +% \begin{macro}{\@@_backend_indexed_structure_destination:nn, +% \@@_backend_indexed_structure_destination:nnnn} +% This are the indexed variants of the commands to create a destination +% and a structure destination. +% At first xetex/dvipdfmx. +% The structure destination is an array, so we use obj for it +% so that we can reference it: +% \begin{macrocode} +%<*xdvipdfmx|dvipdfmx> +\cs_set_protected:Npn \@@_backend_indexed_structure_destination:nn #1#2 + { + \@@_backend:e + { + dest ~ ( \exp_not:n {#1} ) + [ + @thispage + \str_case:nnF {#2} + { + { xyz } { /XYZ ~ @xpos ~ @ypos ~ null } + { fit } { /Fit } + { fitb } { /FitB } + { fitbh } { /FitBH } + { fitbv } { /FitBV ~ @xpos } + { fith } { /FitH ~ @ypos } + { fitv } { /FitV ~ @xpos } + { fitr } { /Fit } + } + { /XYZ ~ @xpos ~ @ypos ~ \fp_eval:n { (#2) / 100 } } + ] + } +% \end{macrocode} +% We do not test anymore if the structure object exist. The object of the structure destination +% gets the name \texttt{@pdf.Sdest.\meta{destname}}, where \meta{destname} is the +% name of the standard destination so that we can reference it in the GoTo links. +% \begin{macrocode} + \@@_backend:e + { + obj ~ @pdf.SDest.\exp_not:n{#1} + [ + \exp_after:wN \pdf_object_ref_indexed:nn \l_pdf_current_structure_destination_tl + \str_case:nnF {#2} + { + { xyz } { /XYZ ~ @xpos ~ @ypos ~ null } + { fit } { /Fit } + { fitb } { /FitB } + { fitbh } { /FitBH } + { fitbv } { /FitBV ~ @xpos } + { fith } { /FitH ~ @ypos } + { fitv } { /FitV ~ @xpos } + { fitr } { /Fit } + } + { /XYZ ~ @xpos ~ @ypos ~ \fp_eval:n { (#2) / 100 } } + ] + } + } +% \end{macrocode} +% The second destination command is for the boxed destination. Here we need to define +% an new auxiliary command: +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_indexed_structure_destination_aux:nnnn #1#2#3#4 + { + \vbox_to_zero:n + { + \__kernel_kern:n {#4} + \hbox:n + { + \@@_backend:n { obj ~ @pdf_ #2 _llx ~ @xpos } + \@@_backend:n { obj ~ @pdf_ #2 _lly ~ @ypos } + } + \tex_vss:D + } + \__kernel_kern:n {#1} + \vbox_to_zero:n + { + \__kernel_kern:n { -#3 } + \hbox:n + { + \@@_backend:n + { + dest ~ (#2) + [ + @thispage + /FitR ~ + @pdf_ #2 _llx ~ @pdf_ #2 _lly ~ + @xpos ~ @ypos + ] + } +% \end{macrocode} +% Here we add the structure destination to the same box +% \begin{macrocode} + \@@_backend:e + { + obj ~ @pdf.SDest.\exp_not:n{#2} + [ + \exp_after:wN \pdf_object_ref_indexed:nn \l_pdf_current_structure_destination_tl + /FitR ~ + @pdf_ #2 _llx ~ @pdf_ #2 _lly ~ + @xpos ~ @ypos + ] + } + } + \tex_vss:D + } + \__kernel_kern:n { -#1 } + } +% \end{macrocode} +% And now we redefine the destination command: +% \begin{macrocode} +\cs_set_protected:Npn \@@_backend_indexed_structure_destination:nnnn #1#2#3#4 + { + \exp_args:Ne \@@_backend_indexed_structure_destination_aux:nnnn + { \dim_eval:n {#2} } {#1} {#3} {#4} + } +% \end{macrocode} +% +% \end{macrocode} +% Now pdftex. We only redefine for version 1.40 revision 24 or later. +% \begin{macrocode} +%<*pdftex> +\bool_lazy_and:nnT + { \int_compare_p:nNn {\tex_pdftexversion:D } > {139} } + { \int_compare_p:nNn {\tex_pdftexrevision:D } > {23} } + { + \cs_set_protected:Npn \@@_backend_indexed_structure_destination:nn #1#2 + { + \tex_pdfdest:D + name {#1} + \str_case:nnF {#2} + { + { xyz } { xyz } + { fit } { fit } + { fitb } { fitb } + { fitbh } { fitbh } + { fitbv } { fitbv } + { fith } { fith } + { fitv } { fitv } + { fitr } { fitr } + } + { xyz ~ zoom \fp_eval:n { #2 * 10 } } + \scan_stop: + \tex_pdfdest:D + struct~ + \exp_after:wN \__kernel_pdf_object_id_indexed:nn \l_pdf_current_structure_destination_tl ~ + name {#1} + \str_case:nnF {#2} + { + { xyz } { xyz } + { fit } { fit } + { fitb } { fitb } + { fitbh } { fitbh } + { fitbv } { fitbv } + { fith } { fith } + { fitv } { fitv } + { fitr } { fitr } + } + { xyz ~ zoom \fp_eval:n { #2 * 10 } } + \scan_stop: + } + \cs_set_protected:Npn \@@_backend_indexed_structure_destination:nnnn #1#2#3#4 + { + \tex_pdfdest:D + name {#1} + fitr ~ + width \dim_eval:n {#2} ~ + height \dim_eval:n {#3} ~ + depth \dim_eval:n {#4} \scan_stop: + \tex_pdfdest:D + struct~ + \exp_after:wN \__kernel_pdf_object_id_indexed:nn \l_pdf_current_structure_destination_tl ~ + name {#1} + fitr ~ + width \dim_eval:n {#2} ~ + height \dim_eval:n {#3} ~ + depth \dim_eval:n {#4} \scan_stop: + } + } +% +% \end{macrocode} +% luatex is quite similar to pdftex. Mostly the test for the version is different +% \begin{macrocode} +%<*luatex> + \int_compare:nNnT {\directlua{tex.print(status.list()["development_id"])} } > {7468} + { + \cs_set_protected:Npn \@@_backend_indexed_structure_destination:nn #1#2 + { + \tex_pdfextension:D dest + name {#1} + \str_case:nnF {#2} + { + { xyz } { xyz } + { fit } { fit } + { fitb } { fitb } + { fitbh } { fitbh } + { fitbv } { fitbv } + { fith } { fith } + { fitv } { fitv } + { fitr } { fitr } + } + { xyz ~ zoom \fp_eval:n { #2 * 10 } } + \scan_stop: + \tex_pdfextension:D dest + struct~ + \exp_after:wN \__kernel_pdf_object_id_indexed:nn \l_pdf_current_structure_destination_tl ~ + name {#1} + \str_case:nnF {#2} + { + { xyz } { xyz } + { fit } { fit } + { fitb } { fitb } + { fitbh } { fitbh } + { fitbv } { fitbv } + { fith } { fith } + { fitv } { fitv } + { fitr } { fitr } + } + { xyz ~ zoom \fp_eval:n { #2 * 10 } } + \scan_stop: + } + \cs_set_protected:Npn \@@_backend_indexed_structure_destination:nnnn #1#2#3#4 + { + \tex_pdfextension:D dest + name {#1} + fitr ~ + width \dim_eval:n {#2} ~ + height \dim_eval:n {#3} ~ + depth \dim_eval:n {#4} \scan_stop: + \tex_pdfextension:D dest + struct~ + \exp_after:wN \__kernel_pdf_object_id_indexed:nn \l_pdf_current_structure_destination_tl~ + name {#1} + fitr ~ + width \dim_eval:n {#2} ~ + height \dim_eval:n {#3} ~ + depth \dim_eval:n {#4} \scan_stop: + } + \cs_set_protected:Npn \@@_backend_link_begin_structure_goto:nnw #1#2 + { + \@@_backend_link_begin:nnnw {#1} { goto~struct~name~{#2}~name } {#2} + } + } +% +% \end{macrocode} +% \end{macro} + % \subsection{Settings for regression tests} % When doing pdf based regression tests some meta data in the pdf should have % fixed values to get identical pdf's. We define here the backend dependant