summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/tagpdf/tagpdf-struct.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/tagpdf/tagpdf-struct.dtx')
-rw-r--r--macros/latex/contrib/tagpdf/tagpdf-struct.dtx1024
1 files changed, 688 insertions, 336 deletions
diff --git a/macros/latex/contrib/tagpdf/tagpdf-struct.dtx b/macros/latex/contrib/tagpdf/tagpdf-struct.dtx
index e385fea951..4c342f921c 100644
--- a/macros/latex/contrib/tagpdf/tagpdf-struct.dtx
+++ b/macros/latex/contrib/tagpdf/tagpdf-struct.dtx
@@ -21,57 +21,278 @@
% 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-tree module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
% \fi
+% \title{^^A
+% The \pkg{tagpdf-struct} module\\ Commands to create the structure ^^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.9, released 2021-06-29}
+% \maketitle
+% \begin{documentation}
+% \section{Public Commands}
+% \begin{function}{\tag_struct_begin:n,\tag_struct_end:}
+% \begin{syntax}
+% \cs{tag_struct_begin:n}\Arg{key-values}\\
+% \cs{tag_struct_end:}
+% \end{syntax}
+% These commands start and end a new structure.
+% They don't start a group. They set all their values globally.
+% \end{function}
+% \begin{function}{\tag_struct_use:n}
+% \begin{syntax}
+% \cs{tag_struct_use:n}\Arg{label}
+% \end{syntax}
+% These commands insert a structure previously stashed away as kid
+% into the currently active structure.
+% A structure should be used only once,
+% if the structure already has a parent a warning is issued.
+% \end{function}
+% The following two functions are used to add annotations. They must be used
+% together and with care to get the same numbers. Perhaps some improvements are needed
+% here.
+% \begin{function}{\tag_struct_insert_annot:nn}
+% \begin{syntax}
+% \cs{tag_struct_insert_annot:nn}\Arg{object reference}\Arg{struct parent number}
+% \end{syntax}
+% This inserts an annotation in the structure. \meta{object reference}
+% is there reference to the annotation. \meta{struct parent number}
+% should be the same number as had been inserted with \cs{tag_struct_parent_int:}
+% as |StructParent| value to the dictionary of the annotion.
+% The command will increase the value of the counter
+% used by \cs{tag_struct_parent_int:}.
+% \end{function}
+% \begin{function}{\tag_struct_parent_int:}
+% \begin{syntax}
+% \cs{tag_struct_parent_int:}
+% \end{syntax}
+% This gives back the next free /StructParent number (assuming that it is
+% together with \cs{tag_struct_insert_annot:nn} which will increase the number.
+% \end{function}
+% \section{Public keys}
+% \subsection{Keys for the structure commands}
+% \begin{function}{tag}
+% This is required. The value of the key is normally one of the
+% standard types listed in section \ref{sec:new-tag}.
+% It is possible to setup new tags/types.
+% The value can also be of the form |type/NS|, where |NS| is the
+% shorthand of a declared name space.
+% Currently the names spaces |pdf|, |pdf2|, |mathml| and |user| are defined.
+% This allows to use a different name space than
+% the one connected by default to the tag. But normally this should not be needed.
+% \end{function}
+% \begin{function}{stash}
+% Normally a new structure inserts itself as a kid
+% into the currently active structure. This key prohibits this.
+% The structure is nevertheless from now on
+% \enquote{the current active structure}
+% and parent for following marked content and structures.
+% \end{function}
+% \begin{function}{label}
+% This key sets a label by which
+% one can use the structure later in another structure.
+% Internally the label name will start with \texttt{tagpdfstruct-}.
+% \end{function}
+% \begin{function}{title,title-o}
+% This keys allows to set the dictionary entry
+% \texttt{/Title} in the structure object.
+% The value is handled as verbatim string and hex encoded.
+% Commands are not expanded. |title-o| will expand the value once.
+% \end{function}
+%
+% \begin{function}{alttext,alttext-o}
+% This key inserts an \texttt{/Alt} value in the dictionary of structure object.
+% The value is handled as verbatim string and hex encoded.
+% |alttext-o| will expand the value once.
+% \end{function}
+% \begin{function}{actualtext,actualtext-o}
+% This key inserts an \texttt{/ActualText} value in the dictionary of structure object.
+% The value is handled as verbatim string and hex encoded.
+% |actualtext-o| will expand the value once.
+% \end{function}
+% \begin{function}{lang}
+% This key allows to set the language for a structure element. The value should be a bcp-identifier,
+% e.g. |de-De|.
+% \end{function}
+% \begin{function}{ref}
+% This key allows to add references to other structure elements,
+% it adds the |/Ref| array to the structure.
+% The value should be a comma separated list of structure labels
+% set with the |label| key. e.g. |ref={label1,label2}|.
+% \end{function}
+% \begin{function}{E}
+% This key sets the |/E| key, the expanded form of an
+% abbreviation or an acronym
+% (I couldn't think of a better name, so I sticked to E).
+% \end{function}
+% \begin{function}{AF,AFinline,AFinline-o}
+% \begin{syntax}
+% AF = \meta{object name}\\
+% AF-inline = \meta{text content}
+% \end{syntax}
+% These keys allows to reference an associated file in the structure element.
+% The value \meta{object name} should be the name of an object pointing
+% to the \texttt{/Filespec} dictionary as expected by
+% |\pdf_object_ref:n| from a current \texttt{l3kernel}.
+%
+% The value |AF-inline| is some text,
+% which is embedded in the PDF as a text file with mime type text/plain.
+% |AF-inline-o| is like |AF-inline| but expands the value once.
+%
+% Future versions will perhaps extend this to more mime types, but it is
+% still a research task to find out what is really needed.
+%
+% \end{function}
+%
+% \begin{function}{attribute}
+% This key takes as argument a comma list of attribute names
+% (use braces to protect the commas from the external key-val parser)
+% and allows to add one or more attribute dictionary entries in
+% the structure object. As an example
+% \begin{verbatim}
+% \tagstructbegin{tag=TH,attribute= TH-row}
+% \end{verbatim}
+% Attribute names and their content must be declared first in \cs{tagpdfsetup}.
+%
+% \end{function}
%
+% \begin{function}{attribute-class}
+% This key takes as argument a comma list of attribute class names
+% (use braces to protect the commas from the external key-val parser)
+% and allows to add one or more attribute classes to the structure object.
+%
+% Attribute class names and their content
+% must be declared first in \cs{tagpdfsetup}.
+% \end{function}
+% \subsection{Setup keys}
+% \begin{function}{newattribute}
+% \begin{syntax}
+% newattribute = \Arg{name}\Arg{Content}
+% \end{syntax}
+% This key can be used in the setup command \cs{tagpdfsetup} and allow to declare a
+% new attribute, which can be used as attribute or attribute class.
+% The value are two brace groups, the first contains the name, the second the content.
+% \begin{verbatim}
+% \tagpdfsetup
+% {
+% newattribute =
+% {TH-col}{/O /Table /Scope /Column},
+% newattribute =
+% {TH-row}{/O /Table /Scope /Row},
+% }
+% \end{verbatim}
+%
+% \end{function}
+% \end{documentation}
+% \begin{implementation}
% \begin{macrocode}
%<@@=tag>
-%<*struct>
-\ProvidesExplPackage {tagpdf-struct-code} {2021-06-14} {0.82}
+%<*header>
+\ProvidesExplPackage {tagpdf-struct-code} {2021-06-29} {0.9}
{part of tagpdf - code related to storing structure}
+%</header>
% \end{macrocode}
+% \section{Variables}
+% \begin{variable}{\c@g_@@_struct_abs_int}
+% Every structure will have a unique, absolute number.
% I will use a latex counter for the structure count
-% to have a chance to avoid double structures in align etc
+% to have a chance to avoid double structures in align etc.
+%
% \begin{macrocode}
+%<*package>
\newcounter { g_@@_struct_abs_int }
\int_gzero:N \c@g_@@_struct_abs_int
% \end{macrocode}
-% a sequence to store structnum -> the obj numbers
-% to allow easy mapping over the structures
+% \end{variable}
+%
+% \begin{variable}{\g_@@_struct_objR_seq}
+% a sequence to store mapping between the
+% structure number and the object number.
+% We assume that structure numbers are assign
+% consecutively and so the index of the seq can be used.
+% A seq allows easy mapping over the structures.
% \begin{macrocode}
\@@_seq_new:N \g_@@_struct_objR_seq
% \end{macrocode}
-% a sequence for the structure stack.
+% \end{variable}
+%
+% \begin{variable}{\g_@@_struct_stack_seq}
+% A stack 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}
% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_struct_tag_stack_seq}
% 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
+% \end{variable}
+%
+% \begin{variable}{\g_@@_struct_stack_current_tl,\l_@@_struct_stack_parent_tmpa_tl}
+% The global variable will hold the current structure number.
+% The local temporary variable will hold the parent when we fetch it from the stack.
% \begin{macrocode}
-\tl_new:N \l_@@_struct_stack_parent_tmp_tl
\tl_new:N \g_@@_struct_stack_current_tl
+\tl_new:N \l_@@_struct_stack_parent_tmpa_tl
% \end{macrocode}
-% I need at least one structure: the StructTreeRoot
+% \end{variable}
+%
+% I will need at least one structure: the StructTreeRoot
% normally it should have only one kid, e.g. the document element.
% The data of the StructTreeRoot and the StructElem are in properties:
-% \g_@@_struct_0_prop for the root
-% \g_@@_struct_N_prop, N >=1
-% they have all the keys
-% objnum - number,
-% Type - StructTreeRoot or StructElem
-% num - number (identical to the num in the name, or 0 for the root)
+% |\g_@@_struct_0_prop| for the root and
+% |\g_@@_struct_N_prop|, $N \geq =1$ for the other.
+%
+% This creates quite a number of properties, so perhaps we will have to
+% do this more efficiently in the future.
+%
+% All properties have at least the keys
+% \begin{description}
+% \item[Type] StructTreeRoot or StructElem
+% \end{description}
% and the keys from the two following lists
% (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{variable}
+% {
+% \c_@@_struct_StructTreeRoot_entries_seq,
+% \c_@@_struct_StructElem_entries_seq
+% }
+% These seq contain the keys we support in the two object types.
+% They are currently no longer used, but are provided as documentation and
+% for potential future checks.
+% They should be adapted if there are changes in the PDF format.
% \begin{macrocode}
\seq_const_from_clist:Nn \c_@@_struct_StructTreeRoot_entries_seq
{%p. 857/858
@@ -79,7 +300,7 @@
K, % kid, dictionary or array of dictionaries
IDTree, % currently unused
ParentTree, % required,obj ref to the parent tree
- ParentTreeNextKey, %optional
+ ParentTreeNextKey, % optional
RoleMap,
ClassMap,
Namespaces
@@ -96,22 +317,55 @@
K, %kids
A, %attributes, probably unused
C, %class ""
- %R,
+ %R, %attribute revision number, irrelevant for us as we
+ % don't update/change existing PDF and (probably)
+ % deprecated in PDF 2.0
T, %title, value in () or <>
Lang, %language
Alt, % value in () or <>
- E, %abreviation
+ E, % abreviation
ActualText,
AF, %pdf 2.0, array of dict, associated files
NS, %pdf 2.0, dict, namespace
PhoneticAlphabet, %pdf 2.0
Phoneme %pdf 2.0
}
-
-% I need an output handler for each prop, to get expandable output
-% see https://tex.stackexchange.com/questions/424208/expandable-version-of-a-expl3-command/424213#424213
-
-\cs_new:Nn \@@_struct_output_prop_aux:nn %#1 num, #2 key
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Variables used by the keys}
+% \begin{variable}{\g_@@_struct_tag_tl,\g_@@_struct_tag_NS_tl}
+% Use by the tag key to store the tag and the namespace.
+% \begin{macrocode}
+\tl_new:N \g_@@_struct_tag_tl
+\tl_new:N \g_@@_struct_tag_NS_tl
+% \end{macrocode}
+% \end{variable}
+% \begin{variable}{\l_@@_struct_key_label_tl}
+% This will hold the label value.
+% \begin{macrocode}
+\tl_new:N \l_@@_struct_key_label_tl
+% \end{macrocode}
+% \end{variable}
+% \begin{variable}{\l_@@_struct_elem_stash_bool}
+% This will keep track of the stash status
+% \begin{macrocode}
+\bool_new:N \l_@@_struct_elem_stash_bool
+% \end{macrocode}
+% \end{variable}
+% \section{Commands}
+%
+% The properties must be in some places handled expandably.
+% So I need an output handler for each prop, to get expandable output
+% see \url{https://tex.stackexchange.com/questions/424208}.
+% There is probably room here for a more efficient implementation.
+% TODO check if this can now be implemented with the pdfdict commands.
+% The property contains currently non pdf keys, but e.g. object numbers are
+% perhaps no longer needed as we have named object anyway.
+%
+% \begin{macro}{\@@_struct_output_prop_aux:nn,\@@_new_output_prop_handler:n}
+% \begin{macrocode}
+\cs_new:Npn \@@_struct_output_prop_aux:nn #1 #2 %#1 num, #2 key
{
\prop_if_in:cnT
{ g_@@_struct_#1_prop }
@@ -121,99 +375,113 @@
}
}
-\cs_new:Nn \@@_new_output_prop_handler:n
+\cs_new_protected:Npn \@@_new_output_prop_handler:n #1
{
\cs_new:cn { @@_struct_output_prop_#1:n }
{
\@@_struct_output_prop_aux:nn {#1}{##1}
}
}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Initialization of the StructTreeRoot}
+% The first structure element, the StructTreeRoot is special, so
+% created manually. The underlying object is |@@/struct/0| which is currently
+% created in the tree code (TODO move it here).
+% The |ParentTree| and |RoleMap| entries are added at begin document
+% in the tree code as they refer to object which are setup in other parts of the
+% code. This avoid timing issues.
+%
+% \begin{macrocode}
+\tl_gset:Nn \g_@@_struct_stack_current_tl {0}
+% \end{macrocode}
-
-% the first one, the StructTreeRoot is special, so
-% created manually:
+%
+% \begin{variable}{g_@@_struct_0_prop,g_@@_struct_kids_0_seq}
+% \begin{macrocode}
\@@_prop_new:c { g_@@_struct_0_prop }
\@@_new_output_prop_handler:n {0}
-\tl_gset:Nn \g_@@_struct_stack_current_tl {0}
-
\@@_seq_new:c { g_@@_struct_kids_0_seq }
-% new
-\@@_prop_gput:cnx
- { g_@@_struct_0_prop }
- { objref}
- { \pdf_object_ref:n { @@/struct/0 } }
-
\@@_prop_gput:cnn
{ g_@@_struct_0_prop }
{ Type }
{ /StructTreeRoot }
-% the constants are defined in the tree code.
-\@@_prop_gput:cnx
- { g_@@_struct_0_prop }
- { ParentTree }
- { \pdf_object_ref:n { @@/tree/parenttree } }
-\@@_prop_gput:cnx
- { g_@@_struct_0_prop }
- { RoleMap }
- { \pdf_object_ref:n { @@/tree/rolemap } }
-
-\@@_prop_gput:cnn
- { g_@@_struct_0_prop }
- { entries }
- { StructTreeRoot }
-
-\@@_prop_gput:cnn
- { g_@@_struct_0_prop }
- { num }
- { 0 }
-%Namespaces are pdf 2.0 but it doesn't harm to have an empty entry
+% \end{macrocode}
+% Namespaces are pdf 2.0 but it doesn't harm
+% to have an empty entry. We could add a test, but if the code moves into
+% the kernel, timing could get tricky.
+% \begin{macrocode}
\@@_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
-
-\cs_new:Nn \@@_struct_kid_mc_gput_right:nn %#1 structure num, #2 MCID absnum%
+% \end{macrocode}
+% \end{variable}
+% \subsection{Handlings kids}
+% Commands to store the kids. Kids in a structure can be a reference to a mc-chunk,
+% an object reference to another structure element, or a object reference to an
+% annotation (through an OBJR object).
+% \begin{macro}{\@@_struct_kid_mc_gput_right:nn}
+% The command to store an mc-chunk, this is a dictionary of type MCR.
+% It would be possible to write out the content directly as unnamed object
+% and to store only the object reference, but probably this would be slower,
+% and the PDF is more readable like this.
+% The code doesn't try to avoid the use of the /Pg key by checking page numbers.
+% That imho only slows down without much gain.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_kid_mc_gput_right:nn #1 #2 %#1 structure num, #2 MCID absnum%
{
- %\@@_store_pdfpageref:Nn \l_tmpa_tl { \@@_ref_value:enn{mcid-#2}{tagabspage}{1} }
\@@_seq_gput_right:cx
{ g_@@_struct_kids_#1_seq }
{
<<
/Type \c_space_tl /MCR \c_space_tl
- /Pg %\c_space_tl \l_tmpa_tl \c_space_tl 0 \c_space_tl R \c_space_tl
+ /Pg
\c_space_tl
\pdf_pageobject_ref:n { \@@_ref_value:enn{mcid-#2}{tagabspage}{1} }
/MCID \c_space_tl \@@_ref_value:enn{mcid-#2}{tagmcid}{1}
>>
}
}
-
-\cs_new:Nn\@@_struct_kid_struct_gput_right:nn %#1 num of parent struct, #2 kid struct
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% \@@_struct_kid_struct_gput_right:nn,\@@_struct_kid_struct_gput_right:xx
+% }
+% This commands adds a structure as kid. We only need to record the object
+% reference in the sequence.
+% \begin{macrocode}
+\cs_new_protected:Npn\@@_struct_kid_struct_gput_right:nn #1 #2 %#1 num of parent struct, #2 kid struct
{
\@@_seq_gput_right:cx
{ g_@@_struct_kids_#1_seq }
{
- \prop_item:cn
- { g_@@_struct_#2_prop }
- { objref }
+ \pdf_object_ref:n { @@/struct/#2 }
}
}
-\cs_new:Nn\@@_struct_kid_OBJR_gput_right:nn %#1 num of parent struct, #2 obj reference
+\cs_generate_variant:Nn \@@_struct_kid_struct_gput_right:nn {xx}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {\@@_struct_kid_OBJR_gput_right:nn,\@@_struct_kid_OBJR_gput_right:xx}
+% At last the command to add an OBJR object. This has to write an object first.
+% The first argument is the number of the parent structure, the second the
+% (expanded) object reference of the annotation.
+% \begin{macrocode}
+\cs_new_protected:Npn\@@_struct_kid_OBJR_gput_right:nn #1 #2 %#1 num of parent struct,
+ %#2 obj reference
{
- \pdf_object_unnamed_write:nx
+ \pdf_object_unnamed_write:nn
{ dict }
{
- /Type \c_space_tl /OBJR \c_space_tl
- /Obj~#2
+ /Type/OBJR/Obj~#2
}
\@@_seq_gput_right:cx
{ g_@@_struct_kids_#1_seq }
@@ -222,27 +490,43 @@
}
}
-\cs_generate_variant:Nn\@@_struct_kid_OBJR_gput_right:nn { nx }
+\cs_generate_variant:Nn\@@_struct_kid_OBJR_gput_right:nn { xx }
-\cs_new:Nn\@@_struct_exchange_kid_command:N %N= seq
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {\@@_struct_exchange_kid_command:N, \@@_struct_exchange_kid_command:c}
+% In luamode it can happen that a single kid in a structure is split at a page
+% break into two or more mcid. In this case the lua code has to convert
+% put the dictionary of the kid into an array. See issue 13 at tagpdf repo.
+% We exchange the dummy command for the kids to mark this case.
+% \begin{macrocode}
+\cs_new_protected:Npn\@@_struct_exchange_kid_command:N #1 %#1 = seq var
{
- \seq_gpop_left:NN #1 \l_tmpa_tl
+ \seq_gpop_left:NN #1 \l_@@_tmpa_tl
\regex_replace_once:nnN
{ \c{\@@_mc_insert_mcid_kids:n} }
{ \c{\@@_mc_insert_mcid_single_kids:n} }
- \l_tmpa_tl
- \seq_gput_left:NV #1 \l_tmpa_tl
+ \l_@@_tmpa_tl
+ \seq_gput_left:NV #1 \l_@@_tmpa_tl
}
\cs_generate_variant:Nn\@@_struct_exchange_kid_command:N { c }
-
-\cs_new:Nn \@@_struct_fill_kid_key:n %#1 is the struct num
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ \@@_struct_fill_kid_key:n }
+% This command adds the kid info to the K entry. In lua mode the
+% content contains commands which are expanded later. The argument is the structure
+% number.
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_fill_kid_key:n #1 %#1 is the struct num
{
\int_case:nnF
{
\seq_count:c
{
- g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ g_@@_struct_kids_#1_seq
}
}
{
@@ -251,17 +535,17 @@
{ 1 } % 1 kid, insert
{
% in this case we need a special command in
- %luamode to get the array right. See issue #13
+ % luamode to get the array right. See issue #13
\bool_if:NT\g_@@_mode_lua_bool
{
\@@_struct_exchange_kid_command:c
- {g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq}
+ {g_@@_struct_kids_#1_seq}
}
\@@_prop_gput:cnx { g_@@_struct_#1_prop } {K}
{
\seq_item:cn
{
- g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ g_@@_struct_kids_#1_seq
}
{1}
}
@@ -273,7 +557,7 @@
[
\seq_use:cn
{
- g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ g_@@_struct_kids_#1_seq
}
{
\c_space_tl
@@ -283,22 +567,25 @@
}
}
-% this command can be used for roots and structure elements
-% #1 is a num
-
-\tl_new:N \l_@@_struct_dict_content_tl
-
-\cs_new:Nn \@@_struct_get_dict_content:n
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_struct_get_dict_content:nN}
+% This maps the dictionary content of a structure into a tl-var.
+% Basically it does what |\pdfdict_use:n| does.
+% TODO!! this looks over-complicated. Check if it can be done with pdfdict now.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_get_dict_content:nN #1 #2 %#1: stucture num
{
- %\tl_set:Nn \l_@@_struct_dict_content_tl {<<}
- \tl_clear:N \l_@@_struct_dict_content_tl
+ \tl_clear:N #2
\seq_map_inline:cn
{
- c_@@_struct_\prop_item:cn{ g_@@_struct_#1_prop }{entries}_entries_seq
+ c_@@_struct_
+ \int_compare:nNnTF{#1}={0}{StructTreeRoot}{StructElem}
+ _entries_seq
}
{
\tl_put_right:Nx
- \l_@@_struct_dict_content_tl
+ #2
{
\prop_if_in:cnT
{ g_@@_struct_#1_prop }
@@ -308,35 +595,99 @@
}
}
}
- %\tl_put_right:Nn \l_@@_struct_dict_content_tl { >> }
}
-
-
-% #1 is the struct num
-\cs_new:Nn \@@_struct_write_obj:n
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_struct_write_obj:n}
+% This writes out the structure object.
+% This is done in the finish code, in the tree module and
+% guarded by the tree boolean.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_write_obj:n #1 % #1 is the struct num
{
- \prop_if_in:cnTF
- { g_@@_struct_#1_prop }
- { objref }
+ \pdf_object_if_exist:nTF { @@/struct/#1 }
{
\@@_struct_fill_kid_key:n { #1 }
- %\prop_show:c { g_@@_struct_#1_prop }
- \@@_struct_get_dict_content:n { #1 }
+ \@@_struct_get_dict_content:nN { #1 } \l_@@_tmpa_tl
\exp_args:Nx
\pdf_object_write:nx
{ @@/struct/#1 }
{
- \l_@@_struct_dict_content_tl
+ \l_@@_tmpa_tl
}
}
{
\msg_error:nnn { tag } { struct-no-objnum } { #1}
}
}
-
-% this command allows to get the current structure tag. We will need to handle nesting
-% P
-\cs_new:Nn \@@_get_data_struct_tag:
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_struct_insert_annot:nn}
+% This is the command to insert an annotation into the structure.
+% It can probably be used for xform too.
+%
+% Annotations used as structure content must
+% \begin{enumerate}
+% \item add a StructParent integer to their dictionary
+% \item push the object reference as OBJR object in the structure
+% \item Add a Structparent/obj-nr reference to the parent tree.
+% \end{enumerate}
+% For a link this looks like this
+% \begin{verbatim}
+% \tag_struct_begin:n { tag=Link }
+% \tag_mc_begin:n { tag=Link }
+% (1) \pdfannot_dict_put:nnx
+% { link/URI }
+% { StructParent }
+% { \int_use:N\c@g_@@_parenttree_obj_int }
+% <start link> link text <stop link>
+% (2+3) \@@_struct_insert_annot:nn {obj ref}{parent num}
+% \tag_mc_end:
+% \tag_struct_end:
+% \end{verbatim}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_insert_annot:nn #1 #2 %#1 object reference to the annotation/xform
+ %#2 structparent number
+ {
+ \bool_if:NT \g_@@_active_struct_bool
+ {
+ %get the number of the parent structure:
+ \seq_get:NNF
+ \g_@@_struct_stack_seq
+ \l_@@_struct_stack_parent_tmpa_tl
+ {
+ \msg_error:nn { tag } { struct-faulty-nesting }
+ }
+ %put the obj number of the annot in the kid entry, this also creates
+ %the OBJR object
+ \@@_struct_kid_OBJR_gput_right:xx
+ {
+ \l_@@_struct_stack_parent_tmpa_tl
+ }
+ {
+ #1 %
+ }
+ % add the parent obj number to the parent tree:
+ \exp_args:Nnx
+ \@@_parenttree_add_objr:nn
+ {
+ #2
+ }
+ {
+ \pdf_object_ref:e { @@/struct/\l_@@_struct_stack_parent_tmpa_tl }
+ }
+ % increase the int:
+ \stepcounter{ g_@@_parenttree_obj_int }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_get_data_struct_tag:}
+% this command allows \cs{tag_get:n} to get the current
+% structure tag with the keyword |struct_tag|. We will need to handle nesting
+% \begin{macrocode}
+\cs_new:Npn \@@_get_data_struct_tag:
{
\exp_args:Ne
\tl_tail:n
@@ -344,28 +695,33 @@
\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?
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Keys}
+% This are the keys for the user commands.
% 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}
+% at the begin.
+% \begin{macro}
+% {
+% label,stash,tag,
+% title,title-o,
+% alttext,alttext-o,
+% actualtext,actualtext-o
+% lang,ref,E
+% }
+% \begin{macrocode}
\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?? 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 \g_@@_struct_tag_tl
- }
- \@@_prop_gput:cnx
+ {
+ \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} }
+ \@@_check_structure_tag:N \g_@@_struct_tag_tl
+ \@@_prop_gput:cnx
{ g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
{ S }
{ \pdf_name_from_unicode_e:n{ \g_@@_struct_tag_tl} } %
@@ -482,12 +838,17 @@
{ <\l_@@_tmpa_str> }
},
}
-
-% keys for AF keys, they rely on l3pdffile!
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{AF,AFinline,AFinline-o}
+% keys for the AF keys (associated files). They use commands from l3pdffile!
% The stream variants use txt as extension to get the mimetype.
+% TODO: check if this should be configurable. For math we will perhaps need another
+% extension.
+% \begin{macrocode}
\keys_define:nn { @@ / struct }
{
- AF .code:n = % T property
+ AF .code:n = % AF property
{
\pdf_object_if_exist:nTF {#1}
{
@@ -503,8 +864,7 @@
,AFinline .code:n =
{
\group_begin:
- \exp_args:Ne
- \pdf_object_if_exist:nF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
+ \pdf_object_if_exist:eF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
{
\pdffile_embed_stream:nxx
{#1}
@@ -520,8 +880,7 @@
,AFinline-o .code:n =
{
\group_begin:
- \exp_args:Ne
- \pdf_object_if_exist:nF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
+ \pdf_object_if_exist:eF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
{
\pdffile_embed_stream:oxx
{#1}
@@ -535,81 +894,70 @@
\group_end:
}
}
-
-\cs_new_protected:Nn \tag_struct_begin:n
+% \end{macrocode}
+% \end{macro}
+%
+% \section{User commands}
+%
+% \begin{macro}{\tag_struct_begin:n,\tag_struct_end:}
+% \begin{macrocode}
+\cs_new_protected:Npn \tag_struct_begin:n #1 %#1 key-val
{
- \group_begin:
- \int_gincr:N \c@g_@@_struct_abs_int
- \@@_prop_new:c { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- \@@_new_output_prop_handler:n {\int_eval:n { \c@g_@@_struct_abs_int }}
- \@@_seq_new:c { g_@@_struct_kids_\int_eval:n { \c@g_@@_struct_abs_int }_seq}
- %\@@_pdfreserveobjnum:N \l_tmpa_tl
- \exp_args:Ne
- \pdf_object_new:nn
- { @@/struct/\int_eval:n { \c@g_@@_struct_abs_int } }
- { dict }
- \@@_prop_gput:cnx
- { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- { objref}
+ \@@_check_if_active_struct:T
{
+ \group_begin:
+ \int_gincr:N \c@g_@@_struct_abs_int
+ \@@_prop_new:c { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ \@@_new_output_prop_handler:n {\int_eval:n { \c@g_@@_struct_abs_int }}
+ \@@_seq_new:c { g_@@_struct_kids_\int_eval:n { \c@g_@@_struct_abs_int }_seq}
\exp_args:Ne
- \pdf_object_ref:n
- {@@/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
- { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- { num}
- { \int_eval:n { \c@g_@@_struct_abs_int } }
- \@@_prop_gput:cno
- { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- { Type }
- { /StructElem }
- \@@_prop_gput:cno
- { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- { entries }
- { StructElem }
- \keys_set:nn { @@ / struct} { #1 }
- \@@_check_structure_has_tag:n { \int_eval:n {\c@g_@@_struct_abs_int} }
- \tl_if_empty:NF
- \l_@@_struct_key_label_tl
- {
- \@@_ref_label:en{tagpdfstruct-\l_@@_struct_key_label_tl}{struct}
- }
- %get the potential parent from the stack:
- \seq_get:NNF
- \g_@@_struct_stack_seq
- \l_@@_struct_stack_parent_tmp_tl
- {
- \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
- \l_@@_struct_elem_stash_bool
- {%set the parent
- \@@_prop_gput:cnx
- { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
- { P }
+ \pdf_object_new:nn
+ { @@/struct/\int_eval:n { \c@g_@@_struct_abs_int } }
+ { dict }
+ \@@_prop_gput:cno
+ { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ { Type }
+ { /StructElem }
+ \keys_set:nn { @@ / struct} { #1 }
+ \@@_check_structure_has_tag:n { \int_eval:n {\c@g_@@_struct_abs_int} }
+ \tl_if_empty:NF
+ \l_@@_struct_key_label_tl
+ {
+ \@@_ref_label:en{tagpdfstruct-\l_@@_struct_key_label_tl}{struct}
+ }
+ %get the potential parent from the stack:
+ \seq_get:NNF
+ \g_@@_struct_stack_seq
+ \l_@@_struct_stack_parent_tmpa_tl
{
- \prop_item:cn
- { g_@@_struct_\l_@@_struct_stack_parent_tmp_tl _prop}
- { objref }
+ \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
+ \l_@@_struct_elem_stash_bool
+ {%set the parent
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { P }
+ {
+ \pdf_object_ref:e { @@/struct/\l_@@_struct_stack_parent_tmpa_tl }
+ }
+ %record this structure as kid:
+ %\tl_show:N \g_@@_struct_stack_current_tl
+ %\tl_show:N \l_@@_struct_stack_parent_tmpa_tl
+ \@@_struct_kid_struct_gput_right:xx
+ { \l_@@_struct_stack_parent_tmpa_tl }
+ { \g_@@_struct_stack_current_tl }
+ %\prop_show:c { g_@@_struct_\g_@@_struct_stack_current_tl _prop }
+ %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmpa_tl _seq}
}
- %record this structure as kid:
- %\tl_show:N \g_@@_struct_stack_current_tl
- %\tl_show:N \l_@@_struct_stack_parent_tmp_tl
- \@@_struct_kid_struct_gput_right:nn
- { \l_@@_struct_stack_parent_tmp_tl }
- { \g_@@_struct_stack_current_tl }
%\prop_show:c { g_@@_struct_\g_@@_struct_stack_current_tl _prop }
- %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmp_tl _seq}
- }
- %\prop_show:c { g_@@_struct_\g_@@_struct_stack_current_tl _prop }
- %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmp_tl _seq}
- \group_end:
+ %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmpa_tl _seq}
+ \group_end:
+ }
}
@@ -617,149 +965,145 @@
{ %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
+ \@@_check_if_active_struct:T
{
- \int_compare:nNnT {\l_@@_loglevel_int} > { 0 }
+ \seq_gpop:NN \g_@@_struct_tag_stack_seq \l_@@_tmpa_tl
+ \seq_gpop:NNTF \g_@@_struct_stack_seq \l_@@_tmpa_tl
{
\@@_check_info_closing_struct:o { \g_@@_struct_stack_current_tl }
}
- }
- { \@@_check_no_open_struck: }
- % get the previous one, shouldn't be empty as the root should be there
- \seq_get:NNTF \g_@@_struct_stack_seq \l_tmpa_tl
- {
- \tl_gset:NV \g_@@_struct_stack_current_tl \l_tmpa_tl
- }
- {
- \@@_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
- }
- }
-
-
-
-\cs_new_protected:Nn \tag_struct_use:n %#1 is the label
- {
- \prop_if_exist:cTF
- { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop } %??????????
- {
- \@@_check_struct_used:n {#1}
- %add the label structure as kid to the current structure (can be the root)
- \@@_struct_kid_struct_gput_right:nn
- { \g_@@_struct_stack_current_tl }
- { \@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0} }
- %add the current structure to the labeled one as parents
- \@@_prop_gput:cnx
- { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0}_prop }
- { P }
+ { \@@_check_no_open_struct: }
+ % get the previous one, shouldn't be empty as the root should be there
+ \seq_get:NNTF \g_@@_struct_stack_seq \l_@@_tmpa_tl
{
- \prop_item:cn
- { g_@@_struct_\g_@@_struct_stack_current_tl _prop}
- { objref }
+ \tl_gset:NV \g_@@_struct_stack_current_tl \l_@@_tmpa_tl
}
- }
- {
- \msg_warning:nnn{ tag }{struct-label-unknown}{#1}
- }
- }
-
-
-%%%% Code to tag annotations like links.
-% Annotations used as structure content must
-% (1) add a StructParent integer to their dictionary
-% (2) push the object reference as OBJR object in the structure
-% (3) Add a Stuctparent/obj-nr reference to the parent three.
-% For a link this looks like this
-% \tag_struct_begin:n { tag=Link }
-% \tag_mc_begin:n { tag=Link }
-% (1) \pdfannot_dict_put:nnx
-% { link/URI }
-% { StructParent }
-% { \int_use:N\c@g_@@_parenttree_obj_int }
-% <start link> link text <stop link>
-% (2+3) \@@_struct_insert_annot:nn {obj ref}{parent num}
-% \tag_mc_end:
-% \tag_struct_end:
-%
-%%%% this works for url, see exp-link.pdf.
-%%%% it must be checked for other links
-
-
-% this will probably be used for xform too, but then we can rename it.
-\cs_new_protected:Npn \@@_struct_insert_annot:nn #1 #2 %#1 object reference to the annotation/xform
- %#2 structparent number
- {
- \bool_if:NT \g_@@_active_struct_bool
- {
- %get the number of the parent link structure:
- \seq_get:NNF
- \g_@@_struct_stack_seq
- \l_@@_struct_stack_parent_tmp_tl
{
- \msg_error:nn { tag } { struct-faulty-nesting }
+ \@@_check_no_open_struct:
}
- %put the obj number of link annot in the kid entry:
- \@@_struct_kid_OBJR_gput_right:nx
+ \seq_get:NNT \g_@@_struct_tag_stack_seq \l_@@_tmpa_tl
{
- \l_@@_struct_stack_parent_tmp_tl
+ \tl_gset:NV \g_@@_struct_tag_tl \l_@@_tmpa_tl
}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\tag_struct_use:n}
+% This command allows to use a stashed structure in another place.
+% TODO: decide how it should be guarded. Probably by the struct-check.
+% \begin{macrocode}
+\cs_new_protected:Nn \tag_struct_use:n %#1 is the label
+ {
+ \@@_check_if_active_struct:T
+ {
+ \prop_if_exist:cTF
+ { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop } %
{
- #1 %
- }
- % add the parent obj number to the parent tree:
- \exp_args:Nnx
- \@@_parenttree_add_objr:nn
- {
- #2
+ \@@_check_struct_used:n {#1}
+ %add the label structure as kid to the current structure (can be the root)
+ \@@_struct_kid_struct_gput_right:xx
+ { \g_@@_struct_stack_current_tl }
+ { \@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0} }
+ %add the current structure to the labeled one as parents
+ \@@_prop_gput:cnx
+ { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0}_prop }
+ { P }
+ {
+ \pdf_object_ref:e { @@/struct/\g_@@_struct_stack_current_tl }
+ }
}
{
- \prop_item:cn
- { g_@@_struct_\l_@@_struct_stack_parent_tmp_tl _prop }
- { objref }
+ \msg_warning:nnn{ tag }{struct-label-unknown}{#1}
}
- % increase the int:
- \stepcounter{ g_@@_parenttree_obj_int }
}
}
-
-
-
-% Code to add an annot to the structure.
-% This is for example needed for widget annotations and form field
-% It reuses the command used by links
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \tag_struct_insert_annot:nn,
+% \tag_struct_insert_annot:xx
+% }
+% \begin{macro}[EXP]
+% {
+% \tag_struct_parent_int:
+% }
+% This are the user command to insert annotations. They must be used
+% together to get the numbers right. They use a counter to the
+% |StructParent| and \cs{tag_struct_insert_annot:nn} increases the
+% counter given back by \cs{tag_struct_parent_int:}.
+%
+% It must be used together with |\tag_struct_parent_int:| to insert an
+% annotation.
+% TODO: decide how it should be guarded if tagging is deactivated.
+% \begin{macrocode}
\cs_new_protected:Npn \tag_struct_insert_annot:nn #1 #2 %#1 should be an object reference
%#2 struct parent num
{
- \@@_struct_insert_annot:nn {#1}{#2}
+ \@@_check_if_active_struct:T
+ {
+ \@@_struct_insert_annot:nn {#1}{#2}
+ }
}
\cs_generate_variant:Nn \tag_struct_insert_annot:nn {xx}
\cs_new:Npn \tag_struct_parent_int: {\int_use:c { c@g_@@_parenttree_obj_int }}
-%</struct>
+%</package>
% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \section{Attributes and attribute classes}
% \begin{macrocode}
-%<*attr>
-\ProvidesExplPackage {tagpdf-attr-code} {2021-06-14} {0.82}
+%<*header>
+\ProvidesExplPackage {tagpdf-attr-code} {2021-06-29} {0.9}
{part of tagpdf - code related to attributes and attribute classes}
-
-% the obj is written in tagpdf-tree-code.
-
-\seq_new:N \g_@@_attr_class_used_seq
-\prop_new:N \g_@@_attr_objref_prop %will contain obj num of used attributes
-
+%</header>
+% \end{macrocode}
+% \subsection{Variables}
+% \begin{variable}
+% {
+% ,\g_@@_attr_entries_prop
+% ,\g_@@_attr_class_used_seq
+% ,\g_@@_attr_objref_prop
+% ,\l_@@_attr_value_tl
+% }
+% |\g_@@_attr_entries_prop| will store attribute names and their dictionary content.\\
+% |\g_@@_attr_class_used_seq| will hold the attributes which have been used as
+% class name.
+% |\l_@@_attr_value_tl| is used to build the attribute array or key.
+% Everytime an attribute is used for the first time, and object is created
+% with its content, the name-object reference relation is stored in
+% |\g_@@_attr_objref_prop|
+% \begin{macrocode}
+%<*package>
\prop_new:N \g_@@_attr_entries_prop
-\tl_new:N \g_@@_attr_class_content_tl
-\tl_new:N \l_@@_attr_objtmp_tl
+\seq_new:N \g_@@_attr_class_used_seq
\tl_new:N \l_@@_attr_value_tl
-
-
-\cs_new_protected:Nn \@@_attr_new_entry:nn %#1:name, #2: content
+\prop_new:N \g_@@_attr_objref_prop %will contain obj num of used attributes
+% \end{macrocode}
+% \end{variable}
+% \subsection{Commands and keys}
+% \begin{macro}{\@@_attr_new_entry:nn,newattribute}
+% This allows to define attributes. Defined attributes
+% are stored in a global property. |newattribute| expects
+% two brace group, the name and the content. The content typically
+% needs an |/O| key for the owner. An example look like
+% this.
+% \begin{verbatim}
+% \tagpdfsetup
+% {
+% newattribute =
+% {TH-col}{/O /Table /Scope /Column},
+% newattribute =
+% {TH-row}{/O /Table /Scope /Row},
+% }
+% \end{verbatim}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_attr_new_entry:nn #1 #2 %#1:name, #2: content
{
\prop_gput:Nnn \g_@@_attr_entries_prop
{#1}{#2}
@@ -772,16 +1116,19 @@
\@@_attr_new_entry:nn #1
}
}
-
-
-% the key for the structure:
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{attribute-class}
+% attribute-class has to store the used attribute names so that
+% they can be added to the ClassMap later.
+% \begin{macrocode}
\keys_define:nn { @@ / struct }
{
attribute-class .code:n =
{
- \clist_set:No \l_tmpa_clist { #1 }
- \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist
- \seq_map_inline:Nn \l_tmpa_seq
+ \clist_set:No \l_@@_tmpa_clist { #1 }
+ \seq_set_from_clist:NN \l_@@_tmpa_seq \l_@@_tmpa_clist
+ \seq_map_inline:Nn \l_@@_tmpa_seq
{
\prop_if_in:NnF \g_@@_attr_entries_prop {##1}
{
@@ -789,38 +1136,41 @@
}
\seq_gput_left:Nn\g_@@_attr_class_used_seq { ##1}
}
- \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq
+ \seq_set_map:NNn \l_@@_tmpb_seq \l_@@_tmpa_seq
{
/##1
}
- \tl_set:Nx \l_tmpa_tl
+ \tl_set:Nx \l_@@_tmpa_tl
{
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{[}
- \seq_use:Nn \l_tmpb_seq { \c_space_tl }
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{]}
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{[}
+ \seq_use:Nn \l_@@_tmpb_seq { \c_space_tl }
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{]}
}
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 0 }
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 0 }
{
\@@_prop_gput:cnx
{ g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
{ C }
- { \l_tmpa_tl }
+ { \l_@@_tmpa_tl }
%\prop_show:c { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
}
- }
+ }
}
-
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{attribute}
+% \begin{macrocode}
\keys_define:nn { @@ / struct }
{
attribute .code:n = % A property (attribute, value currently a dictionary)
{
- \clist_set:No \l_tmpa_clist { #1 }
- \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist
+ \clist_set:No \l_@@_tmpa_clist { #1 }
+ \seq_set_from_clist:NN \l_@@_tmpa_seq \l_@@_tmpa_clist
\tl_set:Nx \l_@@_attr_value_tl
{
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{[}%]
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{[}%]
}
- \seq_map_inline:Nn \l_tmpa_seq
+ \seq_map_inline:Nn \l_@@_tmpa_seq
{
\prop_if_in:NnF \g_@@_attr_entries_prop {##1}
{
@@ -844,7 +1194,7 @@
}
\tl_put_right:Nx \l_@@_attr_value_tl
{ %[
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{]}%
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{]}%
}
% \tl_show:N \l_@@_attr_value_tl
\@@_prop_gput:cnx
@@ -853,5 +1203,7 @@
{ \l_@@_attr_value_tl }
},
}
-%</attr>
+%</package>
% \end{macrocode}
+% \end{macro}
+% \end{implementation}