From 55f834f428a0c05dedecc8d33a1c5300e58c91fc Mon Sep 17 00:00:00 2001
From: Norbert Preining <norbert@preining.info>
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) }
+ }
+%</luatex>
+%    \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
+
+%</pdftex>
+%    \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,"<</Type /MCR /Pg "..kidpageobjnum .. " 0 R /MCID "..kidnum.. ">> " )
+    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
+
+
+%</lua>
+%    \end{macrocode}
-- 
cgit v1.2.3

