% \iffalse meta-comment % %% File: tagpdf-mc.dtx % % Copyright (C) 2019-2021 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % https://www.latex-project.org/lppl.txt % % This file is part of the "tagpdf bundle" (The Work in LPPL) % and all files in that bundle must be distributed together. % % ----------------------------------------------------------------------- % % The development version of the bundle can be found at % % https://github.com/u-fischer/tagpdf % % for those people who are interested. %<*driver> \RequirePackage{pdfmanagement-testphase} \DeclareDocumentMetadata{} \makeatletter \declare@file@substitution{doc.sty}{doc-v3beta.sty} \makeatother \documentclass{l3doc} \usepackage{array,booktabs,caption} \hypersetup{pdfauthor=Ulrike Fischer, pdftitle=tagpdf-mc module (tagpdf)} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % \title{^^A % The \pkg{tagpdf-mc-generic} module\\ Code related to Marked Content (mc-chunks), generic mode ^^A % \\ Part of the tagpdf package % } % % \author{^^A % Ulrike Fischer\thanks % {^^A % E-mail: % \href{mailto:fischer@troubleshooting-tex.de} % {fischer@troubleshooting-tex.de}^^A % }^^A % } % % \date{Version 0.91, released 2021-07-03} % \maketitle % \begin{implementation} % \section{Marked content code -- generic mode} % \begin{macrocode} %<@@=tag> %<*generic> \ProvidesExplPackage {tagpdf-mc-code-generic} {2021-07-03} {0.91} {part of tagpdf - code related to marking chunks - generic mode} % % \end{macrocode} % %\subsection{Variables} % % \begin{variable}{\g_@@_MCID_byabspage_prop} % This property will hold the current maximum on a page % it will contain key-value of type \meta{abspagenum}=\meta{max mcid} % % \begin{macrocode} %<*generic> \@@_prop_new:N \g_@@_MCID_byabspage_prop % \end{macrocode} % \end{variable} % \begin{variable}{\l_@@_mc_ref_abspage_tl} % We need a ref-label system to ensure that the MCID cnt % restarts at 0 on a new page % This will be used to store the tagabspage attribute retrieved from % a label. % \begin{macrocode} \tl_new:N \l_@@_mc_ref_abspage_tl % \end{macrocode} % \end{variable} % \begin{variable}{\l_@@_mc_tmpa_tl} % temporary variable % \begin{macrocode} \tl_new:N \l_@@_mc_tmpa_tl % \end{macrocode} % \end{variable} % \subsection{Functions} % \begin{macro}[pTF]{\@@_mc_if_in:,\tag_mc_if_in:} % This is a test if a mc is open or not. It depends simply on a global boolean: % mc-chunks are added linearly so nesting should not be relevant. % \begin{macrocode} \prg_new_conditional:Nnn \@@_mc_if_in: {p,T,F,TF} { \bool_if:NTF \g_@@_in_mc_bool { \prg_return_true: } { \prg_return_false: } } \prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF} % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_mc_bmc:n,\@@_mc_emc:,\@@_mc_bdc:nn,\@@_mc_bdc:nx} % These are the low-level commands. There are now equal to the % pdfmanagement commands generic mode, but we use an indirection % in case luamode need something else. % change 04.08.2018: the commands do not check the validity of the arguments or try % to escape them, this should be done before using them. % \begin{macrocode} % #1 tag, #2 properties \cs_set_eq:NN \@@_mc_bmc:n \pdf_bmc:n \cs_set_eq:NN \@@_mc_emc: \pdf_emc: \cs_set_eq:NN \@@_mc_bdc:nn \pdf_bdc:nn \cs_generate_variant:Nn \@@_mc_bdc:nn {nx} % \end{macrocode} % \end{macro} % % \begin{macro} % { % \@@_mc_bdc_mcid:nn,\@@_mc_bdc_mcid:n, % \@@_mc_handle_mcid:nn,\@@_mc_handle_mcid:VV % } % % This create a BDC mark with an |/MCID| key. Most of the work here is to get % the current number value for the MCID: they must be numbered by page % starting with 0 and then successively. % The first argument is the tag, e.g. |P| or |Span|, the second is used to pass % more properties. % We also define a wrapper around the low-level command as luamode will need % something different. % \begin{macrocode} \cs_new_protected:Npn \@@_mc_bdc_mcid:nn #1 #2 { \int_gincr:N \c@g_@@_MCID_abs_int \tl_set:Nx \l_@@_mc_ref_abspage_tl { \@@_ref_value:enn %3 args { mcid-\int_use:N \c@g_@@_MCID_abs_int } { tagabspage } {-1} } \prop_get:NoNTF \g_@@_MCID_byabspage_prop { \l_@@_mc_ref_abspage_tl } \l_@@_mc_tmpa_tl { %key already present, use value for MCID and add 1 for the next \int_gset:Nn \g_@@_MCID_tmp_bypage_int { \l_@@_mc_tmpa_tl } \@@_prop_gput:Nxx \g_@@_MCID_byabspage_prop { \l_@@_mc_ref_abspage_tl } { \int_eval:n {\l_@@_mc_tmpa_tl +1} } } { %key not present, set MCID to 0 and insert 1 \int_gzero:N \g_@@_MCID_tmp_bypage_int \@@_prop_gput:Nxx \g_@@_MCID_byabspage_prop { \l_@@_mc_ref_abspage_tl } {1} } \@@_ref_label:en { mcid-\int_use:N \c@g_@@_MCID_abs_int } { mc } \@@_mc_bdc:nx {#1} { /MCID~\int_eval:n { \g_@@_MCID_tmp_bypage_int }~ \exp_not:n { #2 } } } \cs_new_protected:Npn \@@_mc_bdc_mcid:n #1 { \@@_mc_bdc_mcid:nn {#1} {} } \cs_new_protected:Npn \@@_mc_handle_mcid:nn #1 #2 %#1 tag, #2 properties { \@@_mc_bdc_mcid:nn {#1} {#2} } \cs_generate_variant:Nn \@@_mc_handle_mcid:nn {VV} % \end{macrocode} % \end{macro} % \begin{macro}{\@@_mc_handle_stash:n,\@@_mc_handle_stash:x} % This is the handler which puts a mc into the % the current structure. The argument is the number of the mc. % Beside storing the mc into the structure, it also has to record the % structure for the parent tree. % The name is a bit confusing, it does \emph{not} handle mc with the stash key % \ldots. % TODO: why does luamode use it for begin + use, but generic mode only for begin? % \begin{macrocode} \cs_new_protected:Npn \@@_mc_handle_stash:n #1 %1 mcidnum { \@@_check_mc_used:n {#1} \@@_struct_kid_mc_gput_right:nn { \g_@@_struct_stack_current_tl } {#1} \prop_gput:Nxx \g_@@_mc_parenttree_prop {#1} { \g_@@_struct_stack_current_tl } } \cs_generate_variant:Nn \@@_mc_handle_stash:n { x } % \end{macrocode} % \end{macro} % \begin{macro} % { % \@@_mc_bmc_artifact:, % \@@_mc_bmc_artifact:n, % \@@_mc_handle_artifact:N % } % Two commands to create artifacts, one without type, and one with. % We define also a wrapper handler as luamode will need a different definition. % TODO: perhaps later: more properties for artifacts % \begin{macrocode} \cs_new_protected:Npn \@@_mc_bmc_artifact: { \@@_mc_bmc:n {Artifact} } \cs_new_protected:Npn \@@_mc_bmc_artifact:n #1 { \@@_mc_bdc:nn {Artifact}{/Type/#1} } \cs_new_protected:Npn \@@_mc_handle_artifact:N #1 % #1 is a var containing the artifact type { \tl_if_empty:NTF #1 { \@@_mc_bmc_artifact: } { \exp_args:NV\@@_mc_bmc_artifact:n #1 } } % \end{macrocode} % \end{macro} % \begin{macro}{ \@@_get_data_mc_tag: } % This allows to retrieve the active mc-tag. % It is use by the get command. % \begin{macrocode} \cs_new:Nn \@@_get_data_mc_tag: { \g_@@_mc_key_tag_tl } % \end{macrocode} % \end{macro} % % \begin{macro}{\tag_mc_begin:n,\tag_mc_end:} % These are the core public commands to open and close an mc. % They don't need to be in the same group or grouping level, % but the code expect that they are issued linearly. The tag and % the state is passed to the end command through a global var and % a global boolean. % \begin{macrocode} \cs_new_protected:Npn \tag_mc_begin:n #1 %#1 keyval { \@@_check_if_active_mc:T { \group_begin: %hm \@@_check_mc_if_nested: \bool_gset_true:N \g_@@_in_mc_bool \keys_set:nn { @@ / mc } {#1} \bool_if:NTF \l_@@_mc_artifact_bool { %handle artifact \@@_mc_handle_artifact:N \l_@@_mc_artifact_type_tl } { %handle mcid type \@@_check_mc_tag:N \l_@@_mc_key_tag_tl \@@_mc_handle_mcid:VV \l_@@_mc_key_tag_tl \l_@@_mc_key_properties_tl \tl_if_empty:NF {\l_@@_mc_key_label_tl} { \exp_args:NV \@@_mc_handle_mc_label:n \l_@@_mc_key_label_tl } \bool_if:NF \l_@@_mc_key_stash_bool { \@@_mc_handle_stash:x { \int_use:N \c@g_@@_MCID_abs_int } } } \group_end: } } \cs_new_protected:Nn \tag_mc_end: { \@@_check_if_active_mc:T { \@@_check_mc_if_open: \bool_gset_false:N \g_@@_in_mc_bool \tl_gset:Nn \g_@@_mc_key_tag_tl { } \@@_mc_emc: } } % \end{macrocode} % \end{macro} % % \subsection{Keys} % Definitions are different in luamode. % |tag| and |raw| are expanded as |\lua_now:e| in lua does it too and % we assume that their values are safe. % \begin{macro} % { % tag,raw, % alttext,alttext-o, % actualtext,actualtext-o, % label,artifact % } % \begin{macrocode} \keys_define:nn { @@ / mc } { tag .code:n = % the name (H,P,Span) etc { \tl_set:Nx \l_@@_mc_key_tag_tl { #1 } \tl_gset:Nx \g_@@_mc_key_tag_tl { #1 } }, raw .code:n = { \tl_put_right:Nx \l_@@_mc_key_properties_tl { #1 } }, alttext .code:n = % Alt property { \str_set_convert:Nnon \l_@@_tmpa_str { #1 } { default } { utf16/hex } \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< } \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ } }, alttext-o .code:n = % Alt property { \str_set_convert:Noon \l_@@_tmpa_str { #1 } { default } { utf16/hex } \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< } \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ } }, actualtext .code:n = % ActualText property { \str_set_convert:Nnon \l_@@_tmpa_str { #1 } { default } { utf16/hex } \tl_put_right:Nn \l_@@_mc_key_properties_tl { /ActualText~< } \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ } }, actualtext-o .code:n = % ActualText property { \str_set_convert:Noon \l_@@_tmpa_str { #1 } { default } { utf16/hex } \tl_put_right:Nn \l_@@_mc_key_properties_tl { /ActualText~< } \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ } }, label .tl_set:N = \l_@@_mc_key_label_tl, artifact .code:n = { \exp_args:Nnx \keys_set:nn { @@ / mc } { __artifact-bool, __artifact-type=#1 } }, artifact .default:n = {notype} } % % \end{macrocode} % \end{macro} % \end{implementation} % \PrintIndex