diff options
Diffstat (limited to 'Master/texmf-dist/tex/latex/tagpdf/tagpdf-struct-code.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/tagpdf/tagpdf-struct-code.sty | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-struct-code.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-struct-code.sty new file mode 100644 index 00000000000..24345dfd196 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-struct-code.sty @@ -0,0 +1,398 @@ +\ProvidesExplPackage {tagpdf-struct-code} {2018/07/04} {0.1} + {part of tagpdf - code related to storing structure} + +% I will use a latex counter for the structure count +% to have a chance to avoid double structures in align etc + +\newcounter { g__uftag_struct_abs_int } +\int_gzero:N \c@g__uftag_struct_abs_int + + +\zref@newprop {tagstruct} [0] { \int_use:N \c@g__uftag_struct_abs_int } +\zref@newlist {tagpdfstruct} +\zref@addprop {tagpdfstruct}{tagstruct} + +% a sequence stores structnum -> the obj numbers +% to allow easy mapping over the structures + +\__uftag_seq_new:N \g__uftag_struct_objR_seq + +% a sequence for the structure stack. When a sequence is opened it's number is put on the stack. +\seq_new:N \g__uftag_struct_stack_seq +\seq_gpush:Nn \g__uftag_struct_stack_seq {0} + +%this variables will hold the top entry and the parent on the stack +\tl_new:N \l__uftag_struct_stack_parent_tmp_tl +\tl_new:N \g__uftag_struct_stack_current_tl + +% I 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__uftag_struct_0_prop for the root +% \g__uftag_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) +% 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) + + +\seq_new:N \c__uftag_struct_StructTreeRoot_entries_seq +\seq_set_from_clist:Nn \c__uftag_struct_StructTreeRoot_entries_seq + {%p. 857/858 + Type, % always /StructTreeRoot + K, % kid, dictionary or array of dictionaries + IDTree, % currently unused + ParentTree, % required,obj ref to the parent tree + ParentTreeNextKey, %optional + RoleMap, + ClassMap + } + +\seq_new:N \c__uftag_struct_StructElem_entries_seq +\seq_set_from_clist:Nn \c__uftag_struct_StructElem_entries_seq + {%p 858 f + Type, %always /StructElem + S, %tag/type + P, %parent + ID, %optional + Pg, %obj num of starting page, optional + K, %kids + A, %attributes, probably unused + C, %class "" + %R, + T, %title, value in () or <> + Lang, %language + Alt, % value in () or <> + E, %abreviation + ActualText + } + +% 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 \__uftag_struct_output_prop_aux:nn %#1 num, #2 key + { + \prop_if_in:cnT + { g__uftag_struct_#1_prop } + { #2 } + { + \c_space_tl/#2~ \prop_item:cn{ g__uftag_struct_#1_prop } { #2 } + } + } + +\cs_new:Nn \__uftag_new_output_prop_handler:n + { + \cs_new:cn { __uftag_struct_output_prop_#1:n } + { + \__uftag_struct_output_prop_aux:nn {#1}{##1} + } + } + + +% the first one, the StructTreeRoot is special, so +% created manually: +\__uftag_prop_new:c { g__uftag_struct_0_prop } +\__uftag_new_output_prop_handler:n {0} +\tl_gset:Nn \g__uftag_struct_stack_current_tl {0} + +\__uftag_seq_new:c { g__uftag_struct_kids_0_seq} + +\__uftag_prop_gput:cno + { g__uftag_struct_0_prop } + { objnum} + { \c_uftag_tree_obj_structtreeroot_tl } + +\__uftag_prop_gput:cno + { g__uftag_struct_0_prop } + { Type } + { /StructTreeRoot } + +% the constants are defined in the tree code. +\__uftag_prop_gput:cnx + { g__uftag_struct_0_prop } + { ParentTree } + { \c__uftag_tree_obj_parenttree_tl\c_space_tl 0\c_space_tl R } + +\__uftag_prop_gput:cnx + { g__uftag_struct_0_prop } + { RoleMap } + { \c__uftag_tree_obj_rolemap_tl\c_space_tl 0\c_space_tl R } + +\__uftag_prop_gput:cno + { g__uftag_struct_0_prop } + { entries } + { StructTreeRoot } + +\__uftag_prop_gput:cno + { g__uftag_struct_0_prop } + { num } + { 0 } + +% 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 \__uftag_struct_kid_mc_gput_right:nn %#1 structure num, #2 MCID absnum% + { + \__uftag_store_pdfpageref:Nn \l_tmpa_tl { \zref@extractdefault{mcid-#2}{tagabspage}{1} } + \__uftag_seq_gput_right:cx + { g__uftag_struct_kids_#1_seq } + { << + /Type\c_space_tl/MCR\c_space_tl + /Pg\c_space_tl\l_tmpa_tl\c_space_tl0\c_space_tl R\c_space_tl + /MCID\c_space_tl\zref@extractdefault{mcid-#2}{tagmcid}{1} + >> + } + } + +\cs_new:Nn\__uftag_struct_kid_struct_gput_right:nn %#1 num of parent struct, #2 kid struct + { + \__uftag_seq_gput_right:cx + { g__uftag_struct_kids_#1_seq } + { + \prop_item:cn + { g__uftag_struct_#2_prop } + { objnum } + \c_space_tl 0 \c_space_tl R + } + } + +\cs_new:Nn \__uftag_struct_fill_kid_key:n %#1 is the struct num + { + \int_case:nnF + { + \seq_count:c + { + g__uftag_struct_kids_\prop_item:cn{ g__uftag_struct_#1_prop }{num}_seq + } + } + { + { 0 } + { } %no kids, do nothing + { 1 } % 1 kid, insert + { + \__uftag_prop_gput:cnx { g__uftag_struct_#1_prop } {K} + { + \seq_item:cn + { + g__uftag_struct_kids_\prop_item:cn{ g__uftag_struct_#1_prop }{num}_seq + }{1} + } + } % + } + { %many kids, use an array + \__uftag_prop_gput:cnx { g__uftag_struct_#1_prop } {K} + { + [ + \seq_use:cn + { + g__uftag_struct_kids_\prop_item:cn{ g__uftag_struct_#1_prop }{num}_seq + } + {\c_space_tl} + ] + } + } + } + +% this command can be used for roots and structure elements +% #1 is a num + +\tl_new:N \l_uftag_struct_dict_content_tl + +\cs_new:Nn \__uftag_struct_get_dict_content:n + { + \tl_set:Nn \l_uftag_struct_dict_content_tl {<<} + \seq_map_inline:cn + { + c__uftag_struct_\prop_item:cn{ g__uftag_struct_#1_prop }{entries}_entries_seq + } + { + \tl_put_right:Nx + \l_uftag_struct_dict_content_tl + { + \prop_if_in:cnT + { g__uftag_struct_#1_prop } + { ##1 } + { + \c_space_tl/##1~\prop_item:cn{ g__uftag_struct_#1_prop } { ##1 } + } + } + } + \tl_put_right:Nn \l_uftag_struct_dict_content_tl { >> } + } + + +% #1 is the struct num +\cs_new:Nn \__uftag_struct_write_obj:n + { + \prop_if_in:cnTF + { g__uftag_struct_#1_prop } + { objnum } + { + \__uftag_struct_fill_kid_key:n { #1 } + %\prop_show:c { g__uftag_struct_#1_prop } + \__uftag_struct_get_dict_content:n { #1 } + \__uftag_pdfuseobjnum:xx + { \prop_item:cn { g__uftag_struct_#1_prop } {objnum} } + { + \l_uftag_struct_dict_content_tl + } + } + { + \msg_error:nnn { tagpdf } { struct-no-objnum } { #1} + } + } + +% keys for the user commands +% why did I call the submodule elem instead of struct? +\keys_define:nn { tagpdf / elem } + { + label .tl_set:N = \l__uftag_struct_key_label_tl, + stash .bool_set:N = \l__uftag_struct_elem_stash_bool, + tag .code:n = % S property + { + \__uftag_pdf_escape_name:Nn \l__uftag_tmpa_tl { #1 } + \__uftag_prop_gput:cnx + { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop } + { S } + { /\exp_not:V\l__uftag_tmpa_tl } + }, + title .code:n = % T property + { + \__uftag_pdf_escape_string:Nn \l__uftag_tmpa_tl { #1 } + \tl_put_left:Nn \l__uftag_tmpa_tl {(^^fe^^ff} + \__uftag_prop_gput:cno + { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop } + { T } + { \l__uftag_tmpa_tl) } + }, + alttext .code:n = % Alt property + { + \__uftag_pdf_escape_string:Nn \l__uftag_tmpa_tl { #1 } + \tl_put_left:Nn \l__uftag_tmpa_tl {(^^fe^^ff} + \__uftag_prop_gput:cno + { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop } + { Alt } + { \l__uftag_tmpa_tl) } + }, + actualtext .code:n = % ActualText property + { + \__uftag_pdf_escape_hex:Nn \l__uftag_tmpa_tl {#1 } + \tl_put_left:Nn \l__uftag_tmpa_tl {<FEFF } + \__uftag_prop_gput:cno + { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop } + { ActualText } + { \l__uftag_tmpa_tl>} + }, +} + + +\cs_new:Nn \uftag_struct_begin:n + { + \group_begin: + \int_gincr:N \c@g__uftag_struct_abs_int + \__uftag_prop_new:c { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop } + \__uftag_new_output_prop_handler:n {\int_eval:n { \c@g__uftag_struct_abs_int }} + \__uftag_seq_new:c { g__uftag_struct_kids_\int_eval:n { \c@g__uftag_struct_abs_int }_seq} + \__uftag_pdfreserveobjnum:N \l_tmpa_tl + \__uftag_prop_gput:cno + { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop } + { objnum} + { \l_tmpa_tl } + \__uftag_prop_gput:cnx + { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop } + { num} + { \int_eval:n { \c@g__uftag_struct_abs_int } } + \__uftag_prop_gput:cno + { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop } + { Type } + { /StructElem } + \__uftag_prop_gput:cno + { g__uftag_struct_\int_eval:n { \c@g__uftag_struct_abs_int }_prop } + { entries } + { StructElem } + \keys_set:nn {tagpdf / elem} { #1 } + \__uftag_check_structure_has_tag:n { \int_eval:n {\c@g__uftag_struct_abs_int} } + \tl_if_empty:NF + {\l__uftag_struct_key_label_tl} + { + \zref@labelbylist{tagpdfstruct-\l__uftag_struct_key_label_tl}{tagpdfstruct} + } + %get the potential parent from the stack: + \seq_get:NNF + \g__uftag_struct_stack_seq + \l__uftag_struct_stack_parent_tmp_tl + { + \msg_error:nn { tagpdf } { struct-faulty-nesting } + } + \seq_gpush:NV \g__uftag_struct_stack_seq \c@g__uftag_struct_abs_int + \tl_gset:NV \g__uftag_struct_stack_current_tl \c@g__uftag_struct_abs_int + %\seq_show:N \g__uftag_struct_stack_seq + \bool_if:NF + \l__uftag_struct_elem_stash_bool + {%set the parent + \__uftag_prop_gput:cnx + { g__uftag_struct_\int_eval:n {\c@g__uftag_struct_abs_int}_prop } + { P } + { + \prop_item:cn { g__uftag_struct_\l__uftag_struct_stack_parent_tmp_tl _prop} { objnum }~0~R + } + %record this structure as kid: + %\tl_show:N \g__uftag_struct_stack_current_tl + %\tl_show:N \l__uftag_struct_stack_parent_tmp_tl + \__uftag_struct_kid_struct_gput_right:nn + { \l__uftag_struct_stack_parent_tmp_tl } + { \g__uftag_struct_stack_current_tl } + %\prop_show:c { g__uftag_struct_\g__uftag_struct_stack_current_tl _prop } + %\seq_show:c {g__uftag_struct_kids_\l__uftag_struct_stack_parent_tmp_tl _seq} + } + %\prop_show:c { g__uftag_struct_\g__uftag_struct_stack_current_tl _prop } + %\seq_show:c {g__uftag_struct_kids_\l__uftag_struct_stack_parent_tmp_tl _seq} + \group_end: + } + +\cs_new:Nn \uftag_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__uftag_struct_stack_seq + \seq_gpop:NNTF \g__uftag_struct_stack_seq \l_tmpa_tl + { + \__uftag_check_info_closing_struct:o { \g__uftag_struct_stack_current_tl } + } + { \__uftag_check_no_open_struck: } + % get the previous one, shouldn't be empty as the root should be there + \seq_get:NNTF \g__uftag_struct_stack_seq \l_tmpa_tl + { + \tl_gset:NV \g__uftag_struct_stack_current_tl \l_tmpa_tl + } + { + \__uftag_check_no_open_struck: + } + } + +\cs_new:Nn \uftag_struct_use:n %#1 is the label + { + \prop_if_exist:cTF + { g__uftag_struct_\zref@extractdefault{tagpdfstruct-#1}{tagstruct}{unknown}_prop } + { + \__uftag_check_struct_used:n {#1} + %add the label structure as kid to the current structure (can be the root) + \__uftag_struct_kid_struct_gput_right:nn + { \g__uftag_struct_stack_current_tl } + { \zref@extractdefault{tagpdfstruct-#1}{tagstruct}{0} } + %add the current structure to the labeled one as parents + \__uftag_prop_gput:cnx + { g__uftag_struct_\zref@extractdefault{tagpdfstruct-#1}{tagstruct}{0}_prop } + { P } + { + \prop_item:cn { g__uftag_struct_\g__uftag_struct_stack_current_tl _prop} { objnum }~0~R + } + } + {\msg_warning:nnn{tagpdf}{struct-label-unknown}{#1}} + } + +\endinput |