From 55f834f428a0c05dedecc8d33a1c5300e58c91fc Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Wed, 24 Feb 2021 03:01:25 +0000 Subject: CTAN sync 202102240301 --- macros/latex/contrib/tagpdf/tagpdf-backend.dtx | 803 +++++++++++++++++++++++++ 1 file changed, 803 insertions(+) create mode 100644 macros/latex/contrib/tagpdf/tagpdf-backend.dtx (limited to 'macros/latex/contrib/tagpdf/tagpdf-backend.dtx') diff --git a/macros/latex/contrib/tagpdf/tagpdf-backend.dtx b/macros/latex/contrib/tagpdf/tagpdf-backend.dtx new file mode 100644 index 0000000000..d80d56778b --- /dev/null +++ b/macros/latex/contrib/tagpdf/tagpdf-backend.dtx @@ -0,0 +1,803 @@ +% \iffalse meta-comment +% +%% File: tagpdf-backend.dtx +% +% Copyright (C) 2019-2020 Ulrike Fischer +% +% It may be distributed and/or modified under the conditions of the +% LaTeX Project Public License (LPPL), either version 1.3c of this +% license or (at your option) any later version. The latest version +% of this license is in the file +% +% https://www.latex-project.org/lppl.txt +% +% This file is part of the "tagpdf bundle" (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/u-fischer/tagpdf +% +% for those people who are interested. +% +% \fi +% +% \begin{macrocode} +%<@@=tag> +%<*luatex> +\ProvidesExplFile {tagpdf-luatex.def} {2021/02/23} {0.80} + {tagpdf~driver~for~luatex} + +\newattribute \l_@@_mc_type_attr %the value represent the type +\newattribute \l_@@_mc_cnt_attr %will hold the \c@g_@@_MCID_abs_int value + +\newattribute \g_@@_interwordspace_attr +\newattribute \g_@@_interwordfont_attr + +% The lua code +% ensure that 10pt font has been loaded: +{ + \fontencoding{TU}\fontfamily{lmr}\fontseries{m}\fontshape{n}\fontsize{10pt}{10pt}\selectfont +} +\directlua { tagpdf=require('tagpdf.lua') } + +%%%% driver (lualatex) commands +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% I probably want also lua tables +% I put them in the ltx.@@.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 +% ltx.@@.tables[string] +% Old code, I'm not quite sure if this was a good idea. Now I have mix of table in +% ltx.@@.tables and ltx.@@.mc/struct. And a lot is probably not needed. + +\cs_new:Nn \@@_luatex_get_table_name:Nn + { + \tl_set_rescan:Nnn #1 { \char_set_catcode_ignore:N \\ } { #2 } + } + + +\cs_new:Nn \@@_prop_new:N + { + \prop_new:N #1 + \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { ltx.@@.tables.\l_tmpa_tl = {} } + } + + +\cs_new:Nn \@@_seq_new:N + { + \seq_new:N #1 + \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { ltx.@@.tables.\l_tmpa_tl = {} } + } + + +\cs_new:Nn \@@_prop_gput:Nnn + { + \prop_gput:Nnn #1 { #2 } { #3 } + \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { ltx.@@.tables.\l_tmpa_tl["#2"] = "#3" } + } + + +\cs_new:Nn \@@_seq_gput_right:Nn + { + \seq_gput_right:Nn #1 { #2 } + \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { table.insert(ltx.@@.tables.\l_tmpa_tl, "#2") } + } + +%Hm not quite sure about the naming + +\cs_new:Npn \@@_seq_item:cn #1 #2 + { + \directlua { tex.print(ltx.@@.tables.#1[#2]) } + } + +\cs_new:Npn \@@_prop_item:cn #1 #2 + { + \directlua { tex.print(ltx.@@.tables.#1["#2"]) } + } + +%for debugging commands that show both the seq/prop and the lua tables +\cs_new:Nn \@@_seq_show:N + { + \seq_show:N #1 + \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua { ltx.@@.trace.log ("lua~sequence~array~\l_tmpa_tl",1) } + \directlua { ltx.@@.trace.show_seq (ltx.@@.tables.\l_tmpa_tl) } + } + +\cs_new:Nn \@@_prop_show:N + { + \prop_show:N #1 + \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 } + \directlua {ltx.@@.trace.log ("lua~property~table~\l_tmpa_tl",1) } + \directlua {ltx.@@.trace.show_prop (ltx.@@.tables.\l_tmpa_tl) } + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*pdftex> +\ProvidesExplFile {tagpdf-pdftex.def} {2021/02/23} {0.80} + {tagpdf~driver~for~pdftex} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% driver (pdflatex) commands +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% These commands are only aliases for pdflatex but are defined differently with luatex +% to get also lua tables. +\cs_set_eq:NN \@@_prop_new:N \prop_new:N + +\cs_set_eq:NN \@@_seq_new:N \seq_new:N + +\cs_set_eq:NN \@@_prop_gput:Nnn \prop_gput:Nnn + +\cs_set_eq:NN \@@_seq_gput_right:Nn \seq_gput_right:Nn + +\cs_set_eq:NN \@@_seq_item:cn \seq_item:cn + +\cs_set_eq:NN \@@_prop_item:cn \prop_item:cn + +\cs_set_eq:NN \@@_seq_show:N \seq_show:N + +\cs_set_eq:NN \@@_prop_show:N \prop_show:N + +% +% \end{macrocode} +% \begin{macrocode} +%<*lua> +-- tagpdf.lua +-- Ulrike Fischer + +local ProvidesLuaModule = { + name = "tagpdf", + version = "0.80", --TAGVERSION + date = "2021-02-23", --TAGDATE + description = "tagpdf lua code", + license = "The LATEX Project Public License 1.3c" +} + +if luatexbase and luatexbase.provides_module then + luatexbase.provides_module (ProvidesLuaModule) +end + +--[[ +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 ltx.@@. It contains the functions and also the data +collected during the compilation. + +ltx.@@.mc will contain mc connected data. +ltx.@@.struct will contain structure related data. +ltx.@@.page will contain page data +ltx.@@.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 ... +ltx.@@.func will contain (public) functions. +ltx.@@.trace will contain tracing/loging functions. +local funktions starts with __ +functions meant for users will be in ltx.tag + +functions + ltx.@@.func.get_num_from (tag): takes a tag (string) and returns the id number + ltx.@@.func.output_num_from (tag): takes a tag (string) and prints (to tex) the id number + ltx.@@.func.get_tag_from (num): takes a num and returns the tag + ltx.@@.func.output_tag_from (num): takes a num and prints (to tex) the tag + ltx.@@.func.store_mc_data (num,key,data): stores key=data in ltx.@@.mc[num] + ltx.@@.func.store_mc_label (label,num): stores label=num in ltx.@@.mc.labels + ltx.@@.func.store_mc_kid (mcnum,kid,page): stores the mc-kids of mcnum on page page + ltx.@@.func.store_mc_in_page(mcnum,mcpagecnt,page): stores in the page table the number of mcnum on this page + ltx.@@.func.store_struct_mcabs (structnum,mcnum): stores relations structnum<->mcnum (abs) + ltx.@@.func.mc_insert_kids (mcnum): inserts the /K entries for mcnum by wandering throught the [kids] table + ltx.@@.func.mark_page_elements(box,mcpagecnt,mccntprev,mcopen,name,mctypeprev) : the main function + ltx.@@.func.mark_shipout (): a wrapper around the core function which inserts the last EMC + ltx.@@.func.fill_parent_tree_line (page): outputs the entries of the parenttree for this page + ltx.@@.func.output_parenttree(): outputs the content of the parenttree + ltx.@@.func.markspaceon(), ltx.@@.func.markspaceoff(): (de)activates the marking of positions for space chars + ltx.@@.trace.show_mc_data (num): shows ltx.@@.mc[num] + ltx.@@.trace.show_all_mc_data (max): shows a maximum about mc's + ltx.@@.trace.show_seq: shows a sequence (array) + ltx.@@.trace.show_struct_data (num): shows data of structure num + ltx.@@.trace.show_prop: shows a prop + ltx.@@.trace.log + ltx.@@.trace.showspaces : boolean +--]] + +local mctypeattributeid = luatexbase.registernumber ("l_@@_mc_type_attr") +local mccntattributeid = luatexbase.registernumber ("l_@@_mc_cnt_attr") +local iwspaceattributeid = luatexbase.registernumber ("g_@@_interwordspace_attr") +local iwfontattributeid = luatexbase.registernumber ("g_@@_interwordfont_attr") + + +local catlatex = luatexbase.registernumber("catcodetable@latex") +local tagunmarkedbool= token.create("g_@@_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 nodesetattribute = node.set_attribute +local nodenew = node.new +local nodetail = node.tail +local nodeslide = node.slide +local noderemove = node.remove +local nodetraverseid = node.traverse_id +local nodetraverse = node.traverse +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 GLYPH = node.id("glyph") +local KERN = node.id("kern") +local PENALTY = node.id("penalty") +local LOCAL_PAR = node.id("local_par") +local MATH = node.id("math") + +local function @@_get_mathsubtype (mathnode) + if mathnode.subtype == 0 then + subtype = "beginmath" + else + subtype = "endmath" + end + return subtype +end + + + +ltx = ltx or { } +ltx.@@ = ltx.@@ or { } +ltx.@@.mc = ltx.@@.mc or { } -- mc data +ltx.@@.struct = ltx.@@.struct or { } -- struct data +ltx.@@.tables = ltx.@@.tables or { } -- tables created with new prop and new seq. + -- wasn't a so great idea ... +ltx.@@.page = ltx.@@.page or { } -- page data, currently only i->{0->mcnum,1->mcnum,...} +ltx.@@.trace = ltx.@@.trace or { } -- show commands +ltx.@@.func = ltx.@@.func or { } -- functions +ltx.@@.conf = ltx.@@.conf or { } -- configuration variables + +local @@_log = + function (message,loglevel) + if (loglevel or 3) <= tex.count["l_@@_loglevel_int"] then + texio.write_nl("tagpdf: ".. message) + end + end + +ltx.@@.trace.log = @@_log + + +local @@_get_mc_cnt_type_tag = function (n) + local mccnt = nodegetattribute(n,mccntattributeid) or -1 + local mctype = nodegetattribute(n,mctypeattributeid) or -1 + local tag = ltx.@@.func.get_tag_from(mctype) + return mccnt,mctype,tag +end + + +local function @@_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 @@_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 @@_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 + +-- this is for debugging the space chars +local function @@_show_spacemark (head,current,color,height) + local markcolor = color or "1 0 0" + local markheight = height or 10 + local pdfstring = node.new("whatsit","pdf_literal") + pdfstring.data = + string.format("q "..markcolor.." RG "..markcolor.." rg 0.4 w 0 %g m 0 %g l S Q",-3,markheight) + head = node.insert_after(head,current,pdfstring) + return head +end + +--[[ a function to mark up places where real space chars should be inserted + it only sets an attribute. +--]] + +local function @@_mark_spaces (head) + local inside_math = false + for n in nodetraverse(head) do + local id = n.id + if id == GLYPH then + local glyph = n + if glyph.next and (glyph.next.id == GLUE) + and not inside_math and (glyph.next.width >0) + then + nodesetattribute(glyph.next,iwspaceattributeid,1) + nodesetattribute(glyph.next,iwfontattributeid,glyph.font) + -- for debugging + if ltx.@@.trace.showspaces then + @@_show_spacemark (head,glyph) + end + elseif glyph.next and (glyph.next.id==KERN) and not inside_math then + local kern = glyph.next + if kern.next and (kern.next.id== GLUE) and (kern.next.width >0) + then + nodesetattribute(kern.next,iwspaceattributeid,1) + nodesetattribute(kern.next,iwfontattributeid,glyph.font) + end + end + elseif id == PENALTY then + local glyph = n + -- ltx.@@.trace.log ("PENALTY ".. n.subtype.."VALUE"..n.penalty,3) + if glyph.next and (glyph.next.id == GLUE) + and not inside_math and (glyph.next.width >0) and n.subtype==0 + then + nodesetattribute(glyph.next,iwspaceattributeid,1) + -- nodesetattribute(glyph.next,iwfontattributeid,glyph.font) + -- for debugging + if ltx.@@.trace.showspaces then + @@_show_spacemark (head,glyph) + end + end + elseif id == MATH then + inside_math = (n.subtype == 0) + end + end + return head +end + +local function @@_activate_mark_space () + if not luatexbase.in_callback ("pre_linebreak_filter","markspaces") then + luatexbase.add_to_callback("pre_linebreak_filter",@@_mark_spaces,"markspaces") + luatexbase.add_to_callback("hpack_filter",@@_mark_spaces,"markspaces") + end +end + +ltx.@@.func.markspaceon=@@_activate_mark_space + +local function @@_deactivate_mark_space () + if luatexbase.in_callback ("pre_linebreak_filter","markspaces") then + luatexbase.remove_from_callback("pre_linebreak_filter","markspaces") + luatexbase.remove_from_callback("hpack_filter","markspaces") + end +end +-- +ltx.@@.func.markspaceoff=@@_deactivate_mark_space + +local default_space_char = node.new(GLYPH) +local default_fontid = font.id("TU/lmr/m/n/10") +default_space_char.char = 32 +default_space_char.font = default_fontid + +local function @@_insert_space_char (head,n,fontid) + if luaotfload.aux.slot_of_name(fontid,"space") then + local space + -- head, space = node.insert_before(head, n, ) -- Set the right font + -- n.width = n.width - space.width + -- space.attr = n.attr + end +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 ltx.@@.func.mark_page_elements (box,mcpagecnt,mccntprev,mcopen,name,mctypeprev) + local name = name or ("SOMEBOX") + local mctypeprev = mctypeprev or -1 + local abspage = status.total_pages + 1 -- the real counter is increased inside the box so one off + -- if the callback is not used. + ltx.@@.trace.log ("PAGE " .. abspage,3) + ltx.@@.trace.log ("FUNC ARGS: pagecnt".. mcpagecnt.." prev "..mccntprev .. " type prev "..mctypeprev,4) + ltx.@@.trace.log ("TRAVERSING BOX ".. tostring(name).." TYPE ".. node.type(node.getid(box)),3) + local head = box.head -- ShipoutBox is a vlist? + if head then + mccnthead, mctypehead,taghead = @@_get_mc_cnt_type_tag (head) + ltx.@@.trace.log ("HEAD " .. node.type(node.getid(head)).. " MC"..tostring(mccnthead).." => TAG "..tostring(mctypehead).." => "..tostring(taghead),3) + else + ltx.@@.trace.log ("HEAD is ".. tostring(head),3) + end + for n in node.traverse(head) do + local mccnt, mctype, tag = @@_get_mc_cnt_type_tag (n) + local spaceattr = nodegetattribute(n,iwspaceattributeid) or -1 + ltx.@@.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= + ltx.@@.func.mark_page_elements (n,mcpagecnt,mccntprev,mcopen,"INTERNAL HLIST",mctypeprev) + elseif n.id == VLIST then -- enter the vlist + mcopen,mcpagecnt,mccntprev,mctypeprev= + ltx.@@.func.mark_page_elements (n,mcpagecnt,mccntprev,mcopen,"INTERNAL VLIST",mctypeprev) + elseif n.id == GLUE then -- at glue real space chars are inserted, for the rest it is ignored + -- for debugging + if ltx.@@.trace.showspaces and spaceattr==1 then + @@_show_spacemark (head,n,"0 1 0") + end + if spaceattr==1 then + local space + local space_char = node.copy(default_space_char) + local curfont = nodegetattribute(n,iwfontattributeid) + ltx.@@.trace.log ("FONT ".. tostring(curfont),3) + if curfont and luaotfload.aux.slot_of_name(curfont,"space") then + space_char.font=curfont + end + head, space = node.insert_before(head, n, space_char) -- + n.width = n.width - space.width + space.attr = n.attr + end + 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 + ltx.@@.trace.log ("SUBTYPE KERN ".. n.subtype,3) + 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 + ltx.@@.trace.log("NODE "..node.type(node.getid(n)).." "..@@_get_mathsubtype(n),3) + end + -- endmath + ltx.@@.trace.log("CURRENT "..mccnt.." PREV "..mccntprev,3) + if mccnt~=mccntprev then -- a new mc chunk + ltx.@@.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=@@_insert_emc_node (box.list,n) + mcopen = mcopen - 1 + ltx.@@.trace.log ("INSERT EMC " .. mcpagecnt .. " MCOPEN = " .. mcopen,2) + if mcopen ~=0 then + ltx.@@.trace.log ("!WARNING! open mc" .. " MCOPEN = " .. mcopen,1) + end + end + if ltx.@@.mc[mccnt] then + if ltx.@@.mc[mccnt]["artifact"] then + ltx.@@.trace.log("THIS IS AN ARTIFACT of type "..tostring(ltx.@@.mc[mccnt]["artifact"]),3) + if ltx.@@.mc[mccnt]["artifact"] == "" then + box.list = @@_insert_bmc_node (box.list,n,"Artifact") + else + box.list = @@_insert_bdc_node (box.list,n,"Artifact", "/Type /"..ltx.@@.mc[mccnt]["artifact"]) + end + else + ltx.@@.trace.log("THIS IS A TAG "..tostring(tag),3) + mcpagecnt = mcpagecnt +1 + ltx.@@.trace.log ("INSERT BDC "..mcpagecnt,2) + local dict= "/MCID "..mcpagecnt + if ltx.@@.mc[mccnt]["raw"] then + ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["raw"]),3) + dict= dict .. " " .. ltx.@@.mc[mccnt]["raw"] + end + if ltx.@@.mc[mccnt]["alt"] then + ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["alt"]),3) + dict= dict .. " " .. ltx.@@.mc[mccnt]["alt"] + end + if ltx.@@.mc[mccnt]["actualtext"] then + ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["actualtext"]),3) + dict= dict .. " " .. ltx.@@.mc[mccnt]["actualtext"] + end + box.list = @@_insert_bdc_node (box.list,n,tag, dict) + ltx.@@.func.store_mc_kid (mccnt,mcpagecnt,abspage) + ltx.@@.func.store_mc_in_page(mccnt,mcpagecnt,abspage) + ltx.@@.trace.show_mc_data (mccnt) + end + mcopen = mcopen + 1 + else + ltx.@@.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 = @@_insert_bmc_node (box.list,n,"Artifact") + mcopen = mcopen + 1 + end + end + mccntprev = mccnt + end + end -- end if + end -- end for + if head then + mccnthead, mctypehead,taghead = @@_get_mc_cnt_type_tag (head) + ltx.@@.trace.log ("ENDHEAD " .. node.type(node.getid(head)).. " MC"..tostring(mccnthead).." => TAG "..tostring(mctypehead).." => "..tostring(taghead),3) + else + ltx.@@.trace.log ("ENDHEAD is ".. tostring(head),3) + end + ltx.@@.trace.log ("QUITTING TRAVERSING BOX ".. tostring(name).." TYPE ".. node.type(node.getid(box)),3) + return mcopen,mcpagecnt,mccntprev,mctypeprev +end + + + +function ltx.__tag.func.mark_shipout (box) + mcopen = ltx.__tag.func.mark_page_elements (box,-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 list = box.list + emcnode.data = "EMC" + emcnode.mode=1 + if list then + list = node.insert_after (list,node.tail(list),emcnode) + mcopen = mcopen - 1 + ltx.__tag.trace.log ("INSERT LAST EMC, MCOPEN = " .. mcopen,2) + else + ltx.__tag.trace.log ("UPS ",1) + end + if mcopen ~=0 then + ltx.__tag.trace.log ("!WARNING! open mc" .. " MCOPEN = " .. mcopen,1) + end + end +end + + +function ltx.@@.trace.show_seq (seq) + if (type(seq) == "table") then + for i,v in ipairs(seq) do + @@_log ("[" .. i .. "] => " .. tostring(v),1) + end + else + @@_log ("sequence " .. tostring(seq) .. " not found",1) + end +end + +local @@_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 ltx.@@.trace.show_prop (prop) + if (type(prop) == "table") then + for i,v in @@_pairs_prop (prop) do + @@_log ("[" .. i .. "] => " .. tostring(v),1) + end + else + @@_log ("prop " .. tostring(prop) .. " not found or not a table",1) + end + end + + +local @@_get_num_from = + function (tag) + if ltx.@@.tables["g_@@_role_tags_prop"][tag] then + a= ltx.@@.tables["g_@@_role_tags_prop"][tag] + else + a= -1 + end + return a + end + +ltx.@@.func.get_num_from = @@_get_num_from + +function ltx.@@.func.output_num_from (tag) + local num = @@_get_num_from (tag) + tex.sprint(catlatex,num) + if num == -1 then + @@_log ("Unknown tag "..tag.." used") + end +end + +local @@_get_tag_from = + function (num) + if ltx.@@.tables["g_@@_role_tags_seq"][num] then + a = ltx.@@.tables["g_@@_role_tags_seq"][num] + else + a= "UNKNOWN" + end + return a +end + +ltx.@@.func.get_tag_from = @@_get_tag_from + +function ltx.@@.func.output_tag_from (num) + tex.sprint(catlatex,@@_get_tag_from (num)) +end + +function ltx.@@.func.store_mc_data (num,key,data) + ltx.@@.mc[num] = ltx.@@.mc[num] or { } + ltx.@@.mc[num][key] = data + @@_log ("storing mc"..num..": "..tostring(key).."=>"..tostring(data)) +end + +function ltx.@@.trace.show_mc_data (num) + if ltx.@@ and ltx.@@.mc and ltx.@@.mc[num] then + for k,v in pairs(ltx.@@.mc[num]) do + @@_log ("mc"..num..": "..tostring(k).."=>"..tostring(v),3) + end + if ltx.@@.mc[num]["kids"] then + @@_log ("mc" .. num .. " has " .. #ltx.@@.mc[num]["kids"] .. " kids",3) + for k,v in ipairs(ltx.@@.mc[num]["kids"]) do + @@_log ("mc ".. num .. " kid "..k.." =>" .. v.kid.." on page " ..v.page,3) + end + end + else + @@_log ("mc"..num.." not found",3) + end +end + +function ltx.@@.trace.show_all_mc_data (max) + for i = 1, max do + ltx.@@.trace.show_mc_data (i) + end +end + + +function ltx.@@.func.store_mc_label (label,num) + ltx.@@.mc["labels"] = ltx.@@.mc["labels"] or { } + ltx.@@.mc.labels[label] = num +end + +function ltx.@@.func.store_mc_kid (mcnum,kid,page) + ltx.@@.trace.log("MC"..mcnum.." STORING KID" .. kid.." on page " .. page,3) + ltx.@@.mc[mcnum]["kids"] = ltx.@@.mc[mcnum]["kids"] or { } + local kidtable = {kid=kid,page=page} + tableinsert(ltx.@@.mc[mcnum]["kids"], kidtable ) +end + + +function ltx.@@.func.mc_num_of_kids (mcnum) + local num = 0 + if ltx.@@.mc[mcnum] and ltx.@@.mc[mcnum]["kids"] then + num = #ltx.@@.mc[mcnum]["kids"] + end + ltx.@@.trace.log ("MC" .. mcnum .. "has " .. num .. "KIDS",4) + return num +end + +function ltx.@@.func.mc_insert_kids (mcnum,single) + if ltx.@@.mc[mcnum] then + ltx.@@.trace.log("MC-KIDS test " .. mcnum,4) + if ltx.@@.mc[mcnum]["kids"] then + if #ltx.@@.mc[mcnum]["kids"] > 1 and single==1 then + tex.sprint("[") + end + for i,kidstable in ipairs( ltx.@@.mc[mcnum]["kids"] ) do + local kidnum = kidstable["kid"] + local kidpage = kidstable["page"] + local kidpageobjnum = pdfpageref(kidpage) + ltx.@@.trace.log("MC" .. mcnum .. " insert KID " ..i.. " with num " .. kidnum .. " on page " .. kidpage.."/"..kidpageobjnum,3) + tex.sprint(catlatex,"<> " ) + end + if #ltx.@@.mc[mcnum]["kids"] > 1 and single==1 then + tex.sprint("]") + end + else + ltx.@@.trace.log("WARN! MC"..mcnum.." has no kids",0) + if single==1 then + tex.sprint("null") + end + end + else + ltx.@@.trace.log("WARN! MC"..mcnum.." doesn't exist",0) + end +end + + +function ltx.@@.func.store_struct_mcabs (structnum,mcnum) + ltx.@@.struct[structnum]=ltx.@@.struct[structnum] or { } + ltx.@@.struct[structnum]["mc"]=ltx.@@.struct[structnum]["mc"] or { } + -- a structure can contain more than on mc chunk, the content should be ordered + tableinsert(ltx.@@.struct[structnum]["mc"],mcnum) + ltx.@@.trace.log("MCNUM "..mcnum.." insert in struct "..structnum,3) + -- but every mc can only be in one structure + ltx.@@.mc[mcnum]= ltx.@@.mc[mcnum] or { } + ltx.@@.mc[mcnum]["parent"] = structnum +end + +function ltx.@@.trace.show_struct_data (num) + if ltx.@@ and ltx.@@.struct and ltx.@@.struct[num] then + for k,v in ipairs(ltx.@@.struct[num]) do + @@_log ("struct "..num..": "..tostring(k).."=>"..tostring(v)) + end + else + @@_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 ltx.@@.func.store_mc_in_page (mcnum,mcpagecnt,page) + ltx.@@.page[page] = ltx.@@.page[page] or {} + ltx.@@.page[page][mcpagecnt] = mcnum + ltx.@@.trace.log("PAGE " .. page .. ": inserting MCID " .. mcpagecnt .. " => " .. mcnum,3) +end + +function ltx.@@.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 ltx.@@.page[page] and ltx.@@.page[page][0] then + mcchunks=#ltx.@@.page[page] + ltx.@@.trace.log("PAGETREE PAGE "..page.." has "..mcchunks.."+1 Elements ",3) + for i=0,mcchunks do + ltx.@@.trace.log("PAGETREE CHUNKS "..ltx.@@.page[page][i],3) + end + if mcchunks == 0 then + -- only one chunk so no need for an array + local mcnum = ltx.@@.page[page][0] + local structnum = ltx.@@.mc[mcnum]["parent"] + local propname = "g_@@_struct_"..structnum.."_prop" + local objref = ltx.@@.tables[propname]["objref"] or "XXXX" + texio.write_nl("=====>"..tostring(objref)) + numsentry = pdfpage .. " [".. objref .. "]" + ltx.@@.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3) + else + numsentry = pdfpage .. " [" + for i=0,mcchunks do + local mcnum = ltx.@@.page[page][i] + local structnum = ltx.@@.mc[mcnum]["parent"] or 0 + local propname = "g_@@_struct_"..structnum.."_prop" + local objref = ltx.@@.tables[propname]["objref"] or "XXXX" + numsentry = numsentry .. " ".. objref + end + numsentry = numsentry .. "] " + ltx.@@.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3) + end + else + ltx.@@.trace.log ("PAGETREE: NO DATA FOR PAGE "..page,3) + end + return numsentry +end + +function ltx.@@.func.output_parenttree (abspage) + for i=1,abspage do + line = ltx.@@.func.fill_parent_tree_line (i) .. "^^J" + tex.sprint(catlatex,line) + end +end + + +% +% \end{macrocode} -- cgit v1.2.3