From eef245751e7d3cec3ce8db3dda9f93818e1a7118 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 5 Jul 2018 21:45:46 +0000 Subject: tagpdf (5jul18) git-svn-id: svn://tug.org/texlive/trunk@48146 c570f23f-e606-0410-a88d-b1316a301751 --- .../tex/latex/tagpdf/tagpdf-checks-code.sty | 177 ++++++++ .../texmf-dist/tex/latex/tagpdf/tagpdf-luatex.def | 184 ++++++++ .../tex/latex/tagpdf/tagpdf-mc-code-generic.sty | 223 ++++++++++ .../tex/latex/tagpdf/tagpdf-mc-code-lua.sty | 172 ++++++++ .../tex/latex/tagpdf/tagpdf-mc-code-shared.sty | 57 +++ .../texmf-dist/tex/latex/tagpdf/tagpdf-pdftex.def | 125 ++++++ .../tex/latex/tagpdf/tagpdf-roles-code.sty | 126 ++++++ .../tex/latex/tagpdf/tagpdf-struct-code.sty | 398 +++++++++++++++++ .../tex/latex/tagpdf/tagpdf-tree-code.sty | 147 +++++++ Master/texmf-dist/tex/latex/tagpdf/tagpdf-user.sty | 88 ++++ Master/texmf-dist/tex/latex/tagpdf/tagpdf.lua | 478 +++++++++++++++++++++ Master/texmf-dist/tex/latex/tagpdf/tagpdf.sty | 166 +++++++ 12 files changed, 2341 insertions(+) create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-checks-code.sty create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-luatex.def create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-generic.sty create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-lua.sty create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-shared.sty create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-pdftex.def create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-roles-code.sty create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-struct-code.sty create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-tree-code.sty create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf-user.sty create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf.lua create mode 100644 Master/texmf-dist/tex/latex/tagpdf/tagpdf.sty (limited to 'Master/texmf-dist/tex/latex') diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-checks-code.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-checks-code.sty new file mode 100644 index 00000000000..b1959acc42e --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-checks-code.sty @@ -0,0 +1,177 @@ +\ProvidesExplPackage {tagpdf-checks-code} {2018/07/04} {0.1} + {part of tagpdf - code related to checks and messages} + + +%messages + +% mc +\msg_new:nnn { tagpdf } { mc-nested } { nested~marked~content~found~-~mcid~#1 } +\msg_new:nnn { tagpdf } { mc-tag-missing } { required~tag~missing~-~mcid~#1 } +\msg_new:nnn { tagpdf } { mc-label-unknown }{ label~#1~unknown~-~rerun } +\msg_new:nnn { tagpdf } { mc-used-twice } { mc~#1~has~been~already~used } +\msg_new:nnn { tagpdf } { mc-not-open } { there~is~no~mc~to~end~at~#1 } + +% structures +\msg_new:nnn { tagpdf } { struct-no-objnum } { objnum~missing~for~structure~#1 } +\msg_new:nnn { tagpdf } { struct-faulty-nesting } { there~is~no~open~structure~on~the~stack } +\msg_new:nnn { tagpdf } { struct-missing-tag } { a~structure~must~have~a~tag! } +\msg_new:nnn { tagpdf } { struct-show-closing } { closing~structure~#1~tagged~\prop_item:cn{g__uftag_struct_#1_prop}{S} } +\msg_new:nnn { tagpdf } { struct-used-twice} { structure~with~label~#1~has~already~been~used} +\msg_new:nnn { tagpdf } { struct-label-unknown} { structure~with~label~#1~is~unknown~rerun} + + +%Roles +\msg_new:nnn { tagpdf } { role-missing } { tag~#1~has~no~role~assigned } +\msg_new:nnn { tagpdf } { role-unknown } { role~#1~is~not~known } +\msg_new:nnn { tagpdf } { role-unknown-tag } { tag~#1~is~not~known } +\msg_new:nnn { tagpdf } { role-new-tag } { adding~new~tag~#1~mapped~to~role~#2 } + + +% trees +\msg_new:nnn { tagpdf } {tree-mcid-index-wrong } {something~is~wrong~with~the~mcid} + +% obj +\msg_new:nnn { tagpdf } {obj-write-num } {write~obj~#1~to~pdf} + + +%checks +%structures + +\cs_new:Nn \__uftag_check_structure_has_tag:n %#1 struct num + { + \prop_if_in:cnF { g__uftag_struct_#1_prop } + {S} + { + \msg_error:nn { tagpdf }{ struct-missing-tag } + } + } + +\cs_new:Nn \__uftag_check_info_closing_struct:n %#1 struct num + { + \msg_info:nnn {tagpdf}{struct-show-closing}{#1} + } + +\cs_generate_variant:Nn \__uftag_check_info_closing_struct:n {o,x} + +\cs_new:Nn \__uftag_check_no_open_struck: + { + \msg_error:nn {tagpdf}{ struct-faulty-nesting } + } + +\cs_new:Nn \__uftag_check_struct_used:n %#1 label + { + \prop_get:cnNT + {g__uftag_struct_\zref@extractdefault{tagpdfstruct-#1}{tagstruct}{unknown}_prop} + {P} + \l_tmpa_tl + {\msg_warning:nnn {tagpdf}{struct-used-twice}{#1}} + } + +%roles + +\cs_new:Nn \__uftag_check_add_tag_role:nn %#1 tag, #2 role + { + \tl_if_empty:nTF { #2 } + { + \msg_warning:nnn { tagpdf }{ role-missing } { #1 } + } + { + \prop_get:NnNF \g__uftag_role_tags_prop { #2 } \l_tmpa_tl + { + \msg_warning:nnn { tagpdf }{ role-unknown } { #2 } + } + { + \msg_info:nnnn { tagpdf }{ role-new-tag } { #1 }{ #2 } + } + } + } + +%mc +\cs_new:Nn \__uftag_check_mc_if_nested: + { + \_uftag_mc_if_in:T + { + \msg_warning:nnx {tagpdf}{mc-nested}{ \__uftag_get_mc_abs_cnt: } + } + } + +\cs_new:Nn \__uftag_check_mc_if_open: + { + \_uftag_mc_if_in:F + { + \msg_warning:nnx {tagpdf}{mc-not-open}{ \__uftag_get_mc_abs_cnt: } + } + } + +\cs_new:Nn \__uftag_check_mc_tag:N + { + \tl_if_empty:NT #1 + { + \msg_error:nnx {tagpdf}{mc-tag-missing}{ \__uftag_get_mc_abs_cnt: } + } + \prop_if_in:NoF \g__uftag_role_tags_prop { #1 } + { + \msg_warning:nnx {tagpdf}{role-unknown-tag} { #1 } + } + } + +\seq_new:N \g__uftag_check_mc_used_seq +\cs_new:Nn \__uftag_check_mc_used:n + { + \seq_if_in:NnTF \g__uftag_check_mc_used_seq { #1 } + { + \msg_warning:nnn {tagpdf}{mc-used-twice}{ #1 } + } + { + \seq_gput_right:Nx\g__uftag_check_mc_used_seq { #1 } + } + } + + + +\cs_new:Nn \__uftag_check_show_MCID_by_page: + { + \tl_set:Nx \l__uftag_tmpa_tl + { + \zref@extractdefault + {LastPage} {abspage} {-1} + } + \int_step_inline:nnnn {1}{1} + { + \l__uftag_tmpa_tl + } + { + \seq_clear:N \l_tmpa_seq + \int_step_inline:nnnn {1}{1} + { + \zref@extractdefault + {LastPage} {tagmcabs} {-1} + } + { + \int_compare:nT + { + \zref@extractdefault + {mcid-####1} {tagabspage} {-1} + = ##1 + } + { + \seq_gput_right:Nx \l_tmpa_seq + { + Page##1-####1-\zref@extractdefault + {mcid-####1} {tagmcid} {-1} + } + } + } + \seq_show:N \l_tmpa_seq + } + } + +\cs_new:Nn\__uftag_check_record_pdfobj_num:n + { + \int_compare:nT {\l__uftag_loglevel_int >= 3 } + { + \msg_info:nnx { tagpdf }{obj-write-num}{#1} + } + } + +\endinput diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-luatex.def b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-luatex.def new file mode 100644 index 00000000000..3cff65569c1 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-luatex.def @@ -0,0 +1,184 @@ +\ProvidesExplFile {tagpdf-luatex.def} {2018/07/04} {0.1} + {tagpdf driver for luatex} + +\newattribute \g__uftag_mc_type_attr %the value represent the type +\newattribute \g__uftag_mc_cnt_attr %will hold the \c@g__uftag_MCID_abs_int value + +% The lua code +\directlua { tagpdf=require('tagpdf.lua') } + +%%%% driver (lualatex) commands +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\cs_new:Nn \__uftag_pdfliteral_page:n {\__uftag_tex_pdfextension:D literal~page {#1}} +\cs_new:Nn \__uftag_pdfcatalog:n {\__uftag_tex_pdfextension:D catalog {#1}} + +%reserve an object num +\cs_new:Nn \__uftag_pdfreserveobjnum:N + { + % #1 = macro name to be populated with object number + \__uftag_tex_pdfextension:D~obj~reserveobjnum + \tl_set:Nx #1 { \__uftag_tex_pdffeedback:D lastobj }% + } + +% use an object num +\cs_new:Nn \__uftag_pdfuseobjnum:Nn + { + % #1 = macro with object number to be populated + % #2 = object contents, as valid PDF + % should #2 be filtered through \pdfstringdef ??? + \__uftag_tex_immediate:D \__uftag_tex_pdfextension:D~obj~useobjnum~#1~{ #2 }% + } + +\cs_new:Nn \__uftag_pdfuseobjnum:nn + { + % #1 = a number + % #2 = object contents, as valid PDF + % should #2 be filtered through \pdfstringdef ??? + \__uftag_tex_immediate:D \__uftag_tex_pdfextension:D~obj~useobjnum~#1~{ #2 }% + } + +% obj num of the dictionary for a page: +% the page count starts by 1 +% pages can referenced before they are actually created +% no error if the page later doesn't exist + +\cs_new:Nn \__uftag_store_pdfpageref:Nn + { + % #1 = macro name to be populated with current page object number + % #2 = number or counter identifying the required page + \tl_set:Nx #1 { \__uftag_tex_pdffeedback:D pageref~#2 }% + } + +% a global version of the command +\cs_new:Nn \__uftag_gstore_pdfpageref:Nn + { + \tl_gset:Nx #1 { \__uftag_tex_pdffeedback:D pageref~#2 }% + } + +\cs_new:Nn \__uftag_pdfobj:Nn + { + % #1 = macro name to refer to this object + % #2 = object contents, as valid PDF + % should #2 be filtered through \pdfstringdef ??? + \__uftag_tex_immediate:D \__uftag_tex_pdfextension:D~obj~{ #2 } + \tl_set:Nx #1 { \__uftag_tex_pdffeedback:D~lastobj }% + } + +% pdfpage**s**attr: for all pages +%% is global needed? Yes. Without it the setting is lost if issued in a group +% +\cs_new:Nn \__uftag_gset_pdfpagesattr:n + { + \__uftag_tex_global:D \__uftag_tex_pdfvariable:D~pagesattr { #1 } + } + +\cs_new:Nn \__uftag_gadd_pdfpagesattr:n + { + \exp_args:No \__uftag_gset_pdfpagesattr:n { \__uftag_tex_the:D \__uftag_tex_pdfvariable:D~pagesattr #1} + } + +% pdfpageattr for one page +% do we need an immediate version?? +\cs_new:Nn \__uftag_gset_pdfpageattr:n + { + \__uftag_tex_global:D \__uftag_tex_pdfvariable:D~pageattr { #1 } + } + +\cs_new:Nn \__uftag_gadd_pdfpageattr:n + { + \exp_args:No \__uftag_gset_pdfpageattr:n { \__uftag_tex_the:D \__uftag_tex_pdfvariable:D~pageattr #1} + } + +\cs_new:Nn \__uftag_get_pdfpageattr:N + { + \tl_set:No #1 { \__uftag_tex_the:D \__uftag_tex_pdfvariable:D~pageattr } + } + + +\cs_new:Nn \__uftag_pdfcompresslevel:n + { + \__uftag_tex_pdfvariable:D compresslevel #1 + } + +\cs_new:Nn \__uftag_pdfobjcompresslevel:n + { + \__uftag_tex_pdfvariable:D objcompresslevel #1 + } + +% I probably want also lua tables +% I put them in the uftag.tables namespaces +% The tables will be named like the variables but without backslash +% To access such a table with a dynamical name create a string and then use +% uftag.tables[string] +% Old code, I'm not quite sure if this was a good idea. Now I have mix of table in +% utftag.tables and uftag.mc/struct. And a lot is probably not needed. + +\cs_new:Nn \__uftag_luatex_get_table_name:Nn + { + \tl_set_rescan:Nnn #1 { \char_set_catcode_ignore:N \\ } { #2 } + } + + +\cs_new:Nn \__uftag_prop_new:N + { + \prop_new:N #1 + \__uftag_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { uftag.tables.\l_tmpa_tl = {} } + } + + +\cs_new:Nn \__uftag_seq_new:N + { + \seq_new:N #1 + \__uftag_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { uftag.tables.\l_tmpa_tl = {} } + } + + +\cs_new:Nn \__uftag_prop_gput:Nnn + { + \prop_gput:Nnn #1 { #2 } { #3 } + \__uftag_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { uftag.tables.\l_tmpa_tl["#2"] = "#3" } + } + + +\cs_new:Nn \__uftag_seq_gput_right:Nn + { + \seq_gput_right:Nn #1 { #2 } + \__uftag_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { table.insert(uftag.tables.\l_tmpa_tl, "#2") } + } + +%Hm not quite sure about the naming + +\cs_new:Npn \__uftag_seq_item:cn #1 #2 + { + \directlua { tex.print(uftag.tables.#1[#2]) } + } + +\cs_new:Npn \__uftag_prop_item:cn #1 #2 + { + \directlua { tex.print(uftag.tables.#1["#2"]) } + } + +%for debugging commands that show both the seq/prop and the lua tables +\cs_new:Nn \__uftag_seq_show:N + { + \seq_show:N #1 + \__uftag_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { uftag.trace.log ("lua~sequence~array~\l_tmpa_tl",1) } + \directlua { uftag.trace.show_seq (uftag.tables.\l_tmpa_tl) } + } + +\cs_new:Nn \__uftag_prop_show:N + { + \prop_show:N #1 + \__uftag_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua {uftag.trace.log ("lua~property~table~\l_tmpa_tl",1) } + \directlua {uftag.trace.show_prop (uftag.tables.\l_tmpa_tl) } + } + + +\endinput diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-generic.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-generic.sty new file mode 100644 index 00000000000..5bdab895e61 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-generic.sty @@ -0,0 +1,223 @@ +\ProvidesExplPackage {tagpdf-mc-code-generic} {2018/07/04} {0.1} + {part of tagpdf - code related to marking chunks - generic mode} + +% for the label system +% tagmcid is the id which should be also in the pdf +% it will be (hopefully) reset by page + +\int_new:N \g__uftag_MCID_tmp_bypage_int +\zref@newprop {tagmcid} [0] { \int_use:N \g__uftag_MCID_tmp_bypage_int } +\zref@addprop {tagpdf} {tagmcid} + +% will hold the current maximum on a page +% it will contain key-value of type "abspagenum=max mcid on this page" +\__uftag_prop_new:N \g__uftag_MCID_byabspage_prop + + +% this are the low level mc command. +% they insert literals and so a are specific to generic mode +% checking if the type is defined will done somewhere else +% #1 is the type/tag +\cs_new:Nn \__uftag_mc_bmc:n + { + \__uftag_pdf_escape_name:Nn\l_uttag_tmpa_tl { #1 } + \__uftag_pdfliteral_page:n + { + /\l_uttag_tmpa_tl\c_space_tl BMC + } + } + +\cs_new:Nn \__uftag_mc_emc: + { + \__uftag_pdfliteral_page:n + { + EMC + } + } + +% #1 tag, #2 properties +% I escape the name. But the dictionary content +% must imho be done at a higher level +\cs_new:Nn \__uftag_mc_bdc:nn + { + \__uftag_pdf_escape_name:Nn\l_uttag_tmpa_tl { #1 } + \__uftag_pdfliteral_page:n + { + /\l_uttag_tmpa_tl\c_space_tl<<#2>>~BDC + } + } + + +% bdc with /MCID + more properties +% we need a ref-label system to ensure that the cnt restarts at 0 on a new page + +\tl_new:N \l__uftag_mc_ref_abspage_tl %will store the abspage value of label +\tl_new:N \l__uftag_mc_tmp_tl + +\cs_new:Nn \__uftag_mc_bdc_mcid:nn + { + \int_gincr:N \c@g__uftag_MCID_abs_int + \tl_set:Nx \l__uftag_mc_ref_abspage_tl + { + \zref@extractdefault %3 args + { + mcid-\int_use:N \c@g__uftag_MCID_abs_int + } + {tagabspage} + {-1} + } + \prop_get:NoNTF + \g__uftag_MCID_byabspage_prop + { + \l__uftag_mc_ref_abspage_tl + } + \l__uftag_mc_tmp_tl + { + %key already present, use value for MCID and add 1 for the next + \int_gset:Nn \g__uftag_MCID_tmp_bypage_int { \l__uftag_mc_tmp_tl } + \__uftag_prop_gput:Nxx + \g__uftag_MCID_byabspage_prop + { \l__uftag_mc_ref_abspage_tl } + { \int_eval:n {\l__uftag_mc_tmp_tl +1} } + } + { + %key not present, set MCID to 0 and insert 1 + \int_gzero:N \g__uftag_MCID_tmp_bypage_int + \__uftag_prop_gput:Nxx + \g__uftag_MCID_byabspage_prop + { \l__uftag_mc_ref_abspage_tl } + {1} + } + \zref@labelbylist + { + mcid-\int_use:N \c@g__uftag_MCID_abs_int + } + {tagpdf} + \__uftag_mc_bdc:nn + { #1 } + { /MCID~\int_eval:n { \g__uftag_MCID_tmp_bypage_int }~#2 } + } + +% only /MCID +\cs_new:Nn \__uftag_mc_bdc_mcid:n + { + \__uftag_mc_bdc_mcid:nn { #1 } {} + } + +%artifact without type +\cs_new:Nn \__uftag_mc_bmc_artifact: + { + \__uftag_mc_bmc:n {Artifact} + } + +%artifact with a type: +\cs_new:Nn \__uftag_mc_bmc_artifact:n + { + \__uftag_mc_bdc:nn {Artifact}{/Type\c_space_tl/#1} + } + +% perhaps later: more properties for artifacts + + +% keyval definitions for the user commands: + +\tl_new:N \l__uftag_mc_key_tag_tl + +%Attention! definitions are different in luamode. +\keys_define:nn { tagpdf / mc } +{ + tag .code:n = % the name (H,P,Span etc + { + \__uftag_pdf_escape_name:Nn \l__uftag_mc_key_tag_tl { #1 } + }, + raw .tl_set:N = \l__uftag_mc_key_properties_tl, + label .tl_set:N = \l__uftag_mc_key_label_tl, + artifact .meta:n = { artifact-bool, artifact-type=#1 }, + artifact .default:n = {notype} +} + +\cs_new:Nn \__uftag_mc_handle_artifact:N %#1 contains the artifact type + { + \tl_if_empty:NTF #1 + { \__uftag_mc_bmc_artifact: } + { \exp_args:No\__uftag_mc_bmc_artifact:n { #1 } } + } + +\cs_new:Nn \__uftag_mc_handle_mcid:nn %#1 tag, #2 properties + { + \__uftag_mc_bdc_mcid:nn { #1 }{ #2 } + } + + +% puts the absolute number of an mcid in the current structure +\cs_new:Nn \__uftag_mc_handle_stash:n %1 mcidnum + { + \__uftag_check_mc_used:n { #1 } + \__uftag_struct_kid_mc_gput_right:nn + { \g__uftag_struct_stack_current_tl } + { #1 } + \prop_gput:Nxx \g__uftag_mc_parenttree_prop + { #1 } + { \g__uftag_struct_stack_current_tl } + } + +\cs_new:Nn \uftag_mc_begin:n + { + \group_begin: + \__uftag_check_mc_if_nested: + \bool_gset_true:N \g__uftag_in_mc_bool + \keys_set:nn { tagpdf / mc }{ #1 } + \bool_if:NTF \l__uftag_mc_artifact_bool + { %handle artifact + \__uftag_mc_handle_artifact:N \l__uftag_mc_artifact_type_tl + } + { %handle mcid type + \__uftag_check_mc_tag:N \l__uftag_mc_key_tag_tl + \__uftag_mc_handle_mcid:nn { \l__uftag_mc_key_tag_tl }{\l__uftag_mc_key_properties_tl} + \tl_if_empty:NF {\l__uftag_mc_key_label_tl} + { + \__uftag_mc_handle_mc_label:n { \l__uftag_mc_key_label_tl } + } + \bool_if:NF \l__uftag_mc_key_stash_bool + { + \__uftag_mc_handle_stash:n { \int_use:N \c@g__uftag_MCID_abs_int } + } + } + \group_end: + } + +\cs_new:Nn\uftag_mc_end: + { + \__uftag_check_mc_if_open: + \bool_gset_false:N \g__uftag_in_mc_bool + \__uftag_mc_emc: + } + +\cs_new:Nn\uftag_mc_use:n %#1: label name + { + \tl_set:Nx \l_tmpa_tl { \zref@extractdefault{tagpdf-#1}{tagmcabs}{} } + \tl_if_empty:NTF\l_tmpa_tl + { + \msg_warning:nnn {tagpdf} {mc-label-unknown} { #1 } + } + { + \prop_gput:Nxx + \g__uftag_mc_parenttree_prop + { + \zref@extractdefault{tagpdf-#1}{tagmcabs}{} + } + { + \g__uftag_struct_stack_current_tl + } + \__uftag_struct_kid_mc_gput_right:nn + { + \g__uftag_struct_stack_current_tl + } + { + \zref@extractdefault{tagpdf-#1}{tagmcabs}{} + } + } + } + + +\endinput diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-lua.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-lua.sty new file mode 100644 index 00000000000..0d8a66b12a1 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-lua.sty @@ -0,0 +1,172 @@ +\ProvidesExplFile {tagpdf-mc-code-lua.sty} {2018/07/04} {0.1} + {tagpdf - mc code only for the luamode } + +%the two attibutes are defined in the driver file. +%it also load the lua (as it can also contain functions needed by generic mode. +%\newattribute \g__uftag_mc_type_attr %the value represent the type +%\newattribute \g__uftag_mc_cnt_attr %will hold the \c@g__uftag_MCID_abs_int value + +%An attribute for the current structure probably doesn't make sense as mc chunks can be used later. +%\newattribute \g__uftag_struct_type_attr %represent the current structure type. Not sure if needed +%\newattribute \g__uftag_struct_cnt_attr %will hold \c@g__uftag_struct_abs_int a cnt + +% handling attribute needs a different system to number the page wise mcid's: +% a tagmcbegin ... tagmcend pair no longer surrounds exactly one mc chunk: it can be split +% at page breaks. We know the included mcid(s) only after the ship out. So for the struct-> mcid mapping we +% need to record struct -> mc-cnt (in \g__uftag_mc_parenttree_prop and/or a lua table +% and at shipout mc-cnt-> {mcid, mcid, ...} (in a table?) +% and when building the trees connect both + +% key definitions are overwritten for luatex to store that data in tables +% the data for the mc are in uftag.mc[absnum] +% the fields of the table are +% tag : the type (a string) +% raw : more properties (string) +% label: a string. Do we need a way to retrieve the num from the label from lua?? +% artifact: the presence indicates an artifact, the value (string) is the type. +% kids: a array of tables {1={kid=num2,page=pagenum1}, 2={kid=num2,page=pagenum2},...}, +% this describes the chunks the mc has been split to by the traversing code +% parent: the number of the structure it is in. Needed to build the parent tree. + +% The main function which wanders through the shipout box to inject the literals. +\AtBeginDocument +{ + \bool_if:NT\g_uftag_active_mc_bool + { + \AtBeginShipout + { + \directlua{uftag.func.mark_shipout ()} + } + } +} + +% the keys +\tl_new:N \l__uftag_mc_key_tag_tl +\tl_new:N \l__uftag_mc_key_label_tl +\tl_new:N \l__uftag_mc_key_properties_tl + +\keys_define:nn { tagpdf / mc } +{ + tag .code:n = % + { + \__uftag_pdf_escape_name:Nn \l__uftag_mc_key_tag_tl { #1 } + \directlua + { + uftag.func.store_mc_data(\__uftag_get_mc_abs_cnt:,"tag","#1") + } + }, + raw .code:n = + { + \tl_set:Nn\l__uftag_mc_key_properties_tl { #1 } + \directlua + { + uftag.func.store_mc_data(\__uftag_get_mc_abs_cnt:,"raw","#1") + } + }, + label .code:n = + { + \tl_set:Nn\l__uftag_mc_key_label_tl { #1 } + \directlua {uftag.func.store_mc_data(\__uftag_get_mc_abs_cnt:,"label","#1")} + }, + __artifact-store .code:n = + { + \directlua {uftag.func.store_mc_data(\__uftag_get_mc_abs_cnt:,"artifact","#1")} + }, + artifact .meta:n = { artifact-bool, artifact-type=#1,__artifact-store=#1, tag=Artifact }, + artifact .default:n = { notype } +} + + +% attributes +% set the mc from a tag name + +\cs_new:Nn \__uftag_mc_lua_gset_mc_type_attr:n % #1 is a tag name + { + \global\setattribute \g__uftag_mc_type_attr { \directlua {uftag.func.output_num_from ("#1") } } + \global\setattribute \g__uftag_mc_cnt_attr { \__uftag_get_mc_abs_cnt: } + } + +\cs_generate_variant:Nn\__uftag_mc_lua_gset_mc_type_attr:n { o } + +\cs_new:Nn \__uftag_mc_lua_gunset_mc_type_attr: + { + \global\unsetattribute \g__uftag_mc_type_attr + \global\unsetattribute \g__uftag_mc_cnt_attr + } + +%This command will in the finish code replace the dummy for a mc by the real mcid kids +\cs_new:Nn \__uftag_mc_insert_mcid_kids:n + { + \directlua {uftag.func.mc_insert_kids (#1) } + } + + +% puts an mcid absolute number in the current structure +\cs_new:Nn \__uftag_mc_handle_stash:n %1 mcidnum + { + \__uftag_check_mc_used:n { #1 } + \seq_gput_right:cn % Don't fill a lua table due to the command in the item, so the kernel command + { g__uftag_struct_kids_\g__uftag_struct_stack_current_tl _seq } + { + \__uftag_mc_insert_mcid_kids:n {#1} + } + \directlua + { + uftag.func.store_struct_mcabs(\g__uftag_struct_stack_current_tl,#1) + } + \prop_gput:Nxx + \g__uftag_mc_parenttree_prop + { #1 } + { \g__uftag_struct_stack_current_tl } + } + +\cs_generate_variant:Nn \__uftag_mc_handle_stash:n { o } + +\cs_new:Nn \uftag_mc_begin:n + { + \group_begin: + \__uftag_check_mc_if_nested: + \bool_gset_true:N \g__uftag_in_mc_bool + \int_gincr:N \c@g__uftag_MCID_abs_int + \keys_set:nn { tagpdf / mc }{ label={}, #1 } + %check that a tag or artifact has been used + \__uftag_check_mc_tag:N \l__uftag_mc_key_tag_tl + %set the attributes (is done globally!): + \__uftag_mc_lua_gset_mc_type_attr:o { \l__uftag_mc_key_tag_tl } + \bool_if:NF \l__uftag_mc_artifact_bool + { % store the absolute num name in a label: + \tl_if_empty:NF {\l__uftag_mc_key_label_tl} + { + \__uftag_mc_handle_mc_label:n { \l__uftag_mc_key_label_tl } + } + % if not stashed record the absolute number + \bool_if:NF \l__uftag_mc_key_stash_bool + { + \exp_args:Nx \__uftag_mc_handle_stash:n { \__uftag_get_mc_abs_cnt: } + } + } + \group_end: + } + +\cs_new:Nn\uftag_mc_end: + { + \__uftag_check_mc_if_open: + \bool_gset_false:N \g__uftag_in_mc_bool + \__uftag_mc_lua_gunset_mc_type_attr: + } + +\cs_new:Nn\uftag_mc_use:n %#1: label name + { + \tl_set:Nx \l_tmpa_tl { \zref@extractdefault{tagpdf-#1}{tagmcabs}{} } + \tl_if_empty:NTF\l_tmpa_tl + { + \msg_warning:nnn {tagpdf} {mc-label-unknown} { #1 } + } + { + \__uftag_mc_handle_stash:o { \l_tmpa_tl } + } + } + + + +\endinput diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-shared.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-shared.sty new file mode 100644 index 00000000000..006014432c2 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-mc-code-shared.sty @@ -0,0 +1,57 @@ +\ProvidesExplPackage {tagpdf-mc-code-shared} {2018/07/04} {0.1} + {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 +% \cl@@ckpt and restored e.g. in tabulars and align +% \int_new:N \c@g__uftag_MCID_int and +% \tl_put_right:Nn\cl@@ckpt{\@elt{g_uf_test_int}} +% would work too, but as the name is not expl3 then too, why bother? +% the absolute counter can be used to label and to check if the page +% counter needs a reset. + +\newcounter { g__uftag_MCID_abs_int } +\cs_new:Nn \__uftag_get_mc_abs_cnt: { \int_use:N \c@g__uftag_MCID_abs_int } + +% tagmcabs is the label name of the absolute count which is used to identify the chunk +\zref@newprop {tagmcabs} [0] { \int_use:N \c@g__uftag_MCID_abs_int } +\zref@addprop {tagpdf} {tagmcabs} +\zref@addprop {LastPage} {tagmcabs} + +%stores labels of mcid. +\cs_new:Nn \__uftag_mc_handle_mc_label:n + { + \zref@labelbylist{tagpdf-#1}{tagpdf} + } + +% will hold the structure numbers for the parenttree +% key: absolute number of the mc (tagmcabs) +% value: the structure number the mc is in +\__uftag_prop_new:N \g__uftag_mc_parenttree_prop + +%to test nesting mc: +\bool_new:N \g__uftag_in_mc_bool + +\prg_new_conditional:Nnn \_uftag_mc_if_in: {p,T,F,TF} + { + \bool_if:NTF \g__uftag_in_mc_bool + { \prg_return_true: } + { \prg_return_false: } + } + +%shared keys +%the rest are in the splitted code +\tl_new:N \l__uftag_mc_artifact_type_tl + +\keys_define:nn { tagpdf / mc } + { + stash .bool_set:N = \l__uftag_mc_key_stash_bool, + artifact-bool .bool_set:N = \l__uftag_mc_artifact_bool, + artifact-type .choice:, + artifact-type / pagination .code:n = {\tl_set:Nn \l__uftag_mc_artifact_type_tl { Pagination }}, + artifact-type / layout .code:n = {\tl_set:Nn \l__uftag_mc_artifact_type_tl { Layout }}, + artifact-type / page .code:n = {\tl_set:Nn \l__uftag_mc_artifact_type_tl { Page }}, + artifact-type / background .code:n = {\tl_set:Nn \l__uftag_mc_artifact_type_tl { Background }}, + artifact-type / notype .code:n = {\tl_set:Nn \l__uftag_mc_artifact_type_tl {}}, + } + +\endinput diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-pdftex.def b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-pdftex.def new file mode 100644 index 00000000000..af728c69d90 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-pdftex.def @@ -0,0 +1,125 @@ +\ProvidesExplFile {tagpdf-pdftex.def} {2018/07/04} {0.1} + {tagpdf driver for pdftex} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% driver (pdflatex) commands +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%literal +\cs_new:Nn \__uftag_pdfliteral_page:n { \__uftag_tex_pdfliteral:D page { #1} } +\cs_new:Nn \__uftag_pdfcatalog:n { \__uftag_tex_pdfcatalog:D { #1 } } + +% reserve an object num and store the number +\cs_new:Nn \__uftag_pdfreserveobjnum:N % #1 = macro name to be populated with object number + { + \__uftag_tex_pdfobj:D reserveobjnum + \tl_set:Nx #1 { \int_use:N \__uftag_tex_pdflastobj:D }% + } + +% add content to an object num stored in a macro +\cs_new:Nn \__uftag_pdfuseobjnum:Nn + { + % #1 = macro containing the object number + % #2 = object contents, as valid PDF + % should #2 be filtered through \pdfstringdef ??? + \__uftag_tex_immediate:D \__uftag_tex_pdfobj:D useobjnum~#1~{#2}% + } + +\cs_new:Nn \__uftag_pdfuseobjnum:nn + { + % #1 = a number the object number + % #2 = object contents, as valid PDF + % should #2 be filtered through \pdfstringdef ??? + \__uftag_check_record_pdfobj_num:n {#1} + \__uftag_tex_immediate:D \__uftag_tex_pdfobj:D useobjnum~#1~{#2}% + } + +% obj num of the dictionary for a page: +% the page count starts by 1 +% pages can referenced before they are actually created +% no error if the page later doesn't exist +\cs_new:Nn \__uftag_store_pdfpageref:Nn + { + % #1 = macro name to be populated with current page object number + % #2 = number or counter identifying the required page + \tl_set:Nx #1 { \__uftag_tex_pdfpageref:D #2}% + } + +% a global version of the command +\cs_new:Nn \__uftag_gstore_pdfpageref:Nn + { + \tl_gset:Nx #1 { \__uftag_tex_pdfpageref:D #2}% + } + +\cs_new:Nn \__uftag_pdfobj:Nn + { + % #1 = macro name to refer to this object + % #2 = object contents, as valid PDF + % should #2 be filtered through \pdfstringdef ??? + \__uftag_tex_immediate:D \__uftag_tex_pdfobj:D { #2 } + \tl_set:Nx #1 {\int_use:N \__uftag_tex_pdflastobj:D }% + } + +% pdfpage**s**attr: for all pages +%% is global needed? Yes. Without it the setting is lost if issued in a group +% +\cs_new:Nn \__uftag_gset_pdfpagesattr:n + { + \__uftag_tex_global:D \__uftag_tex_pdfpagesattr:D { #1 } + } + +\cs_new:Nn \__uftag_gadd_pdfpagesattr:n + { + \exp_args:No \__uftag_gset_pdfpagesattr:n { \__uftag_tex_the:D \__uftag_tex_pdfpagesattr:D #1 } + } + +% pdfpageattr for one page +% I must avoid to overwrite other entries, +% And I must avoid to add more and more /StructParens +% do we need an immediate version?? +\cs_new:Nn \__uftag_gset_pdfpageattr:n + { + \__uftag_tex_global:D \__uftag_tex_pdfpageattr:D { #1 } + } + +\cs_new:Nn \__uftag_gadd_pdfpageattr:n + { + \exp_args:No \__uftag_gset_pdfpageattr:n { \__uftag_tex_the:D \__uftag_tex_pdfpageattr:D #1} + } + +\cs_new:Nn \__uftag_get_pdfpageattr:N + { + \tl_set:No #1 { \__uftag_tex_the:D \__uftag_tex_pdfpageattr:D } + } +\cs_new:Nn \__uftag_pdfcompresslevel:n + { + \__uftag_tex_pdfcompresslevel:D #1 + } + +\cs_new:Nn \__uftag_pdfobjcompresslevel:n + { + \__uftag_tex_pdfobjcompresslevel:D #1 + } + + +% These commands are only aliases for pdflatex but are defined differently with luatex +% to get also lua tables. +\cs_set_eq:NN \__uftag_prop_new:N \prop_new:N + +\cs_set_eq:NN \__uftag_seq_new:N \seq_new:N + +\cs_set_eq:NN \__uftag_prop_gput:Nnn \prop_gput:Nnn + +\cs_set_eq:NN \__uftag_seq_gput_right:Nn \seq_gput_right:Nn + +\cs_set_eq:NN \__uftag_seq_item:cn \seq_item:cn + +\cs_set_eq:NN \__uftag_prop_item:cn \prop_item:cn + +\cs_set_eq:NN \__uftag_seq_show:N \seq_show:N + +\cs_set_eq:NN \__uftag_prop_show:N \prop_show:N + + + +\endinput diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-roles-code.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-roles-code.sty new file mode 100644 index 00000000000..06489c6ea8c --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-roles-code.sty @@ -0,0 +1,126 @@ +\ProvidesExplPackage {tagpdf-roles-code} {2018/07/04} {0.1} + {part of tagpdf - code related to roles and structure names} + +\__uftag_seq_new:N \g__uftag_role_tags_seq %to get names from numbers +\__uftag_prop_new:N \g__uftag_role_tags_prop %to get numbers from names + +%The list of standard adobe tags. +\clist_const:Nn \c__uftag_role_sttags_clist + {%possible root elements + 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, + H1, + H2, + H3, + H4, + H5, + H6, + P, + L, %list + LI, %list item (around label and list item body) + Lbl, %list label + Lbody, %list item body + Table, + TR, %table row + TH, %table header cell + TD, %table data cell + THead, %table header (n rows) + 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 + } + +% get tag name from number: \seq_item:Nn \g__uftag_role_tags_seq { n } +%\seq_gset_from_clist:NN \g__uftag_role_tags_seq \c__uftag_role_tags_clist + +\clist_map_inline:Nn \c__uftag_role_sttags_clist + { + \__uftag_seq_gput_right:Nn \g__uftag_role_tags_seq { #1 } + } + + +% get tag number from name: \prop_item:Nn \g__uftag_role_tags_prop { name } +\int_step_inline:nnnn { 1 }{ 1 }{ \seq_count:N \g__uftag_role_tags_seq } + { + \__uftag_prop_gput:Nxn \g__uftag_role_tags_prop + { + \seq_item:Nn \g__uftag_role_tags_seq { #1 } + } + { #1 } + } + +\cs_new:Nn \__uftag_role_get_tag_from_index:nn + { + \__uftag_seq_item:cn { #1_seq } { #2 } + } + +\cs_new:Nn \__uftag_role_get_index_from_tag:nn + { + \__uftag_prop_item:cn { #1_prop } { #2 } + } + +% new tags and the rolemap + +\__uftag_prop_new:N \g__uftag_role_rolemap_prop + +\cs_new:Nn \__uftag_role_add_tag:nn %new name, reference to old + { + \__uftag_seq_gput_right:Nn \g__uftag_role_tags_seq { #1 } + \__uftag_prop_gput:Nnx \g__uftag_role_tags_prop { #1 } + { + \seq_count:N \g__uftag_role_tags_seq + } + \__uftag_check_add_tag_role:nn {#1}{#2} + \tl_if_empty:nF { #2 } + { + \__uftag_prop_gput:Nnn \g__uftag_role_rolemap_prop + { #1 } { #2 } + } + } + +\cs_generate_variant:Nn \__uftag_role_add_tag:nn {xx} + +\keys_define:nn { tagpdf-setup } + { + add-new-tag .code:n = + { + \seq_set_split:Nnn \l_tmpa_seq { / } {#1/} + \__uftag_role_add_tag:xx + { + \seq_item:Nn \l_tmpa_seq {1} + } + { + \seq_item:Nn \l_tmpa_seq {2} + } + } + } + + +\endinput 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 {} + }, +} + + +\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 diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-tree-code.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-tree-code.sty new file mode 100644 index 00000000000..751c26974d2 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-tree-code.sty @@ -0,0 +1,147 @@ +\ProvidesExplPackage {tagpdf-tree-code} {2018/07/04} {0.1} + {part of tagpdf - code related to writing trees and dictionaries to the pdf} + +%this does the actual finishing: +\AtBeginDocument +{ + \bool_if:NT \g_uftag_active_tree_bool + { + \AfterEndDocument { \uftag_finish_structure: } + } +} + + +% the StructTreeRoot +% we better get the object number in any case: +\__uftag_pdfreserveobjnum:N \l_tmpa_tl +\tl_const:Nx \c_uftag_tree_obj_structtreeroot_tl { \l_tmpa_tl } + + +\cs_new:Nn \__uftag_tree_write_structtreeroot: +{ + \__uftag_pdfcatalog:n { /StructTreeRoot~\c_uftag_tree_obj_structtreeroot_tl\c_space_tl0~R } + \__uftag_struct_write_obj:n { 0 } +} + +\cs_new:Nn \__uftag_tree_write_structelements: + { + \int_step_inline:nnnn {1}{1}{\c@g__uftag_struct_abs_int} + { + %\prop_show:c {g__uftag_struct_##1_prop} + \__uftag_struct_write_obj:n { ##1 } %write the object + } + } + + +%the ParentTree +\__uftag_pdfreserveobjnum:N \l_tmpa_tl +\tl_const:Nx \c__uftag_tree_obj_parenttree_tl { \l_tmpa_tl } +\tl_new:N \l__uftag_parenttree_content_tl + +\cs_new:Nn \__uftag_tree_fill_parenttree: +{ + \int_step_inline:nnnn{1}{1}{\zref@extractdefault{LastPage}{abspage}{-1}} %not quite clear if labels are needed. See lua code + { %page ##1\par + \prop_clear:N \l_tmpa_prop + \int_step_inline:nnnn{1}{1}{\zref@extractdefault{LastPage}{tagmcabs}{-1}} + { + %mcid####1 + \int_compare:nT%F + {\zref@extractdefault{mcid-####1}{tagabspage}{-1}=##1} %mcid is on current page + {% yes\par + \prop_put:Nxx \l_tmpa_prop + {\zref@extractdefault{mcid-####1}{tagmcid}{-1}} + {\prop_item:Nn \g__uftag_mc_parenttree_prop {####1}} + } + } + %\prop_show:N \l_tmpa_prop + \tl_put_right:Nx\l__uftag_parenttree_content_tl + {\int_eval:n {##1-1}\c_space_tl[\c_space_tl} %%brackt + \int_step_inline:nnnn {0}{1}{ \prop_map_function:NN \l_tmpa_prop\__uftag_prop_count:nn -1 } + { + \prop_get:NnNTF \l_tmpa_prop {####1} \l_tmpb_tl + {% page#1:mcid##1:\l_tmpb_tl :content + \tl_put_right:Nx \l__uftag_parenttree_content_tl + { + \prop_item:cn { g__uftag_struct_\l_tmpb_tl _prop } {objnum}~0~R~ + } + } + {\msg_warning:nn {tagpdf} {tree-mcid-index-wrong} } + } + \tl_put_right:Nn\l__uftag_parenttree_content_tl{]^^J} % + } +} + +%lua mode must/can do it differently +\cs_new:Nn \__uftag_tree_lua_fill_parenttree: + { + \tl_set:Nn\l__uftag_parenttree_content_tl + { + \directlua{uftag.func.output_parenttree(\int_use:N\g__uftag_abspage_int)} + } + } + + + +\cs_new:Nn \__uftag_tree_write_parenttree: + { + \bool_if:NTF \g__uftag_mode_lua_bool + { + \__uftag_tree_lua_fill_parenttree: + } + { + \__uftag_tree_fill_parenttree: + } + \__uftag_pdfuseobjnum:xx { \c__uftag_tree_obj_parenttree_tl } + { + <<\c_space_tl/Nums\c_space_tl [\l__uftag_parenttree_content_tl] \c_space_tl >> + } + } + +%the Rolemap tree +\__uftag_pdfreserveobjnum:N \l_tmpa_tl +\tl_const:Nx \c__uftag_tree_obj_rolemap_tl { \l_tmpa_tl } +\tl_new:N \l__uftag_rolemap_content_tl + +\cs_new:Nn \__uftag_tree_fill_rolemap: + { + \prop_map_inline:Nn \g__uftag_role_rolemap_prop + { + \tl_put_right:Nx \l__uftag_rolemap_content_tl + { + /##1\c_space_tl/##2^^J + } + } + } + +\cs_new:Nn \__uftag_tree_write_rolemap: + { + \__uftag_tree_fill_rolemap: + \__uftag_pdfuseobjnum:xx { \c__uftag_tree_obj_rolemap_tl } + { + <<\l__uftag_rolemap_content_tl >> + } + } + +\cs_new:Nn \uftag_finish_structure: + { + \__uftag_pdfcatalog:n {^^J/MarkInfo\c_space_tl<> } + \__uftag_tree_write_parenttree: + \__uftag_tree_write_rolemap: + \__uftag_tree_write_structelements: + \__uftag_tree_write_structtreeroot: + } + + +%StructParents + tabs order. Tabs order should be probably be changeable by page. + +\cs_new:Nn \__uftag_tree_write_pageattr: +{ + \__uftag_get_pdfpageattr:N \l_tmpa_tl + \regex_replace_once:nnN {/StructParents\s*\d+} {}\l_tmpa_tl + \regex_replace_once:nnN {/Tabs\s*/[SCR]} {}\l_tmpa_tl + \__uftag_gset_pdfpageattr:x + {\l_tmpa_tl/StructParents\c_space_tl \int_eval:n{\g__uftag_abspage_int }\l__uftag_tree_tabs_order_tl} +} + +\endinput diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf-user.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-user.sty new file mode 100644 index 00000000000..084c0f36030 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf-user.sty @@ -0,0 +1,88 @@ +\ProvidesExplFile {tagpdf-user.sty} {2018/07/04} {0.1} + {tagpdf - user commands} + +\NewDocumentCommand \tagpdfsetup { m } + { + \keys_set:nn { tagpdf-setup } { #1 } + } + +\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 + +%%%% mc related user commands +\NewDocumentCommand \tagmcifinTF { m m } + { + \_uftag_mc_if_in:TF { #1 } { #2 } + } + +\NewDocumentCommand \tagmcbegin { m } + { + \uftag_mc_begin:n {#1}\ignorespaces + } + + +\NewDocumentCommand \tagmcend { } + { + \unskip\uftag_mc_end: + } + +\NewDocumentCommand \tagmcuse { m } + { + \uftag_mc_use:n {#1} + } + + +%%%% structure related commands + +\NewDocumentCommand \tagstructbegin { m } + { + \uftag_struct_begin:n {#1} + } + +\NewDocumentCommand \tagstructend { } + { + \uftag_struct_end: + } + +\NewDocumentCommand \tagstructuse { m } + { + \uftag_struct_use:n {#1} + } + + + +%%%% debug/show commands +\NewDocumentCommand\showtagpdfmcdata { O {\__uftag_get_mc_abs_cnt:} } +{ + \bool_if:NT \g__uftag_mode_lua_bool + { + \sys_if_engine_luatex:T + { + \directlua{uftag.trace.show_all_mc_data(#1)} + } + } +} + +\NewDocumentCommand\showtagpdfattributes { } +{ + \bool_if:NT \g__uftag_mode_lua_bool + { + \sys_if_engine_luatex:T + { + \directlua + { + uftag.trace.log( + "showtagpdfattributes: MC=>abscnt=\__uftag_get_mc_abs_cnt:=>attr=\the\g__uftag_mc_cnt_attr=>tag=" .. + tostring(uftag.func.get_tag_from (\the\g__uftag_mc_type_attr)) .. + "=\the\g__uftag_mc_type_attr",0 + ) + } + \ignorespaces + } + } +} + + + +\endinput diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf.lua b/Master/texmf-dist/tex/latex/tagpdf/tagpdf.lua new file mode 100644 index 00000000000..4c0c6678d7d --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf.lua @@ -0,0 +1,478 @@ +-- Packageversion: 0.1 +-- Packagedate: 2018/07/04 +-- tagpdf.lua +-- Ulrike Fischer + +--[[ +The code has quite probably a number of problems + - more variables should be local instead of global + - the naming is not always consistent due to the development of the code + - the traversing of the shipout box must be tested with more complicated setups + - it should probably handle more node types + - +--]] + + + +--[[ +the main table is named uftag. It contains the functions and also the data +collected during the compilation. + +uftag.mc will contain mc connected data. +uftag.struct will contain structure related data. +uftag.page will contain page data +uftag.tables contains also data from mc and struct (from older code). This needs cleaning up. + There are certainly dublettes, but I don't dare yet ... +uftag.func will contain (public) functions. +uftag.trace will contain tracing/loging functions. +local funktions starts with __ + +functions + uftag.func.get_num_from (tag): takes a tag (string) and returns the id number + uftag.func.output_num_from (tag): takes a tag (string) and prints (to tex) the id number + uftag.func.get_tag_from (num): takes a num and returns the tag + uftag.func.output_tag_from (num): takes a num and prints (to tex) the tag + uftag.func.store_mc_data (num,key,data): stores key=data in uftag.mc[num] + uftag.func.store_mc_label (label,num): stores label=num in uftag.mc.labels + uftag.func.store_mc_kid (mcnum,kid,page): stores the mc-kids of mcnum on page page + uftag.func.store_mc_in_page(mcnum,mcpagecnt,page): stores in the page table the number of mcnum on this page + uftag.func.store_struct_mcabs (structnum,mcnum): stores relations structnum<->mcnum (abs) + uftag.func.mc_insert_kids (mcnum): inserts the /K entries for mcnum by wandering throught the [kids] table + uftag.func.mark_page_elements(box,mcpagecnt,mccntprev,mcopen,name,mctypeprev) : the main function + uftag.func.mark_shipout (): a wrapper around the core function which inserts the last EMC + uftag.func.fill_parent_tree_line (page): outputs the entries of the parenttree for this page + uftag.func.output_parenttree(): outputs the content of the parenttree + uftag.trace.show_mc_data (num): shows uftag.mc[num] + uftag.trace.show_all_mc_data (max): shows a maximum about mc's + uftag.trace.show_seq: shows a sequence (array) + uftag.trace.show_struct_data (num): shows data of structure num + uftag.trace.show_prop: shows a prop + uftag.trace.log +--]] + +local mctypeattributeid = luatexbase.registernumber ("g__uftag_mc_type_attr") +local mccntattributeid = luatexbase.registernumber ("g__uftag_mc_cnt_attr") + +local catlatex = luatexbase.registernumber("catcodetable@latex") +local tagunmarkedbool= token.create("g__uftag_tagunmarked_bool") +local truebool = token.create("c_true_bool") + +local tableinsert = table.insert + +-- not all needed, copied from lua-visual-debug. +local nodeid = node.id +local nodecopy = node.copy +local nodegetattribute = node.get_attribute +local nodenew = node.new +local nodetail = node.tail +local nodeslide = node.slide +local noderemove = node.remove +local nodetraverseid = node.traverse_id +local nodeinsertafter = node.insert_after +local nodeinsertbefore = node.insert_before +local pdfpageref = pdf.pageref + +local HLIST = node.id("hlist") +local VLIST = node.id("vlist") +local RULE = node.id("rule") +local DISC = node.id("disc") +local GLUE = node.id("glue") +local KERN = node.id("kern") +local PENALTY = node.id("penalty") +local LOCAL_PAR = node.id("local_par") +local MATH = node.id("math") + +local function __uftag_get_mathsubtype (mathnode) + if mathnode.subtype == 0 then + subtype = "beginmath" + else + subtype = "endmath" + end + return subtype +end + + + +uftag = uftag or { } +uftag.mc = uftag.mc or { } -- mc data +uftag.struct = uftag.struct or { } -- struct data +uftag.tables = uftag.tables or { } -- tables created with new prop and new seq. + -- wasn't a so great idea ... +uftag.page = uftag.page or { } -- page data, currently only i->{0->mcnum,1->mcnum,...} +uftag.trace = uftag.trace or { } -- show commands +uftag.func = uftag.func or { } -- functions +uftag.conf = uftag.conf or { } -- configuration variables + +local __uftag_log = + function (message,loglevel) + if (loglevel or 3) <= tex.count["l__uftag_loglevel_int"] then + texio.write_nl("tagpdf: ".. message) + end + end + +uftag.trace.log = __uftag_log + + +local __uftag_get_mc_cnt_type_tag = function (n) + local mccnt = nodegetattribute(n,mccntattributeid) or -1 + local mctype = nodegetattribute(n,mctypeattributeid) or -1 + local tag = uftag.func.get_tag_from(mctype) + return mccnt,mctype,tag +end + + +local function __uftag_insert_emc_node (head,current) + local emcnode = nodenew("whatsit","pdf_literal") + emcnode.data = "EMC" + emcnode.mode=1 + head = node.insert_before(head,current,emcnode) + return head +end + + +local function __uftag_insert_bmc_node (head,current,tag) + local bmcnode = nodenew("whatsit","pdf_literal") + bmcnode.data = "/"..tag.." BMC" + bmcnode.mode=1 + head = node.insert_before(head,current,bmcnode) + return head +end + +local function __uftag_insert_bdc_node (head,current,tag,dict) + local bdcnode = nodenew("whatsit","pdf_literal") + bdcnode.data = "/"..tag.."<<"..dict..">> BDC" + bdcnode.mode=1 + head = node.insert_before(head,current,bdcnode) + return head +end + + +--[[ + Now follows the core function + It wades through the shipout box and checks the attributes + ARGUMENTS + box: is a box, + mcpagecnt: num, the current page cnt of mc (should start at -1 in shipout box), needed for recursion + mccntprev: num, the attribute cnt of the previous node/whatever - if different we have a chunk border + mcopen: num, records if some bdc/emc is open + These arguments are only needed for log messages, if not present are replaces by fix strings: + name: string to describe the box + mctypeprev: num, the type attribute of the previous node/whatever + + there are lots of logging messages currently. Should be cleaned up in due course. + One should also find ways to make the function shorter. +--]] + +function uftag.func.mark_page_elements (box,mcpagecnt,mccntprev,mcopen,name,mctypeprev) + local name = name or ("SOMEBOX") + local mctypeprev = mctypeprev or -1 + local abspage = tex.count["g__uftag_abspage_int"] --["c@abspage"] + uftag.trace.log ("PAGE " .. abspage,3) + uftag.trace.log ("FUNC ARGS: pagecnt".. mcpagecnt.." prev "..mccntprev .. " type prev "..mctypeprev,4) + uftag.trace.log ("TRAVERSING BOX ".. tostring(name).." TYPE ".. node.type(node.getid(box)),3) + local head = box.head -- AtBeginShipoutBox is a vlist? + if head then + mccnthead, mctypehead,taghead = __uftag_get_mc_cnt_type_tag (head) + uftag.trace.log ("HEAD " .. node.type(node.getid(head)).. " MC"..tostring(mccnthead).." => TAG "..tostring(mctypehead).." => "..tostring(taghead),3) + else + uftag.trace.log ("HEAD is ".. tostring(head),3) + end + for n in node.traverse(head) do + local mccnt, mctype, tag = __uftag_get_mc_cnt_type_tag (n) + uftag.trace.log ("NODE ".. node.type(node.getid(n)).." MC"..tostring(mccnt).." => TAG "..tostring(mctype).." => " .. tostring(tag),3) + if n.id == HLIST + then -- enter the hlist + mcopen,mcpagecnt,mccntprev,mctypeprev= + uftag.func.mark_page_elements (n,mcpagecnt,mccntprev,mcopen,"INTERNAL HLIST",mctypeprev) + elseif n.id == VLIST then -- enter the vlist + mcopen,mcpagecnt,mccntprev,mctypeprev= + uftag.func.mark_page_elements (n,mcpagecnt,mccntprev,mcopen,"INTERNAL VLIST",mctypeprev) + elseif n.id == GLUE then -- glue is ignored + elseif n.id == LOCAL_PAR then -- local_par is ignored + elseif n.id == PENALTY then -- penalty is ignored + elseif n.id == KERN then -- kern is ignored + else + -- math is currently only logged. + -- we could mark the whole as math + -- for inner processing the mlist_to_hlist callback is probably needed. + if n.id == MATH then + uftag.trace.log("NODE "..node.type(node.getid(n)).." "..__uftag_get_mathsubtype(n),3) + end + -- endmath + uftag.trace.log("CURRENT "..mccnt.." PREV "..mccntprev,3) + if mccnt~=mccntprev then -- a new mc chunk + uftag.trace.log ("NODE ".. node.type(node.getid(n)).." MC"..tostring(mccnt).." <=> PREVIOUS "..tostring(mccntprev),3) + if mcopen~=0 then -- there is a chunk open, close it (hope there is only one ... + box.list=__uftag_insert_emc_node (box.list,n) + mcopen = mcopen - 1 + uftag.trace.log ("INSERT EMC " .. mcpagecnt .. " MCOPEN = " .. mcopen,2) + if mcopen ~=0 then + uftag.trace.log ("!WARNING! open mc" .. " MCOPEN = " .. mcopen,1) + end + end + if uftag.mc[mccnt] then + if uftag.mc[mccnt]["artifact"] then + uftag.trace.log("THIS IS AN ARTIFACT of type "..tostring(uftag.mc[mccnt]["artifact"]),3) + if uftag.mc[mccnt]["artifact"] == "notype" then + box.list = __uftag_insert_bmc_node (box.list,n,"Artifact") + else + box.list = __uftag_insert_bdc_node (box.list,n,"Artifact", "/Type /"..uftag.mc[mccnt]["artifact"]) + end + else + uftag.trace.log("THIS IS A TAG "..tostring(tag),3) + mcpagecnt = mcpagecnt +1 + uftag.trace.log ("INSERT BDC "..mcpagecnt,2) + box.list = __uftag_insert_bdc_node (box.list,n,tag, "/MCID "..mcpagecnt) + uftag.func.store_mc_kid (mccnt,mcpagecnt,abspage) + uftag.func.store_mc_in_page(mccnt,mcpagecnt,abspage) + uftag.trace.show_mc_data (mccnt) + end + mcopen = mcopen + 1 + else + uftag.trace.log("THIS HAS NOT BEEN TAGGED",1) + -- perhaps code that tag a artifact can be added ... + if tagunmarkedbool.mode == truebool.mode then + box.list = __uftag_insert_bmc_node (box.list,n,"Artifact") + end + mcopen = mcopen + 1 + end + mccntprev = mccnt + end + end -- end if + end -- end for + if head then + mccnthead, mctypehead,taghead = __uftag_get_mc_cnt_type_tag (head) + uftag.trace.log ("ENDHEAD " .. node.type(node.getid(head)).. " MC"..tostring(mccnthead).." => TAG "..tostring(mctypehead).." => "..tostring(taghead),3) + else + uftag.trace.log ("ENDHEAD is ".. tostring(head),3) + end + uftag.trace.log ("QUITTING TRAVERSING BOX ".. tostring(name).." TYPE ".. node.type(node.getid(box)),3) + return mcopen,mcpagecnt,mccntprev,mctypeprev +end + +function uftag.func.mark_shipout () + mcopen = uftag.func.mark_page_elements (tex.box["AtBeginShipoutBox"],-1,-100,0,"Shipout",-1) + if mcopen~=0 then -- there is a chunk open, close it (hope there is only one ... + local emcnode = nodenew("whatsit","pdf_literal") + local box = tex.box["AtBeginShipoutBox"].list + emcnode.data = "EMC" + emcnode.mode=1 + if box then + box = node.insert_after (box,node.tail(box),emcnode) + mcopen = mcopen - 1 + uftag.trace.log ("INSERT LAST EMC, MCOPEN = " .. mcopen,2) + else + uftag.trace.log ("UPS ",1) + end + if mcopen ~=0 then + uftag.trace.log ("!WARNING! open mc" .. " MCOPEN = " .. mcopen,1) + end + end +end + +function uftag.trace.show_seq (seq) + if (type(seq) == "table") then + for i,v in ipairs(seq) do + __uftag_log ("[" .. i .. "] => " .. tostring(v),1) + end + else + __uftag_log ("sequence " .. tostring(seq) .. " not found",1) + end +end + +local __uftag_pairs_prop = + function (prop) + local a = {} + for n in pairs(prop) do tableinsert(a, n) end + table.sort(a) + local i = 0 -- iterator variable + local iter = function () -- iterator function + i = i + 1 + if a[i] == nil then return nil + else return a[i], prop[a[i]] + end + end + return iter + end + + +function uftag.trace.show_prop (prop) + if (type(prop) == "table") then + for i,v in __uftag_pairs_prop (prop) do + __uftag_log ("[" .. i .. "] => " .. tostring(v),1) + end + else + __uftag_log ("prop " .. tostring(prop) .. " not found or not a table",1) + end + end + + +local __uftag_get_num_from = + function (tag) + if uftag.tables["g__uftag_role_tags_prop"][tag] then + a= uftag.tables["g__uftag_role_tags_prop"][tag] + else + a= -1 + end + return a + end + +uftag.func.get_num_from = __uftag_get_num_from + +function uftag.func.output_num_from (tag) + local num = __uftag_get_num_from (tag) + tex.sprint(catlatex,num) + if num == -1 then + __uftag_log ("Unknown tag "..tag.." used") + end +end + +local __uftag_get_tag_from = + function (num) + if uftag.tables["g__uftag_role_tags_seq"][num] then + a = uftag.tables["g__uftag_role_tags_seq"][num] + else + a= "UNKNOWN" + end + return a +end + +uftag.func.get_tag_from = __uftag_get_tag_from + +function uftag.func.output_tag_from (num) + tex.sprint(catlatex,__uftag_get_tag_from (num)) +end + +function uftag.func.store_mc_data (num,key,data) + uftag.mc[num] = uftag.mc[num] or { } + uftag.mc[num][key] = data + __uftag_log ("storing mc"..num..": "..tostring(key).."=>"..tostring(data)) +end + +function uftag.trace.show_mc_data (num) + if uftag and uftag.mc and uftag.mc[num] then + for k,v in pairs(uftag.mc[num]) do + __uftag_log ("mc"..num..": "..tostring(k).."=>"..tostring(v),3) + end + if uftag.mc[num]["kids"] then + __uftag_log ("mc" .. num .. " has " .. #uftag.mc[num]["kids"] .. " kids",3) + for k,v in ipairs(uftag.mc[num]["kids"]) do + __uftag_log ("mc ".. num .. " kid "..k.." =>" .. v.kid.." on page " ..v.page,3) + end + end + else + __uftag_log ("mc"..num.." not found",3) + end +end + +function uftag.trace.show_all_mc_data (max) + for i = 1, max do + uftag.trace.show_mc_data (i) + end +end + + +function uftag.func.store_mc_label (label,num) + uftag.mc["labels"] = uftag.mc["labels"] or { } + uftag.mc.labels[label] = num +end + +function uftag.func.store_mc_kid (mcnum,kid,page) + uftag.trace.log("MC"..mcnum.." STORING KID" .. kid.." on page " .. page,3) + uftag.mc[mcnum]["kids"] = uftag.mc[mcnum]["kids"] or { } + local kidtable = {kid=kid,page=page} + tableinsert(uftag.mc[mcnum]["kids"], kidtable ) +end + +function uftag.func.mc_insert_kids (mcnum) + if uftag.mc[mcnum] then + uftag.trace.log("MC-KIDS test " .. mcnum,4) + if uftag.mc[mcnum]["kids"] then + for i,kidstable in ipairs( uftag.mc[mcnum]["kids"] ) do + local kidnum = kidstable["kid"] + local kidpage = kidstable["page"] + local kidpageobjnum = pdfpageref(kidpage) + uftag.trace.log("MC" .. mcnum .. " insert KID " ..i.. " with num " .. kidnum .. " on page " .. kidpage.."/"..kidpageobjnum,3) + tex.sprint(catlatex,"<> " ) + end + else + uftag.trace.log("WARN! MC"..mcnum.." has no kids",0) + end + else + uftag.trace.log("WARN! MC"..mcnum.." doesn't exist",0) + end +end + + +function uftag.func.store_struct_mcabs (structnum,mcnum) + uftag.struct[structnum]=uftag.struct[structnum] or { } + uftag.struct[structnum]["mc"]=uftag.struct[structnum]["mc"] or { } + -- a structure can contain more than on mc chunk, the content should be ordered + tableinsert(uftag.struct[structnum]["mc"],mcnum) + -- but every mc can only be in one structure + uftag.mc[mcnum]= uftag.mc[mcnum] or { } + uftag.mc[mcnum]["parent"] = structnum +end + +function uftag.trace.show_struct_data (num) + if uftag and uftag.struct and uftag.struct[num] then + for k,v in ipairs(uftag.struct[num]) do + __uftag_log ("struct "..num..": "..tostring(k).."=>"..tostring(v)) + end + else + __uftag_log ("struct "..num.." not found ") + end +end + +-- pay attention: lua counts arrays from 1, tex pages from one +-- mcid and arrays in pdf count from 0. +function uftag.func.store_mc_in_page (mcnum,mcpagecnt,page) + uftag.page[page] = uftag.page[page] or {} + uftag.page[page][mcpagecnt] = mcnum + uftag.trace.log("PAGE " .. page .. ": inserting MCID " .. mcpagecnt .. " => " .. mcnum,3) +end + +function uftag.func.fill_parent_tree_line (page) + -- we need to get page-> i=kid -> mcnum -> structnum + -- pay attention: the kid numbers and the page number in the parent tree start with 0! + local numsentry + local pdfpage = page-1 + if uftag.page[page] and uftag.page[page][0] then + mcchunks=#uftag.page[page] + uftag.trace.log("PAGETREE PAGE "..page.." has "..mcchunks.."+1 Elements ",3) + for i=0,mcchunks do + uftag.trace.log("PAGETREE CHUNKS "..uftag.page[page][i],0) + end + if mcchunks == 0 then + -- only one chunk so no need for an array + local mcnum = uftag.page[page][0] + local structnum = uftag.mc[mcnum]["parent"] + local propname = "g__uftag_struct_"..structnum.."_prop" + local objnum = uftag.tables[propname]["objnum"] or "XXXX" + texio.write_nl("=====>"..tostring(objnum)) + numsentry = pdfpage .. " ".. objnum .. " 0 R" + uftag.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3) + else + numsentry = pdfpage .. " [" + for i=0,mcchunks do + local mcnum = uftag.page[page][i] + local structnum = uftag.mc[mcnum]["parent"] + local propname = "g__uftag_struct_"..structnum.."_prop" + local objnum = uftag.tables[propname]["objnum"] or "XXXX" + numsentry = numsentry .. " ".. objnum .. " 0 R" + end + numsentry = numsentry .. "] " + uftag.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3) + end + else + uftag.trace.log ("PAGETREE: NO DATA FOR PAGE "..i,3) + end + return numsentry +end + +function uftag.func.output_parenttree (abspage) + for i=1,abspage do + line = uftag.func.fill_parent_tree_line (i) .. "^^J" + tex.sprint(catlatex,line) + end +end diff --git a/Master/texmf-dist/tex/latex/tagpdf/tagpdf.sty b/Master/texmf-dist/tex/latex/tagpdf/tagpdf.sty new file mode 100644 index 00000000000..a9dc7173783 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tagpdf/tagpdf.sty @@ -0,0 +1,166 @@ +\RequirePackage{expl3}[2018/06/14] + +\ProvidesExplPackage {tagpdf} {2018/07/04} {0.1} + {A package to experiment with pdf tagging} + +% storing internal names to my name space: +\cs_set_eq:NN \__uftag_tex_pdffeedback:D \tex_pdffeedback:D +\cs_set_eq:NN \__uftag_tex_pdfextension:D \tex_pdfextension:D +\cs_set_eq:NN \__uftag_tex_immediate:D \tex_immediate:D +\cs_set_eq:NN \__uftag_tex_pdfvariable:D \tex_pdfvariable:D +\cs_set_eq:NN \__uftag_tex_global:D \tex_global:D +\cs_set_eq:NN \__uftag_tex_the:D \tex_the:D +\cs_set_eq:NN \__uftag_tex_pdfliteral:D \tex_pdfliteral:D +\cs_set_eq:NN \__uftag_tex_pdfcatalog:D \tex_pdfcatalog:D +\cs_set_eq:NN \__uftag_tex_pdflastobj:D \tex_pdflastobj:D +\cs_set_eq:NN \__uftag_tex_pdfobj:D \tex_pdfobj:D +\cs_set_eq:NN \__uftag_tex_pdfpageattr:D \tex_pdfpageattr:D +\cs_set_eq:NN \__uftag_tex_pdfpagesattr:D \tex_pdfpagesattr:D +\cs_set_eq:NN \__uftag_tex_pdfpageref:D \tex_pdfpageref:D +\cs_set_eq:NN \__uftag_tex_pdfcompresslevel:D \tex_pdfcompresslevel:D +\cs_set_eq:NN \__uftag_tex_pdfobjcompresslevel:D \tex_pdfobjcompresslevel:D + +%%% package options +\bool_new:N\g__uftag_mode_lua_bool + +\DeclareOption{luamode} { \sys_if_engine_luatex:T { \bool_gset_true:N \g__uftag_mode_lua_bool } } +\DeclareOption{genericmode}{ \bool_gset_false:N\g__uftag_mode_lua_bool } +\ExecuteOptions{luamode} +\ProcessOptions + +%%% some packages +\RequirePackage{xparse} +\RequirePackage{atbegshi} +\RequirePackage{zref-base,zref-lastpage} +\RequirePackage{etoolbox} +\RequirePackage{pdfescape} + +%%% absolute page numbers +\int_new:N \g__uftag_abspage_int +\int_gset:Nn \g__uftag_abspage_int { 0 } +\zref@newlist {tagpdf} +\zref@newprop*{tagabspage} [0] { \int_use:N \g__uftag_abspage_int } +\zref@addprop {tagpdf} {tagabspage} + + +%%% tagpdfsetup, +%%% TODO: checks need to be improved +\int_new:N \l__uftag_loglevel_int +\tl_new:N \l__uftag_tree_tabs_order_tl + +\keys_define:nn { tagpdf-setup } +{ + activate-mc .bool_gset:N = \g_uftag_active_mc_bool, + activate-tree .bool_gset:N = \g_uftag_active_tree_bool, + activate-struct .bool_gset:N = \g_uftag_active_struct_bool, + activate-all .meta:n ={activate-mc,activate-tree,activate-struct}, + check-tags .bool_set:N = \g__uftag_check_tags_bool, + check-tags .initial:n = true, + log .choice:, + log / none .code:n = {\int_set:Nn \l__uftag_loglevel_int { 0 }}, + log / v .code:n = {\int_set:Nn \l__uftag_loglevel_int { 1 }}, + log / vv .code:n = {\int_set:Nn \l__uftag_loglevel_int { 2 }}, + log / vvv .code:n = {\int_set:Nn \l__uftag_loglevel_int { 3 }}, + log / all .code:n = {\int_set:Nn \l__uftag_loglevel_int { 10 }}, + tagunmarked .bool_gset:N = \g__uftag_tagunmarked_bool, + tagunmarked .initial:n = true, + tabsorder .choice:, + tabsorder / row .code:n = {\tl_set:Nn \l__uftag_tree_tabs_order_tl {/Tabs/R}}, + tabsorder / column .code:n = {\tl_set:Nn \l__uftag_tree_tabs_order_tl {/Tabs/C}}, + tabsorder / structure .code:n = {\tl_set:Nn \l__uftag_tree_tabs_order_tl {/Tabs/S}}, + tabsorder / none .code:n = {\tl_set:Nn \l__uftag_tree_tabs_order_tl {}}, + compresslevel .choices:nn = {0,1,2,3,4,5,6,7,8,9} + { + \__uftag_pdfcompresslevel:n {#1} + \__uftag_pdfobjcompresslevel:n {#1} + }, + compresslevel .value_required:n = true, + uncompress .meta:n = { compresslevel = 0 }, +} + + +% commands to escape strings so that they can be safely used in pdf +% currently not much used. But will be needed later, when alt and actualtext are added. +% we probably need the equivalent \pdfescapestring, \pdfescapename \pdfescapehex +% the commands of pdfescape adds an additional layout to allow for babel shorthands +\cs_set_eq:NN \__uftag_pdf_escape_string:Nn \EdefEscapeString +\cs_set_eq:NN \__uftag_pdf_escape_name:Nn \EdefEscapeName +\cs_set_eq:NN \__uftag_pdf_escape_hex:Nn \EdefEscapeHex + +% a hook for later code and an absolute page counter +% should be executed before counters are resetted. +% is it used? +\cs_new:Nn \__uftag_finish_page_hook: { } + +\AtBeginShipout + { + \__uftag_finish_page_hook: + \__uftag_tree_write_pageattr: + \int_gincr:N \g__uftag_abspage_int + } + + +%testing the engines and loading the driver files +\sys_if_engine_xetex:T + { + \PackageError { tagpdf } { xelatex~is~not~supported~-~aborting } {} + \tex_endinput:D + } + +\sys_if_engine_luatex:T + { + \file_input:n {tagpdf-luatex.def} + } + +\sys_if_engine_pdftex:T + { + \file_input:n {tagpdf-pdftex.def} + } + +\sys_if_output_dvi:T + { + \PackageError { tagpdf } { dvi~output~is~not~supported~-~aborting }{} + \tex_endinput:D + } + +\cs_generate_variant:Nn \__uftag_prop_gput:Nnn { Nxn , Nxx, Nnx , cnn, cxn, cnx, cno} +\cs_generate_variant:Nn \__uftag_seq_gput_right:Nn { Nx , No, cn, cx } +\cs_generate_variant:Nn \__uftag_prop_new:N { c } +\cs_generate_variant:Nn \__uftag_seq_new:N { c } +\cs_generate_variant:Nn \__uftag_seq_show:N { c } +\cs_generate_variant:Nn \__uftag_prop_show:N { c } +\cs_generate_variant:Nn \prop_gput:Nnn {Nxx} +\cs_generate_variant:Nn \prop_put:Nnn {Nxx} +\cs_generate_variant:Nn \__uftag_pdfuseobjnum:Nn {Nx} +\cs_generate_variant:Nn \__uftag_pdfuseobjnum:nn {nx,xx} +\cs_generate_variant:Nn \__uftag_gset_pdfpageattr:n {x} + +% few temp tl +\tl_new:N \l__uftag_tmpa_tl +\tl_new:N \l__uftag_tmpb_tl +\tl_new:N \l__uftag_tmpc_tl +\tl_new:N \l__uftag_tmpd_tl +\tl_new:N \l__uftag_tmpe_tl + +% helper function to get the propcount. +% use as \prop_map_function:NN PROP { \__uftag_prop_count:nn -1 } +\cs_new:Nn\__uftag_prop_count:nn { + 1 } + +%% Loading the tagpdf sub packages +\RequirePackage { tagpdf-checks-code } +\RequirePackage { tagpdf-user } +\RequirePackage { tagpdf-tree-code } +\RequirePackage { tagpdf-roles-code } +% mc-code is split: +\RequirePackage { tagpdf-mc-code-shared } +\bool_if:NTF \g__uftag_mode_lua_bool + { + \RequirePackage {tagpdf-mc-code-lua} + } + { + \RequirePackage { tagpdf-mc-code-generic } % + } + +\RequirePackage { tagpdf-struct-code } + +\endinput -- cgit v1.2.3