diff options
author | Karl Berry <karl@freefriends.org> | 2021-05-15 20:37:46 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-05-15 20:37:46 +0000 |
commit | 449b126a17ce3ea3c78f166b93b59470ffa01abf (patch) | |
tree | 6e5985ca4eec7a1b2ca662e1f1ec9eae67753031 /Master/texmf-dist/source/latex/tagpdf | |
parent | e04026bae8d6038a4ba422e41af58d1743178733 (diff) |
tagpdf (15may21)
git-svn-id: svn://tug.org/texlive/trunk@59214 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/tagpdf')
8 files changed, 1034 insertions, 225 deletions
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx index d80d56778bc..42620d46e5e 100644 --- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx +++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx @@ -27,7 +27,7 @@ % \begin{macrocode} %<@@=tag> %<*luatex> -\ProvidesExplFile {tagpdf-luatex.def} {2021/02/23} {0.80} +\ProvidesExplFile {tagpdf-luatex.def} {2021/05/14} {0.81} {tagpdf~driver~for~luatex} \newattribute \l_@@_mc_type_attr %the value represent the type @@ -55,41 +55,32 @@ % Old code, I'm not quite sure if this was a good idea. Now I have mix of table in % ltx.@@.tables and ltx.@@.mc/struct. And a lot is probably not needed. -\cs_new:Nn \@@_luatex_get_table_name:Nn - { - \tl_set_rescan:Nnn #1 { \char_set_catcode_ignore:N \\ } { #2 } - } - -\cs_new:Nn \@@_prop_new:N +\cs_new_protected:Nn \@@_prop_new:N { \prop_new:N #1 - \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } - \directlua { ltx.@@.tables.\l_tmpa_tl = {} } + \directlua { ltx.@@.tables.\cs_to_str:N#1 = {} } } -\cs_new:Nn \@@_seq_new:N +\cs_new_protected:Nn \@@_seq_new:N { \seq_new:N #1 - \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } - \directlua { ltx.@@.tables.\l_tmpa_tl = {} } + \directlua { ltx.@@.tables.\cs_to_str:N#1 = {} } } -\cs_new:Nn \@@_prop_gput:Nnn +\cs_new_protected:Nn \@@_prop_gput:Nnn { \prop_gput:Nnn #1 { #2 } { #3 } - \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } - \directlua { ltx.@@.tables.\l_tmpa_tl["#2"] = "#3" } + \directlua { ltx.@@.tables.\cs_to_str:N#1 ["#2"] = "#3" } } -\cs_new:Nn \@@_seq_gput_right:Nn +\cs_new_protected:Nn \@@_seq_gput_right:Nn { \seq_gput_right:Nn #1 { #2 } - \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } - \directlua { table.insert(ltx.@@.tables.\l_tmpa_tl, "#2") } + \directlua { table.insert(ltx.@@.tables.\cs_to_str:N#1, "#2") } } %Hm not quite sure about the naming @@ -105,27 +96,25 @@ } %for debugging commands that show both the seq/prop and the lua tables -\cs_new:Nn \@@_seq_show:N +\cs_new_protected:Nn \@@_seq_show:N { \seq_show:N #1 - \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } - \directlua { ltx.@@.trace.log ("lua~sequence~array~\l_tmpa_tl",1) } - \directlua { ltx.@@.trace.show_seq (ltx.@@.tables.\l_tmpa_tl) } + \directlua { ltx.@@.trace.log ("lua~sequence~array~\cs_to_str:N#1",1) } + \directlua { ltx.@@.trace.show_seq (ltx.@@.tables.\cs_to_str:N#1) } } -\cs_new:Nn \@@_prop_show:N +\cs_new_protected:Nn \@@_prop_show:N { \prop_show:N #1 - \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } - \directlua {ltx.@@.trace.log ("lua~property~table~\l_tmpa_tl",1) } - \directlua {ltx.@@.trace.show_prop (ltx.@@.tables.\l_tmpa_tl) } + \directlua {ltx.@@.trace.log ("lua~property~table~\cs_to_str:N#1",1) } + \directlua {ltx.@@.trace.show_prop (ltx.@@.tables.\cs_to_str:N#1) } } %</luatex> % \end{macrocode} % % \begin{macrocode} %<*pdftex> -\ProvidesExplFile {tagpdf-pdftex.def} {2021/02/23} {0.80} +\ProvidesExplFile {tagpdf-pdftex.def} {2021/05/14} {0.81} {tagpdf~driver~for~pdftex} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -160,8 +149,8 @@ local ProvidesLuaModule = { name = "tagpdf", - version = "0.80", --TAGVERSION - date = "2021-02-23", --TAGDATE + version = "0.81", --TAGVERSION + date = "2021-05-14", --TAGDATE description = "tagpdf lua code", license = "The LATEX Project Public License 1.3c" } @@ -237,6 +226,7 @@ local nodeid = node.id local nodecopy = node.copy local nodegetattribute = node.get_attribute local nodesetattribute = node.set_attribute +local nodehasattribute = node.has_attribute local nodenew = node.new local nodetail = node.tail local nodeslide = node.slide @@ -361,6 +351,17 @@ local function @@_mark_spaces (head) nodesetattribute(kern.next,iwfontattributeid,glyph.font) end end + -- look also back + if glyph.prev and (glyph.prev.id == GLUE) + and not inside_math and (glyph.prev.width >0) and not nodehasattribute(glyph.prev,iwspaceattributeid) + then + nodesetattribute(glyph.prev,iwspaceattributeid,1) + nodesetattribute(glyph.prev,iwfontattributeid,glyph.font) + -- for debugging + if ltx.__tag.trace.showspaces then + __tag_show_spacemark (head,glyph) + end + end elseif id == PENALTY then local glyph = n -- ltx.@@.trace.log ("PENALTY ".. n.subtype.."VALUE"..n.penalty,3) @@ -770,7 +771,7 @@ function ltx.@@.func.fill_parent_tree_line (page) local structnum = ltx.@@.mc[mcnum]["parent"] local propname = "g_@@_struct_"..structnum.."_prop" local objref = ltx.@@.tables[propname]["objref"] or "XXXX" - texio.write_nl("=====>"..tostring(objref)) + ltx.@@.trace.log("=====>"..tostring(objref),5) numsentry = pdfpage .. " [".. objref .. "]" ltx.@@.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3) else diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx index ad3866ed76c..eb0f41e89b1 100644 --- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx +++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-checks.dtx % -% Copyright (C) 2019-2020 Ulrike Fischer +% 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 @@ -27,7 +27,7 @@ % \begin{macrocode} %<@@=tag> %<*checks> -\ProvidesExplPackage {tagpdf-checks-code} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-checks-code} {2021/05/14} {0.81} {part of tagpdf - code related to checks and messages} @@ -39,6 +39,8 @@ \msg_new:nnn { tag } {mc-label-unknown} { label~#1~unknown~-~rerun } \msg_new:nnn { tag } {mc-used-twice} { mc~#1~has~been~already~used } \msg_new:nnn { tag } {mc-not-open} { there~is~no~mc~to~end~at~#1 } +\msg_new:nnn { tag } {mc-pushed} { #1~has~been~pushed~to~the~mc~stack} +\msg_new:nnn { tag } {mc-popped} { #1~has~been~removed~from~the~mc~stack } % structures \msg_new:nnn { tag } {struct-no-objnum} { objnum~missing~for~structure~#1 } @@ -56,7 +58,8 @@ \msg_new:nnn { tag } {role-missing} { tag~#1~has~no~role~assigned } \msg_new:nnn { tag } {role-unknown} { role~#1~is~not~known } \msg_new:nnn { tag } {role-unknown-tag} { tag~#1~is~not~known } -\msg_new:nnn { tag } {role-new-tag} { adding~new~tag~#1~mapped~to~role~#2 } +\msg_new:nnn { tag } {role-tag} { mapping~tag~#1~to~role~#2 } +\msg_new:nnn { tag } {new-tag} { adding~new~tag~#1 } % trees @@ -88,6 +91,15 @@ } } +\cs_new:Nn \@@_check_structure_tag:NN %_protected? + { + \exp_args:NNx + \prop_if_in:NnF \g_@@_role_tags_prop {#1/#2} + { + \msg_warning:nnx { tag } {role-unknown-tag} {#1} + } + } + \cs_new_protected:Nn \@@_check_info_closing_struct:n %#1 struct num { \msg_info:nnn { tag } {struct-show-closing} {#1} @@ -122,7 +134,7 @@ { \prop_get:NnNTF \g_@@_role_tags_prop {#2} \l_tmpa_tl { - \msg_info:nnnn { tag } {role-new-tag} {#1} {#2} + \msg_info:nnnn { tag } {role-tag} {#1} {#2} } { \msg_warning:nnn { tag } {role-unknown} {#2} @@ -147,13 +159,27 @@ } } +\cs_new_protected:Nn \@@_check_mc_pushed_popped:nn + { + \int_compare:nNnT + { \l_@@_loglevel_int } ={ 2 } + { \msg_info:nnx {tag}{mc-#1}{#2} } + \int_compare:nNnT + { \l_@@_loglevel_int } > { 2 } + { + \msg_warning:nnx {tag}{mc-#1}{#2} + \seq_log:N \g_@@_mc_stack_seq + } + } + + \cs_new:Nn \@@_check_mc_tag:N %protected?? { \tl_if_empty:NT #1 { \msg_error:nnx { tag } {mc-tag-missing} { \@@_get_mc_abs_cnt: } } - \prop_if_in:NoF \g_@@_role_tags_prop {#1} + \prop_if_in:NoF \g_@@_role_tags_NS_prop {#1} { \msg_warning:nnx { tag } {role-unknown-tag} {#1} } diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx index a2cc7f349dc..565e41b372c 100644 --- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx +++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx @@ -27,7 +27,7 @@ % \begin{macrocode} %<@@=tag> %<*shared> -\ProvidesExplPackage {tagpdf-mc-code-shared} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-mc-code-shared} {2021/05/14} {0.81} {part of tagpdf - code related to marking chunks - code shared by generic and luamode } % I use a latex counter for the absolute count, so that it is added to @@ -56,6 +56,9 @@ % value: the structure number the mc is in \_@@_prop_new:N \g_@@_mc_parenttree_prop +% some commands (e.g. links) want to close a previous mc and reopen it after +% there work. For this we create a stack: +\seq_new:N \g_@@_mc_stack_seq % shared keys % the rest are in the splitted code \tl_new:N \l_@@_mc_artifact_type_tl @@ -119,11 +122,58 @@ % we need to define it for both modes to avoid a problem with the label \int_new:N \g_@@_MCID_tmp_bypage_int +% \end{macrocode} + +% \begin{function}[added = 2021-04-22] +% { +% \tag_mc_end_push:, \tag_mc_begin_pop:n +% } +% \begin{syntax} +% \cs{tag_mc_end_push:} \\ +% \cs{tag_mc_begin_pop:n}\Arg{key-values} +% \end{syntax} +% If there is an open mc chunk, +% \cs{tag_mc_end_push:} ends it and pushes its tag of the stack. If there is no +% open chunk, it puts -1 on the stack (for debugging) +% \cs{tag_mc_begin_pop:n} removes a value from the stack. If it is different from +% -1 it opens a tag with it. +% The reopened mc chunk looses info like the alttext for now. +% +% \begin{macrocode} +\cs_new_protected:Npn \tag_mc_end_push: + { + \@@_mc_if_in:TF + { + \seq_gpush:Nx \g_@@_mc_stack_seq { \tag_get:n {mc_tag} } + \@@_check_mc_pushed_popped:nn {pushed}{\tag_get:n {mc_tag}} + \tag_mc_end: + } + { + \@@_check_mc_pushed_popped:nn {pushed}{-1} + \seq_gpush:Nn \g_@@_mc_stack_seq{ -1 } + } + } +\cs_new_protected:Npn \tag_mc_begin_pop:n #1 + { + \seq_gpop:NNTF \g_@@_mc_stack_seq \l_@@_tmpa_tl + { + \tl_if_eq:NnTF \l_@@_tmpa_tl {-1} + { + \@@_check_mc_pushed_popped:nn {popped}{-1} + } + { + \@@_check_mc_pushed_popped:nn {popped}{\l_@@_tmpa_tl} + \tag_mc_begin:n {tag=\l_@@_tmpa_tl,#1} + } + } + { \@@_check_mc_pushed_popped:nn {popped}{empty~stack,~nothing} } %message? + } + %</shared> % \end{macrocode} % \begin{macrocode} %<*generic> -\ProvidesExplPackage {tagpdf-mc-code-generic} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-mc-code-generic} {2021/05/14} {0.81} {part of tagpdf - code related to marking chunks - generic mode} % for the label system @@ -148,8 +198,6 @@ \prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF} -%deprecated -\prg_new_eq_conditional:NNn \uftag_mc_if_in: \@@_mc_if_in: {p,T,F,TF} % this are the low level mc command. @@ -381,8 +429,6 @@ \group_end: } -%deprecated -\cs_set_eq:NN \uftag_mc_begin:n \tag_mc_begin:n \cs_new_protected:Nn \tag_mc_end: { @@ -392,7 +438,7 @@ \@@_mc_emc: } -\cs_set_eq:NN \uftag_mc_end: \tag_mc_end: + \cs_new_protected:Nn \tag_mc_use:n %#1: label name { @@ -420,16 +466,13 @@ } } -%deprecated -\cs_set_eq:NN \uftag_mc_use:n \tag_mc_use:n \cs_new:Nn \@@_get_data_mc_tag: { \g_@@_mc_key_tag_tl } - %</generic> % \end{macrocode} % \begin{macrocode} %<*luamode> -\ProvidesExplPackage {tagpdf-mc-code-lua} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-mc-code-lua} {2021/05/14} {0.81} {tagpdf - mc code only for the luamode } % the two attibutes are defined in the driver file. @@ -500,8 +543,6 @@ \prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF} -%deprecated -\prg_new_eq_conditional:NNn \uftag_mc_if_in: \@@_mc_if_in: {p,T,F,TF} % the keys \tl_new:N \l_@@_mc_key_tag_tl @@ -746,8 +787,6 @@ %\group_end: } -%deprecated -\cs_set_eq:NN \uftag_mc_begin:n \tag_mc_begin:n \cs_new_protected:Nn \tag_mc_end: { @@ -758,7 +797,7 @@ \tl_set:Nn \l_@@_mc_key_tag_tl { } } -\cs_set_eq:NN \uftag_mc_end: \tag_mc_end: + \cs_new_protected:Nn \tag_mc_use:n %#1: label name { @@ -772,7 +811,7 @@ } } -\cs_set_eq:NN \uftag_mc_use:n \tag_mc_use:n + \cs_new:Nn \@@_get_data_mc_tag: { \l_@@_mc_key_tag_tl } %</luamode> diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx index 920c6345ca8..2254ad420a4 100644 --- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx +++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-roles.dtx % -% Copyright (C) 2019 Ulrike Fischer +% 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 @@ -27,30 +27,145 @@ % \begin{macrocode} %<@@=tag> %<*roles> -\ProvidesExplPackage {tagpdf-roles-code} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-roles-code} {2021/05/14} {0.81} {part of tagpdf - code related to roles and structure names} - -\@@_seq_new:N \g_@@_role_tags_seq %to get names from numbers -\@@_prop_new:N \g_@@_role_tags_prop %to get numbers from names - -%The list of standard adobe tags. -\clist_const:Nn \c_@@_role_sttags_clist - {%possible root elements +% \end{macrocode} +% \section{Variables} +% Tags have both a name (a string) and a number (for the lua attribute). +% Testing a name is easier with a prop, while accessing with a number is +% better done with a seq. So both are used and must be kept in sync if a new +% tag is added. The number is only relevant for the MC type, tags with the same +% name from different names spaces can have the same number. +% \begin{macro}{\g_@@_role_tags_seq,\g_@@_role_tags_prop} +% \begin{macrocode} +\@@_seq_new:N \g_@@_role_tags_seq %to get names (type/NS) from numbers +\@@_prop_new:N \g_@@_role_tags_prop %to get numbers from names (type/NS) +% \end{macrocode} +% \end{macro} +% \begin{macro}{\g_@@_role_tags_NS_prop} +% in pdf 2.0 tags belong to a name space. For every tag we store a default +% name space. +% The keys are the tags, the value shorthands like pdf2, or mathml. +% There is no need to access this from lua, so we use the standard prop commands. +% \begin{macrocode} +\prop_new:N \g_@@_role_tags_NS_prop %to namespace info +% \end{macrocode} +% \end{macro} +% \begin{macro}{\g_@@_role_NS_prop} +% The standard names spaces are the following. The keys are the name +% tagpdf will use, the urls are the identifier in the namespace object. +% \begin{description} +% \item[mathml] http://www.w3.org/1998/Math/MathML +% \item[pdf2] http://iso.org/pdf2/ssn +% \item[pdf] http://iso.org/pdf/ssn (default) +% \item[user] \cs{c_@@_role_userNS_id_str} (random id, for user tags) +% \end{description} +% More namespaces are possible and +% their objects references and the ones of the namespaces must be collected +% so that an array can be written to the StructTreeRoot at the end (see tagpdf-tree). +% We use a prop to store also the object reference as it will be needed rather +% often. +% \begin{macrocode} +\prop_new:N \g_@@_role_NS_prop % collect namespaces +% \end{macrocode} +% \end{macro} +% \section{Namesspaces} +% The following commands setups a names space. Namespace dictionaries can +% contain an optional |/Schema| and |/RoleMapNS| entry. We only reserve the +% objects but delay the writing to the finish code, where we can test if the +% keys and the name spaces are actually needed +% \begin{macro}{\@@_role_NS_new:nn} +% This commands setups objects for the name space and its rolemap. It also +% initialize a prop to collect the rolemaps if needed. +% \begin{function}{\@@_role_NS_new:nnn} +% \begin{syntax} +% \cs{@@_role_NS_new:nnn}\Arg{shorthand}\Arg{URI-ID}{Schema} +% \end{syntax} +% \end{function} +% \begin{macro}{\@@_role_NS_new:nnn} +% \begin{macrocode} +\cs_new_protected:Npn \@@_role_NS_new:nnn #1 #2 #3 + { \msg_redirect_name:nnn { pdfdict } { empty-value } { none } + \pdf_object_new:nn {tag/NS/#1}{dict} + \pdfdict_new:n {g_@@_role/Namespace_#1_dict} + \pdf_object_new:nn {@@/RoleMapNS/#1}{dict} + \pdfdict_new:n {g_@@_role/RoleMapNS_#1_dict} + \pdfdict_gput:nnn + {g_@@_role/Namespace_#1_dict} + {Type} + {/Namespace} + \pdf_string_from_unicode:nnN{utf8/string}{#2}\l_tmpa_str + \pdfdict_gput:nnx + {g_@@_role/Namespace_#1_dict} + {NS} + {\l_tmpa_str} + %RoleMapNS is added in tree + \pdfdict_gput:nnx{g_@@_role/Namespace_#1_dict} + {Schema}{#3} + \prop_gput:Nnx \g_@@_role_NS_prop {#1}{\pdf_object_ref:n{tag/NS/#1}~} + \msg_redirect_name:nnn { pdfdict } { empty-value } { warning } + } +% \end{macrocode} +% \end{macro} +% We need an id for the user space. For the tests it should be possible +% to set it to a fix value. So we use random numbers which can +% be fixed by setting a seed. We fake a sort of +% GUID but not try to be really exact as it doesn't matter ... +% +% \begin{macrocode} +\str_const:Nx \c_@@_role_userNS_id_str + { data:, + \int_to_Hex:n{\int_rand:n {65535}} + \int_to_Hex:n{\int_rand:n {65535}} + - + \int_to_Hex:n{\int_rand:n {65535}} + - + \int_to_Hex:n{\int_rand:n {65535}} + - + \int_to_Hex:n{\int_rand:n {65535}} + - + \int_to_Hex:n{\int_rand:n {16777215}} + \int_to_Hex:n{\int_rand:n {16777215}} + } +% \end{macrocode} +% Now we setup the standard names spaces. Currently only if we detect pdf2.0 but +% this will perhaps have to change if the structure code gets to messy. +% \begin{macrocode} +\pdf_version_compare:NnT > {1.9} + { + \@@_role_NS_new:nnn {pdf} {http://iso.org/pdf/ssn}{} + \@@_role_NS_new:nnn {pdf2} {http://iso.org/pdf2/ssn}{} + \@@_role_NS_new:nnn {mathml}{http://www.w3.org/1998/Math/MathML}{} + \exp_args:Nnx + \@@_role_NS_new:nnn {user}{\c_@@_role_userNS_id_str}{} + } +% \end{macrocode} +% +% \section{Data} +% In this section we setup the standard data. +% At first the list of structure types. We split them in three lists, +% the tags with which are both in the pdf and pdf2 namespace, +% the one only in pdf and the one with the tags only in pdf2. +% We also define a rolemap for the pdfII only type to pdf so that +% they can always be used. +% \begin{macro} +% { +% \c_@@_role_sttags_pdf_pdfII_clist, +% \c_@@_role_sttags_only_pdf_clist, +% \c_@@_role_sttags_only_pdfII_clist, +% \c_@@_role_sttags_mathml_clist, +% \c_@@_role_sttags_pdfII_to_pdf_prop +% } +% \begin{macrocode} +% +\clist_const:Nn \c_@@_role_sttags_pdf_pdfII_clist + { Document, %A complete document. This is the root element of any structure tree containing %multiple parts or multiple articles. Part, %A large-scale division of a document. - Art, %A relatively self-contained body of text constituting a single narrative or exposition - %subelements Sect, %A container for grouping related content elements. Div, %A generic block-level element or group of elements - BlockQuote, %A portion of text consisting of one or more paragraphs attributed to someone other - %than the author of the surrounding text. Caption, %A brief portion of text describing a table or figure. - TOC, %A list made up of table of contents item entries (structure tag TOCI; see below) - %and/or other nested table of contents entries - TOCI, %An individual member of a table of contents. This entry's children can be any of - %the following structure tags: - %Lbl,Reference,NonStruct,P,TOC Index, NonStruct, %probably not needed H, @@ -73,29 +188,301 @@ TBody, %table rows TFoot, %table footer Span, %generic inline marker - Quote, %inline quote - Note, % footnote, endnote. Lbl can be child - Reference, % A citation to content elsewhere in the document. - BibEntry, %bibentry - Code, % Link, % Annot, Figure, Formula, Form, - Artifact + % ruby warichu etc .. + Ruby, + RB, + RT, + Warichu, + WT, + WP, + Artifact % only MC-tag ?... } +\clist_const:Nn \c_@@_role_sttags_only_pdf_clist + { + Art,%A relatively self-contained body of text constituting a single narrative or exposition + BlockQuote, %A portion of text consisting of one or more paragraphs attributed to someone other + %than the author of the surrounding text. + TOC, %A list made up of table of contents item entries (structure tag TOCI; see below) + %and/or other nested table of contents entries + TOCI, %An individual member of a table of contents. This entry's children can be any of + %the following structure tags: + %Lbl,Reference,NonStruct,P,TOC + Index, + Private, + Quote, %inline quote + Note, %footnote, endnote. Lbl can be child + Reference, %A citation to content elsewhere in the document. + BibEntry, %bibentry + Code + } + +\clist_const:Nn \c_@@_role_sttags_only_pdfII_clist + { + DocumentFragment + ,Aside + ,H7 + ,H8 + ,H9 + ,H10 + ,Title + ,FENote + ,Sub + ,Em + ,Strong + ,Artifact + } + +\clist_const:Nn \c_@@_role_sttags_mathml_clist + { + abs + ,and + ,annotation + ,apply + ,approx + ,arccos + ,arccosh + ,arccot + ,arccoth + ,arccsc + ,arccsch + ,arcsec + ,arcsech + ,arcsin + ,arcsinh + ,arctan + ,arctanh + ,arg + ,bind + ,bvar + ,card + ,cartesianproduct + ,cbytes + ,ceiling + ,cerror + ,ci + ,cn + ,codomain + ,complexes + ,compose + ,condition + ,conjugate + ,cos + ,cosh + ,cot + ,coth + ,cs + ,csc + ,csch + ,csymbol + ,curl + ,declare + ,degree + ,determinant + ,diff + ,divergence + ,divide + ,domain + ,domainofapplication + ,emptyset + ,eq + ,equivalent + ,eulergamma + ,exists + ,exp + ,exponentiale + ,factorial + ,factorof + ,false + ,floor + ,fn + ,forall + ,gcd + ,geq + ,grad + ,gt + ,ident + ,image + ,imaginary + ,imaginaryi + ,implies + ,in + ,infinity + ,int + ,integers + ,intersect + ,interval + ,inverse + ,lambda + ,laplacian + ,lcm + ,leq + ,limit + ,ln + ,log + ,logbase + ,lowlimit + ,lt + ,maction + ,maligngroup + ,malignmark + ,math + ,matrix + ,matrixrow + ,max + ,mean + ,median + ,menclose + ,merror + ,mfenced + ,mfrac + ,mglyph + ,mi + ,min + ,minus + ,mlabeledtr + ,mlongdiv + ,mmultiscripts + ,mn + ,mo + ,mode + ,moment + ,momentabout + ,mover + ,mpadded + ,mphantom + ,mprescripts + ,mroot + ,mrow + ,ms + ,mscarries + ,mscarry + ,msgroup + ,msline + ,mspace + ,msqrt + ,msrow + ,mstack + ,mstyle + ,msub + ,msubsup + ,msup + ,mtable + ,mtd + ,mtext + ,mtr + ,munder + ,munderover + ,naturalnumbers + ,neq + ,none + ,not + ,notanumber + ,notin + ,notprsubset + ,notsubset + ,or + ,otherwise + ,outerproduct + ,partialdiff + ,pi + ,piece + ,piecewise + ,plus + ,power + ,primes + ,product + ,prsubset + ,quotient + ,rationals + ,real + ,reals + ,reln + ,rem + ,root + ,scalarproduct + ,sdev + ,sec + ,sech + ,selector + ,semantics + ,sep + ,set + ,setdiff + ,share + ,sin + ,sinh + ,subset + ,sum + ,tan + ,tanh + ,tendsto + ,times + ,transpose + ,true + ,union + ,uplimit + ,variance + ,vector + ,vectorproduct + ,xor + } + +\prop_const_from_keyval:Nn \c_@@_role_sttags_pdfII_to_pdf_prop + { + DocumentFragment = Art, + Aside = Note, + Title = H1, + Sub = Span, + H7 = H6 , + H8 = H6 , + H9 = H6 , + H10 = H6, + FENote= Note, + Em = Span, + Strong= Span, + } +% \end{macrocode} +% \end{macro} +% We fill the structure tags in to the seq. We allow all pdf1.7 and pdf2.0, +% and role map if needed the 2.0 tags. +% \begin{macrocode} % get tag name from number: \seq_item:Nn \g_@@_role_tags_seq { n } -%\seq_gset_from_clist:NN \g_@@_role_tags_seq \c_@@_role_tags_clist +% get tag number from name: \prop_item:Nn \g_@@_role_tags_prop { name } -\clist_map_inline:Nn \c_@@_role_sttags_clist +\clist_map_inline:Nn \c_@@_role_sttags_pdf_pdfII_clist { \@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 } + \prop_gput:Nnn \g_@@_role_tags_NS_prop { #1 }{ pdf2 } } +\clist_map_inline:Nn \c_@@_role_sttags_only_pdf_clist + { + \@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 } + \prop_gput:Nnn \g_@@_role_tags_NS_prop { #1 }{ pdf } + } +\clist_map_inline:Nn \c_@@_role_sttags_only_pdfII_clist + { + \@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 } + \prop_gput:Nnn \g_@@_role_tags_NS_prop { #1 }{ pdf2 } + } +\pdf_version_compare:NnT > {1.9} + { + \clist_map_inline:Nn \c_@@_role_sttags_mathml_clist + { + \@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 } + \prop_gput:Nnn \g_@@_role_tags_NS_prop { #1 }{ mathml } + } + } +% \end{macrocode} +% For luatex and the MC we need a name/number relation. +% The name space is not relevant. +% \begin{macrocode} - -% get tag number from name: \prop_item:Nn \g_@@_role_tags_prop { name } \int_step_inline:nnnn { 1 }{ 1 }{ \seq_count:N \g_@@_role_tags_seq } { \@@_prop_gput:Nxn \g_@@_role_tags_prop @@ -104,51 +491,146 @@ } { #1 } } - -\cs_new:Nn \@@_role_get_tag_from_index:nn +% \end{macrocode} +% +% \section{Adding new tags and rolemapping} +% +% \subsection{pdf 1.7 and earlier} +% With this versions only RoleMap is filled. +% At first the dictionary: +% \begin{macrocode} +\pdfdict_new:n {g_@@_role/RoleMap_dict} +% \end{macrocode} +% \begin{macro}{\@@_role_add_tag:nn} +% The pdf 1.7 version has only two arguments: new and rolemap name. +% To make pdf 2.0 types usable we directly define a rolemapping for them. +% TODO: add checks +% \begin{macrocode} +\cs_new_protected:Nn \@@_role_add_tag:nn %(new) name, reference to old { - \@@_seq_item:cn { #1_seq } { #2 } + \prop_if_in:NnF \g_@@_role_tags_prop {#1} + { + \msg_info:nnn { tag }{new-tag}{#1} + \@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 } + \@@_prop_gput:Nnx \g_@@_role_tags_prop { #1 } + { + \seq_count:N \g_@@_role_tags_seq + } + \prop_gput:Nnn \g_@@_role_tags_NS_prop { #1 }{ user } + } + %\@@_check_add_tag_role:nn {#1}{#2} %%!TODO + \tl_if_empty:nF { #2 } + { + \pdfdict_gput:nnx {g_@@_role/RoleMap_dict} + {#1} + {\pdf_name_from_unicode_e:n{#2}} + } } +\cs_generate_variant:Nn \@@_role_add_tag:nn {VV} -\cs_new:Nn \@@_role_get_index_from_tag:nn +\pdf_version_compare:NnT < {2.0} { - \@@_prop_item:cn { #1_prop } { #2 } + \prop_map_inline:Nn \c_@@_role_sttags_pdfII_to_pdf_prop + { + \@@_role_add_tag:nn {#1}{#2} + } } -% new tags and the rolemap - -\@@_prop_new:N \g_@@_role_rolemap_prop - -\cs_new_protected:Nn \@@_role_add_tag:nn %new name, reference to old +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_role_add_tag:nnnn} +% The pdf 2.0 version takes for arguments: +% tag/namespace/role/namespace +% TODO: add checks +% \begin{macrocode} +\cs_new_protected:Nn \@@_role_add_tag:nnnn %tag/namespace/role/namespace { + \msg_info:nnn { tag }{new-tag}{#1} \@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 } \@@_prop_gput:Nnx \g_@@_role_tags_prop { #1 } - { - \seq_count:N \g_@@_role_tags_seq - } - \@@_check_add_tag_role:nn {#1}{#2} - \tl_if_empty:nF { #2 } - { - \@@_prop_gput:Nnn \g_@@_role_rolemap_prop - { #1 } { #2 } - } - } + { + \seq_count:N \g_@@_role_tags_seq + } + \prop_gput:Nnn \g_@@_role_tags_NS_prop { #1 }{ #2 } + %\@@_check_add_tag_role:nn {#1}{#3} %TODO + \pdfdict_gput:nnx {g_@@_role/RoleMapNS_#2_dict}{#1} + { + [ + \pdf_name_from_unicode_e:n{#3} + \c_space_tl + \pdf_object_ref:n {tag/NS/#4} + ] + } + } +\cs_generate_variant:Nn \@@_role_add_tag:nnnn {VVVV} +% \end{macrocode} +% \end{macro} +% The user interface use the key add-new-tag, which takes either a +% keyval list as argument, or a tag/role. +% \begin{macrocode} -\cs_generate_variant:Nn \@@_role_add_tag:nn {xx} +\tl_new:N \l_@@_role_tag_tmpa_tl +\tl_new:N \l_@@_role_tag_namespace_tmpa_tl +\tl_new:N \l_@@_role_role_tmpa_tl +\tl_new:N \l_@@_role_role_namespace_tmpa_tl + +\keys_define:nn { @@ / tag-role } + { + ,tag .tl_set:N = \l_@@_role_tag_tmpa_tl + ,tag-namespace .tl_set:N = \l_@@_role_tag_namespace_tmpa_tl + ,role .tl_set:N = \l_@@_role_role_tmpa_tl + ,role-namespace .tl_set:N = \l_@@_role_role_namespace_tmpa_tl + } \keys_define:nn { @@ / setup } { add-new-tag .code:n = { - \seq_set_split:Nnn \l_tmpa_seq { / } {#1/} - \@@_role_add_tag:xx + \keys_set_known:nnnN + {@@/tag-role} + { + tag-namespace=user, + role-namespace=, %so that we can test for it. + #1 + }{@@/tag-role}\l_tmpa_tl + \tl_if_empty:NF \l_tmpa_tl { - \seq_item:Nn \l_tmpa_seq {1} + \exp_args:NNno \seq_set_split:Nnn \l_tmpa_seq { / } {\l_tmpa_tl/} + \tl_set:Nx \l_@@_role_tag_tmpa_tl { \seq_item:Nn \l_tmpa_seq {1} } + \tl_set:Nx \l_@@_role_role_tmpa_tl { \seq_item:Nn \l_tmpa_seq {2} } } + \tl_if_empty:NT \l_@@_role_role_namespace_tmpa_tl { - \seq_item:Nn \l_tmpa_seq {2} + \prop_get:NVNTF + \g_@@_role_tags_NS_prop + \l_@@_role_role_tmpa_tl + \l_@@_role_role_namespace_tmpa_tl + { + \prop_if_in:NVF\g_@@_role_NS_prop \l_@@_role_role_namespace_tmpa_tl + { + \tl_set:Nn \l_@@_role_role_namespace_tmpa_tl {user} + } + } + { + \tl_set:Nn \l_@@_role_role_namespace_tmpa_tl {user} + } } - } + \pdf_version_compare:NnTF < {2.0} + { + %TODO add check for emptyness? + \@@_role_add_tag:VV + \l_@@_role_tag_tmpa_tl + \l_@@_role_role_tmpa_tl + } + { + \@@_role_add_tag:VVVV + \l_@@_role_tag_tmpa_tl + \l_@@_role_tag_namespace_tmpa_tl + \l_@@_role_role_tmpa_tl + \l_@@_role_role_namespace_tmpa_tl + } + } } diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx index edc5e445c70..bfe85344b64 100644 --- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx +++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx @@ -27,7 +27,7 @@ % \begin{macrocode} %<@@=tag> %<*space> -\ProvidesExplPackage {tagpdf-space-code} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-space-code} {2021/05/14} {0.81} {part of tagpdf - code related to real space chars} % luatex uses an attribute (declared in the driver file) and some luacode in tagpdf.lua % perhaps I will split the code by engine in the future diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx index 09ea3511882..9e66d4913d6 100644 --- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx +++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx @@ -27,30 +27,37 @@ % \begin{macrocode} %<@@=tag> %<*struct> -\ProvidesExplPackage {tagpdf-struct-code} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-struct-code} {2021/05/14} {0.81} {part of tagpdf - code related to storing structure} - +% \end{macrocode} % I will use a latex counter for the structure count % to have a chance to avoid double structures in align etc - +% \begin{macrocode} \newcounter { g_@@_struct_abs_int } \int_gzero:N \c@g_@@_struct_abs_int - -% ref code is in tagpdf.dtx - -% a sequence stores structnum -> the obj numbers +% \end{macrocode} +% a sequence to store structnum -> the obj numbers % to allow easy mapping over the structures - +% \begin{macrocode} \@@_seq_new:N \g_@@_struct_objR_seq - -% a sequence for the structure stack. When a sequence is opened it's number is put on the stack. +% \end{macrocode} +% a sequence for the structure stack. +% When a sequence is opened it's number is put on the stack. +% \begin{macrocode} \seq_new:N \g_@@_struct_stack_seq \seq_gpush:Nn \g_@@_struct_stack_seq {0} - -%this variables will hold the top entry and the parent on the stack +% \end{macrocode} +% We will perhaps also need the tags. While it is possible to get them from the +% numbered stack, lets build a tag stack too. +% \begin{macrocode} +\seq_new:N \g_@@_struct_tag_stack_seq +\seq_gpush:Nn \g_@@_struct_tag_stack_seq {Root} +% \end{macrocode} +%this variables will hold the number of top entry and the parent on the stack +% \begin{macrocode} \tl_new:N \l_@@_struct_stack_parent_tmp_tl \tl_new:N \g_@@_struct_stack_current_tl - +% \end{macrocode} % I need at least one structure: the StructTreeRoot % normally it should have only one kid, e.g. the document element. @@ -65,8 +72,7 @@ % (the root has a special set of properties). % the values of the prop should be already escaped properly % when the entries are created (title,lange,alt,E,actualtext) - - +% \begin{macrocode} \seq_const_from_clist:Nn \c_@@_struct_StructTreeRoot_entries_seq {%p. 857/858 Type, % always /StructTreeRoot @@ -75,7 +81,8 @@ ParentTree, % required,obj ref to the parent tree ParentTreeNextKey, %optional RoleMap, - ClassMap + ClassMap, + Namespaces } \seq_const_from_clist:Nn \c_@@_struct_StructElem_entries_seq @@ -131,19 +138,13 @@ \@@_seq_new:c { g_@@_struct_kids_0_seq } -% deprecated -%\@@_prop_gput:cno -% { g_@@_struct_0_prop } -% { objnum} -% { \c_@@_tree_obj_structtreeroot_tl } - % new -\@@_prop_gput:cno +\@@_prop_gput:cnx { g_@@_struct_0_prop } { objref} - { \pdf_object_ref:n { c_@@_struct_0_obj } } + { \pdf_object_ref:n { @@/struct/0 } } -\@@_prop_gput:cno +\@@_prop_gput:cnn { g_@@_struct_0_prop } { Type } { /StructTreeRoot } @@ -152,23 +153,30 @@ \@@_prop_gput:cnx { g_@@_struct_0_prop } { ParentTree } - { \pdf_object_ref:n { c_@@_tree_parenttree_obj } } + { \pdf_object_ref:n { @@/tree/parenttree } } \@@_prop_gput:cnx { g_@@_struct_0_prop } { RoleMap } - { \pdf_object_ref:n { c_@@_tree_rolemap_obj } } + { \pdf_object_ref:n { @@/tree/rolemap } } -\@@_prop_gput:cno +\@@_prop_gput:cnn { g_@@_struct_0_prop } { entries } { StructTreeRoot } -\@@_prop_gput:cno +\@@_prop_gput:cnn { g_@@_struct_0_prop } { num } { 0 } +%Namespaces are pdf 2.0 but it doesn't harm to have an empty entry +\@@_prop_gput:cnx + { g_@@_struct_0_prop } + { Namespaces } + { \pdf_object_ref:n { @@/tree/namespaces } } + + % commands to store the kids % I don't compare the page objects number yet, but always add the /Pg key, perhaps later @@ -316,7 +324,7 @@ \@@_struct_get_dict_content:n { #1 } \exp_args:Nx \pdf_object_write:nx - { c_@@_struct_#1_obj } + { @@/struct/#1 } { \l_@@_struct_dict_content_tl } @@ -326,23 +334,48 @@ } } +% this command allows to get the current structure tag. We will need to handle nesting +% P +\cs_new:Nn \@@_get_data_struct_tag: + { + \exp_args:Ne + \tl_tail:n + { + \prop_item:cn {g_@@_struct_\g__tag_struct_stack_current_tl _prop}{S} + } + } + % keys for the user commands % should I pass the values (e.g. the tag) through an escape command? +% we store the tag in a variable. But we should be careful, it is only reliable +% at the begin +\tl_new:N \g_@@_struct_tag_tl +\tl_new:N \g_@@_struct_tag_NS_tl +\cs_generate_variant:Nn \seq_set_split:Nnn{Nne} \keys_define:nn { @@ / struct } { label .tl_set:N = \l_@@_struct_key_label_tl, stash .bool_set:N = \l_@@_struct_elem_stash_bool, tag .code:n = % S property - {%%????????? \pdfescapename?? - \tl_set:Nx \l_@@_tmpa_tl { #1 } + {%%????????? \pdfescapename?? slash/not slash is here the question ... + \seq_set_split:Nne \l_tmpa_seq { / } {#1/\prop_item:Nn\g__tag_role_tags_NS_prop{#1}} + \tl_gset:Nx \g_@@_struct_tag_tl { \seq_item:Nn\l_tmpa_seq {1} } + \tl_gset:Nx \g_@@_struct_tag_NS_tl { \seq_item:Nn\l_tmpa_seq {2} } \bool_if:NT \g_@@_check_tags_bool { - \@@_check_structure_tag:N \l_@@_tmpa_tl + \@@_check_structure_tag:N \g_@@_struct_tag_tl } \@@_prop_gput:cnx { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop } { S } - { /\exp_not:V\l_@@_tmpa_tl } + { \pdf_name_from_unicode_e:n{ \g_@@_struct_tag_tl} } % + \prop_get:NVNT \g_@@_role_NS_prop\g_@@_struct_tag_NS_tl\l_@@_tmpa_tl + { + \@@_prop_gput:cnx + { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop } + { NS } + { \l_@@_tmpa_tl } % + } }, title .code:n = % T property { @@ -513,7 +546,7 @@ %\@@_pdfreserveobjnum:N \l_tmpa_tl \exp_args:Ne \pdf_object_new:nn - { c_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_obj } + { @@/struct/\int_eval:n { \c@g_@@_struct_abs_int } } { dict } \@@_prop_gput:cnx { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop } @@ -521,7 +554,7 @@ { \exp_args:Ne \pdf_object_ref:n - {c_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_obj} + {@@/struct/\int_eval:n { \c@g_@@_struct_abs_int }} } % \prop_show:c { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop } \@@_prop_gput:cnx @@ -551,6 +584,7 @@ \msg_error:nn { tag } { struct-faulty-nesting } } \seq_gpush:NV \g_@@_struct_stack_seq \c@g_@@_struct_abs_int + \seq_gpush:NV \g_@@_struct_tag_stack_seq \g_@@_struct_tag_tl \tl_gset:NV \g_@@_struct_stack_current_tl \c@g_@@_struct_abs_int %\seq_show:N \g_@@_struct_stack_seq \bool_if:NF @@ -578,13 +612,12 @@ \group_end: } -%deprecated -\cs_set_eq:NN \uftag_struct_begin:n \tag_struct_begin:n \cs_new_protected:Nn \tag_struct_end: { %take the current structure num from the stack: %the objects are written later, lua mode hasn't all needed info yet %\seq_show:N \g_@@_struct_stack_seq + \seq_gpop:NN \g_@@_struct_tag_stack_seq \l_tmpa_tl \seq_gpop:NNTF \g_@@_struct_stack_seq \l_tmpa_tl { \int_compare:nNnT {\l_@@_loglevel_int} > { 0 } @@ -601,10 +634,13 @@ { \@@_check_no_open_struck: } + \seq_get:NNT \g_@@_struct_tag_stack_seq \l_tmpa_tl + { + \tl_gset:NV \g_@@_struct_tag_tl \l_tmpa_tl + } } -%deprecated -\cs_set_eq:NN \uftag_struct_end: \tag_struct_end: + \cs_new_protected:Nn \tag_struct_use:n %#1 is the label { @@ -631,8 +667,6 @@ } } -\cs_set_eq:NN \uftag_struct_use:n \tag_struct_use:n - %%%% Code to tag links %%%% this works for url, see exp-link.pdf. @@ -677,7 +711,7 @@ % \end{macrocode} % \begin{macrocode} %<*attr> -\ProvidesExplPackage {tagpdf-attr-code} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-attr-code} {2021/05/14} {0.81} {part of tagpdf - code related to attributes and attribute classes} % the obj is written in tagpdf-tree-code. diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx index 35f622ca1c9..dd6b7863c79 100644 --- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx +++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx @@ -27,16 +27,22 @@ % \begin{macrocode} %<@@=tag> %<*tree> -\ProvidesExplPackage {tagpdf-tree-code} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-tree-code} {2021/05/14} {0.81} {part of tagpdf - code related to writing trees and dictionaries to the pdf} %this does the actual finishing: -%Is \AfterEndDocument the best places?? +%Is \AddToHook{enddocument/end} the best places?? \hook_gput_code:nnn{begindocument}{tagpdf} { \bool_if:NT \g_@@_active_tree_bool { - \AfterEndDocument { \tag_finish_structure: } + \sys_if_output_pdf:TF + { + \AddToHook{enddocument/end} { \tag_finish_structure: } + } + { + \AddToHook{shipout/lastpage} { \tag_finish_structure: } + } } } @@ -48,7 +54,7 @@ %\tl_const:Nx \c_@@_tree_obj_structtreeroot_tl { \l_tmpa_tl } %new -\pdf_object_new:nn { c_@@_struct_0_obj }{ dict } +\pdf_object_new:nn { @@/struct/0 }{ dict } %need to think about the best place ... \hook_gput_code:nnn{begindocument}{tagpdf} @@ -58,7 +64,7 @@ \pdfmanagement_add:nnx { Catalog } { StructTreeRoot } - { \pdf_object_ref:n { c_@@_struct_0_obj } } + { \pdf_object_ref:n { @@/struct/0 } } } } \cs_new_protected:Nn \@@_tree_write_structtreeroot: @@ -82,7 +88,7 @@ %\tl_const:Nx \c_@@_tree_obj_parenttree_tl { \l_tmpa_tl } %new -\pdf_object_new:nn { c_@@_tree_parenttree_obj }{ dict } +\pdf_object_new:nn { @@/tree/parenttree }{ dict } % we have two sets of entries in the parent tree: % page streams and real objects. @@ -188,39 +194,21 @@ \@@_tree_fill_parenttree: } \tl_put_right:NV \l_@@_parenttree_content_tl\g_@@_parenttree_objr_tl - \pdf_object_write:nx { c_@@_tree_parenttree_obj } + \pdf_object_write:nx { @@/tree/parenttree } { /Nums\c_space_tl [\l_@@_parenttree_content_tl] } } %the Rolemap tree -%deprecated -%\@@_pdfreserveobjnum:N \l_tmpa_tl -%\tl_const:Nx \c_@@_tree_obj_rolemap_tl { \l_tmpa_tl } - -%new -\pdf_object_new:nn { c_@@_tree_rolemap_obj }{ dict } -\tl_new:N \l_@@_rolemap_content_tl - -\cs_new_protected:Nn \@@_tree_fill_rolemap: - { - \prop_map_inline:Nn \g_@@_role_rolemap_prop - { - \tl_put_right:Nx \l_@@_rolemap_content_tl - { - /##1\c_space_tl/##2^^J - } - } - } +\pdf_object_new:nn { @@/tree/rolemap }{ dict } \cs_new_protected:Nn \@@_tree_write_rolemap: { - \@@_tree_fill_rolemap: - \pdf_object_write:nx { c_@@_tree_rolemap_obj } + \pdf_object_write:nx { @@/tree/rolemap } { - \l_@@_rolemap_content_tl + \pdfdict_use:n{g_@@_role/RoleMap_dict} } } @@ -248,16 +236,42 @@ \tl_if_empty:NF \g_@@_attr_class_content_tl { - \pdf_object_new:nn { c_@@_tree_classmap_obj }{ dict } + \pdf_object_new:nn { @@/tree/classmap }{ dict } % \@@_pdfreserveobjnum:N \l_tmpa_tl % \tl_const:Nx \c_@@_tree_obj_classmap_tl { \l_tmpa_tl } \pdf_object_write:nx - { c_@@_tree_classmap_obj } + { @@/tree/classmap } { \g_@@_attr_class_content_tl } \@@_prop_gput:cnx { g_@@_struct_0_prop } { ClassMap } - { \pdf_object_ref:n { c_@@_tree_classmap_obj } } + { \pdf_object_ref:n { @@/tree/classmap } } + } + } + +% namespaces are only relevant for pdf2.0 but we don't care +\pdf_object_new:nn{ @@/tree/namespaces }{array} +\cs_new_protected:Npn \@@_tree_write_namespaces: + { + \prop_map_inline:Nn \g_@@_role_NS_prop + { + \pdfdict_if_empty:nF {g_@@_role/RoleMapNS_##1_dict} + { + \pdf_object_write:nx {@@/RoleMapNS/##1} + { + \pdfdict_use:n {g_@@_role/RoleMapNS_##1_dict} + } + \pdfdict_gput:nnx{g_@@_role/Namespace_##1_dict} + {RoleMapNS}{\pdf_object_ref:n {@@/RoleMapNS/##1}} + } + \pdf_object_write:nx{tag/NS/##1} + { + \pdfdict_use:n {g_@@_role/Namespace_##1_dict} + } + } + \pdf_object_write:nx {@@/tree/namespaces} + { + \prop_map_tokens:Nn \g_@@_role_NS_prop{\use_ii:nn} } } @@ -267,12 +281,11 @@ \@@_tree_write_parenttree: \@@_tree_write_rolemap: \@@_tree_write_classmap: + \@@_tree_write_namespaces: \@@_tree_write_structelements: %this is rather slow!! \@@_tree_write_structtreeroot: } -%deprecated -\cs_set_eq:NN \uftag_finish_structure: \tag_finish_structure: %StructParents !!! we need a better hook for \g__pdf_BACKEND_thispage_shipout_tl!! % No actually diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx index 145b1509712..ba473d7022f 100644 --- a/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx +++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx @@ -27,7 +27,7 @@ % \begin{macrocode} %<@@=tag> %<*package> -\ProvidesExplPackage {tagpdf} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf} {2021/05/14} {0.81} { A package to experiment with pdf tagging } \bool_if:nF @@ -122,9 +122,9 @@ \ref_attribute_gset:nnnn {tagstructobj} {}{now} { \exp_args:Ne - \pdf_object_if_exist:nT {c__tag_struct_ \int_use:N \c@g__tag_struct_abs_int _obj} + \pdf_object_if_exist:nT {@@/struct/\int_use:N \c@g__tag_struct_abs_int} { - \pdf_object_ref:e{c__tag_struct_ \int_use:N \c@g_@@_struct_abs_int _obj} + \pdf_object_ref:e{@@/struct/\int_use:N \c@g_@@_struct_abs_int} } } % replace by abspage?? @@ -208,6 +208,11 @@ \pdfmanagement_remove:nn {Page} {Tabs}, tabsorder .initial:n = structure, uncompress .code:n = {\pdf_uncompress: }, + global-mc .code:n = + { + \cs_set_eq:NN\@@_attribute_set:Nn \@@_attribute_gset:Nn + \cs_set_eq:NN\@@_attribute_unset:N\@@_attribute_gunset:N + } } %need to think about the right place ... %\AtBeginDocument @@ -217,6 +222,10 @@ { \pdfmanagement_add:nnn { Catalog / MarkInfo } { Marked } { true } } + \keys_define:nn { @@ / setup } + { + global-mc .code:n={} + } } % escape commands are a bit engine specific so have been moved to the backend files. % commands to escape strings so that they can be safely used in pdf @@ -326,9 +335,12 @@ % % \begin{macrocode} %<*user> -\ProvidesExplPackage {tagpdf-user} {2021/02/23} {0.80} +\ProvidesExplPackage {tagpdf-user} {2021/05/14} {0.81} {tagpdf - user commands} +% \end{macrocode} +% \begin{macro}{\tagpdfsetup} +% \begin{macrocode} \NewDocumentCommand \tagpdfsetup { m } { \keys_set:nn { @@ / setup } { #1 } @@ -337,8 +349,12 @@ \cs_set_eq:NN\tagpdfifluatexTF \sys_if_engine_luatex:TF \cs_set_eq:NN\tagpdfifluatexT \sys_if_engine_luatex:T \cs_set_eq:NN\tagpdfifpdftexT \sys_if_engine_pdftex:T - -%%% stop tagging +% \end{macrocode} +% \end{macro} +% We need a command to stop tagging in some places. +% +% \begin{macro}{ \tag_stop_group_begin:, \tag_stop_group_end: } +% \begin{macrocode} \bool_new:N \l_@@_stop_bool \prg_new_conditional:Nnn \@@_if_stop: {p,T,F,TF} @@ -359,13 +375,6 @@ \cs_set_eq:NN \tag_struct_begin:n \use_none:n \cs_set_eq:NN \tag_struct_end: \prg_do_nothing: \cs_set_eq:NN \tag_struct_use:n \use_none:n - %deprecated - \cs_set_eq:NN \uftag_mc_begin:n \tag_mc_begin:n - \cs_set_eq:NN \uftag_mc_end: \tag_mc_end: - \cs_set_eq:NN \uftag_mc_use:n \tag_mc_use:n - \cs_set_eq:NN \uftag_struct_begin:n \tag_struct_begin:n - \cs_set_eq:NN \uftag_struct_end: \tag_struct_end: - \cs_set_eq:NN \uftag_struct_use:n \tag_struct_use:n } \cs_new_protected:Npn \tag_stop_group_begin: @@ -375,23 +384,34 @@ } \cs_set_eq:NN \tag_stop_group_end: \group_end: - - -%%% a generic command to retrieve data - +% \end{macrocode} +% \end{macro} +% We need a command to stop tagging in some places. +% +% \begin{macro}{ \tagpdfget, \tag_get:n } +% This is a generic command to retrieve data. Currently +% the only sensible value for the argument is |mc_tag| +% \begin{macrocode} \cs_new:Npn \tagpdfget #1 { \use:c {@@_get_data_#1: } } \cs_new:Npn \tag_get:n #1 { \use:c {@@_get_data_#1: } } -%deprecated: -\cs_new:Npn \uftag_get:n #1 { \use:c {@@_get_data_#1: } } - -%%%% mc related user commands +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tagmcifinTF} +% This is a test if an mc is open or not. It is mostly of +% importance for pdflatex as lualatex doesn't mind much if a mc tag is not +% correctly closed. +% \begin{macrocode} \NewDocumentCommand \tagmcifinTF { m m } { \@@_mc_if_in:TF { #1 } { #2 } } - - +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{tagmcartifact} +% \begin{macrocode} \NewDocumentEnvironment{tagmcartifact}{m} { \tag_mc_artifact_group_begin:n { #1}\ignorespaces @@ -400,6 +420,11 @@ \tag_mc_artifact_group_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tagmcbegin,\tagmcend,\tagmcuse } +% \begin{macrocode} \NewDocumentCommand \tagmcbegin { m } { \tag_mc_begin:n {#1}\ignorespaces @@ -408,7 +433,7 @@ \NewDocumentCommand \tagmcend { } { - \unskip % this unskip appears to mess up some spacing; can we do this in another way? + \if_mode_horizontal: \unskip \fi: % \tag_mc_end: } @@ -417,9 +442,13 @@ \tag_mc_use:n {#1} } - -%%%% structure related commands - +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tagstructbegin,\tagstructend,\tagstructuse } +% +% These are structure related user commands +% \begin{macrocode} \NewDocumentCommand \tagstructbegin { m } { \tag_struct_begin:n {#1} @@ -435,9 +464,14 @@ \tag_struct_use:n {#1} } - - -%%%% debug/show commands +% \end{macrocode} +% \end{macro} +% +% \section{Debugging} +% +% \begin{macro}{\showtagpdfmcdata,\showtagpdfattributes } +% This commands are lua only +% \begin{macrocode} \NewDocumentCommand\showtagpdfmcdata { O {\@@_tag_get_mc_abs_cnt:} } { \bool_if:NT \g_@@_mode_lua_bool @@ -473,6 +507,15 @@ } } +\NewDocumentCommand\showtagstack {} + { + \seq_show:N \g_@@_struct_tag_stack_seq + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ } +% \begin{macrocode} \sys_if_engine_luatex:T { \NewDocumentCommand\pdffakespace { } @@ -480,19 +523,190 @@ \@@_fakespace: } } +% \end{macrocode} +% \end{macro} +% \section{Paratagging} +% The following are some simple commands to enable/disable paratagging. +% Probably one should add some checks if we are already in a paragraph. +% \begin{macrocode} +\bool_new:N \l_@@_para_bool +\bool_new:N \l_@@_para_show_bool +\int_new:N \g_@@_para_int + +\keys_define:nn { @@ / setup } + { + paratagging .bool_set:N = \l_@@_para_bool, + paratagging-show .bool_set:N = \l_@@_para_show_bool, + } + +\AddToHook{para/begin} + { + \int_gincr:N \g_@@_para_int + \bool_if:NT \l__tag_para_bool + { + \tag_struct_begin:n {tag=P} + \bool_if:NT \l_@@_para_show_bool + { \tag_mc_begin:n{artifact} + \llap{\color_select:n{red}\tiny\int_use:N\g_@@_para_int\ } + \tag_mc_end: + } + \tag_mc_begin:n {tag=P} + } + } +\AddToHook{para/end} + { + \bool_if:NT \l__tag_para_bool + { + \tag_mc_end: + \bool_if:NT \l_@@_para_show_bool + { \tag_mc_begin:n{artifact} + \rlap{\color_select:n{red}\tiny\ \int_use:N\g_@@_para_int} + \tag_mc_end: + } + \tag_struct_end: + } + } + + +\newcommand\tagpdfparaOn {\bool_set_true:N \l__tag_para_bool} +\newcommand\tagpdfparaOff{\bool_set_false:N \l__tag_para_bool} -%</user> % \end{macrocode} -% +% \section{Links} +% We need to close and reopen mc-chunks around links. +% With luatex the push/pop command must be outside groups, +% so we add also code to the generic commands in the hyperref driver. % \begin{macrocode} -%<*deprecated> -% \uftag_get:n -% \uftag_mc_if_in: -% \uftag_mc_begin:n -% \uftag_mc_end: -% \uftag_mc_use:n -% \uftag_struct_begin:n -% \uftag_struct_end: -% \uftag_finish_structure: -%</deprecated> +\cs_generate_variant:Nn \pdfannot_dict_put:nnn {nnx} +\hook_gput_code:nnn + {pdfannot/link/URI/before} + {tagpdf} + { + \bool_if:NT \g_@@_active_struct_bool + { + \tag_mc_end_push: + \tag_struct_begin:n { tag=Link } + \tag_mc_begin:n { tag=Link } + \pdfannot_dict_put:nnx + { link/URI } + { StructParent } + { \int_use:N\c@g_@@_parenttree_obj_int } + } + } + +\hook_gput_code:nnn + {pdfannot/link/URI/after} + {tagpdf} + { + \bool_if:NT \g_@@_active_struct_bool + { + \@@_struct_finish_link: + \tag_mc_end: + \tag_struct_end: + \tag_mc_begin_pop:n{} + } + } + +\hook_gput_code:nnn + {pdfannot/link/GoTo/before} + {tagpdf} + { + \bool_if:NT \g_@@_active_struct_bool + { + \tag_mc_end_push: + \tag_struct_begin:n{tag=Link} + \tag_mc_begin:n{tag=Link} + \pdfannot_dict_put:nnx + { link/GoTo } + { StructParent } + { \int_use:N\c@g_@@_parenttree_obj_int } + } + } + +\hook_gput_code:nnn + {pdfannot/link/GoTo/after} + {tagpdf} + { + \bool_if:NT \g_@@_active_struct_bool + { + \@@_struct_finish_link: + \tag_mc_end: + \tag_struct_end: + \tag_mc_begin_pop:n{} + } + } + +\hook_gput_code:nnn + {cmd/url/before} + {tagpdf} + {\tag_mc_end_push:} + +\hook_gput_code:nnn + {cmd/url/after} + {tagpdf} + {\tag_mc_begin_pop:n{}} + +\hook_gput_code:nnn + {cmd/href/before} + {tagpdf} + {\tag_mc_end_push:} + +\hook_gput_code:nnn + {cmd/href/after} + {tagpdf} + {\tag_mc_begin_pop:n{}} + +\hook_gput_code:nnn + {cmd/hrefurl/before} + {tagpdf} + {\tag_mc_end_push:} + +\hook_gput_code:nnn + {cmd/hrefurl/after} + {tagpdf} + {\tag_mc_begin_pop:n{}} + +%this will go when references are improved +\hook_gput_code:nnn + {cmd/T@ref/before} + {tagpdf} + {\tag_mc_end_push:} + +\hook_gput_code:nnn + {cmd/T@ref/after} + {tagpdf} + {\tag_mc_begin_pop:n{}} + +\hook_gput_code:nnn + {cmd/T@pageref/before} + {tagpdf} + {\tag_mc_end_push:} + +\hook_gput_code:nnn + {cmd/T@pageref/after} + {tagpdf} + {\tag_mc_begin_pop:n{}} + +\hook_gput_code:nnn + {cmd/T@nameref/before} + {tagpdf} + {\tag_mc_end_push:} + +\hook_gput_code:nnn + {cmd/T@nameref/after} + {tagpdf} + {\tag_mc_begin_pop:n{}} +% "alternative descriptions " for PAX3. How to get better text here?? +\pdfannot_dict_put:nnn + { link/URI } + { Contents } + { (url) } + +\pdfannot_dict_put:nnn + { link/GoTo } + { Contents } + { (ref) } + % \end{macrocode} +%</user> +% |