diff options
Diffstat (limited to 'macros/latex/contrib/tagpdf/tagpdf-roles.dtx')
-rw-r--r-- | macros/latex/contrib/tagpdf/tagpdf-roles.dtx | 590 |
1 files changed, 536 insertions, 54 deletions
diff --git a/macros/latex/contrib/tagpdf/tagpdf-roles.dtx b/macros/latex/contrib/tagpdf/tagpdf-roles.dtx index 920c6345ca..2254ad420a 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-roles.dtx +++ b/macros/latex/contrib/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 + } + } } |