summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/tagpdf/tagpdf-roles.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/tagpdf/tagpdf-roles.dtx')
-rw-r--r--macros/latex/contrib/tagpdf/tagpdf-roles.dtx590
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
+ }
+ }
}