-- 
--  This is file `luacolor.lua',
--  generated with the docstrip utility.
-- 
--  The original source files were:
-- 
--  luacolor.dtx  (with options: `lua')
--  
--  This is a generated file.
--  
--  Project: luacolor
--  Version: 2026-08-26 v1.19
--  
--  Copyright (C)
--     2007, 2009-2011 Heiko Oberdiek
--     2016-2023 Oberdiek Package Support Group
--  
--  This work may be distributed and/or modified under the
--  conditions of the LaTeX Project Public License, either
--  version 1.3c of this license or (at your option) any later
--  version. This version of this license is in
--     https://www.latex-project.org/lppl/lppl-1-3c.txt
--  and the latest version of this license is in
--     https://www.latex-project.org/lppl.txt
--  and version 1.3 or later is part of all distributions of
--  LaTeX version 2005/12/01 or later.
--  
--  This work has the LPPL maintenance status "maintained".
--  
--  The Current Maintainers of this work are
--  Heiko Oberdiek and the Oberdiek Package Support Group
--  https://github.com/ho-tex/luacolor/issues
--  
--  This work consists of the main source file luacolor.dtx
--  and the derived files
--     luacolor.sty, luacolor.pdf, luacolor.ins, luacolor.drv,
--     luacolor.lua,
--  
oberdiek = oberdiek or {}
local luacolor = oberdiek.luacolor or {}
oberdiek.luacolor = luacolor
function luacolor.getversion()
  tex.write("2026-08-26 v1.19")
end
local ifpdf = tonumber(tex.outputmode or tex.pdfoutput) > 0
local prefix
local prefixes = {
  dvips   = "color ",
  dvipdfm = "pdf:sc ",
  truetex = "textcolor:",
  pctexps = "ps::",
}
local patterns = {
  ["^color "]            = "dvips",
  ["^pdf: *begincolor "] = "dvipdfm",
  ["^pdf: *bcolor "]     = "dvipdfm",
  ["^pdf: *bc "]         = "dvipdfm",
  ["^pdf: *setcolor "]   = "dvipdfm",
  ["^pdf: *scolor "]     = "dvipdfm",
  ["^pdf: *sc "]         = "dvipdfm",
  ["^textcolor:"]        = "truetex",
  ["^ps::"]              = "pctexps",
}
local function info(msg, term)
  local target = "log"
  if term then
    target = "term and log"
  end
  texio.write_nl(target, "Package luacolor info: " .. msg .. ".")
  texio.write_nl(target, "")
end
function luacolor.dvidetect()
  local v = tex.box[0]
  assert(v.id == node.id("hlist"))
  for v in node.traverse_id(node.id("whatsit"), v.head) do
    if v and v.subtype == node.subtype("special") then
      local data = v.data
      for pattern, driver in pairs(patterns) do
        if string.find(data, pattern) then
          prefix = prefixes[driver]
          tex.write(driver)
          return
        end
      end
      info("\\special{" .. data .. "}", true)
      return
    end
  end
  info("Missing \\special", true)
end
local map = {
  n = 0,
}
function luacolor.get(color)
  tex.write("" .. luacolor.getvalue(color))
end
function luacolor.getvalue(color)
  local n = map[color]
  if not n then
    n = map.n + 1
    map.n = n
    map[n] = color
    map[color] = n
  end
  return n
end
local attribute
function luacolor.setattribute(attr)
  attribute = attr
end
function luacolor.getattribute()
  return attribute
end
local LIST = 1
local LIST_LEADERS = 2
local LIST_DISC = 3
local COLOR = 4
local NOCOLOR = 5
local RULE = node.id("rule")
local node_types = {
  [node.id("hlist")] = LIST,
  [node.id("vlist")] = LIST,
  [node.id("rule")]  = COLOR,
  [node.id("glyph")] = COLOR,
  [node.id("disc")]  = LIST_DISC,
  [node.id("whatsit")] = {
    [node.subtype("pdf_colorstack")] =
      function(n)
        return n.stack == 0 and NOCOLOR or nil
      end,
    [node.subtype("special")] = COLOR,
    [node.subtype("pdf_literal")] = COLOR,
    [node.subtype("pdf_save")] = COLOR,
    [node.subtype("pdf_restore")] = COLOR, -- probably not needed
-- TODO (DPC)    [node.subtype("pdf_refximage")] = COLOR,
  },
  [node.id("glue")] =
    function(n)
      if n.subtype >= 100 then -- leaders
        if n.leader.id == RULE then
          return COLOR
        else
          return LIST_LEADERS
        end
      end
    end,
}
local function get_type(n)
  local ret = node_types[n.id]
  if type(ret) == 'table' then
    ret = ret[n.subtype]
  end
  if type(ret) == 'function' then
    ret = ret(n)
  end
  return ret
end
local mode = 2 -- luatex.pdfliteral.direct
local WHATSIT = node.id("whatsit")
local SPECIAL = node.subtype("special")
local PDFLITERAL = node.subtype("pdf_literal")
local DRY_FALSE = false
local DRY_TRUE = true
local function traverse(list, color, dry)
  if not list then
    return color
  end
  local head
  if get_type(list) == LIST then
    head = list.head
  elseif get_type(list) == LIST_DISC then
    head = list.replace
  else
    texio.write_nl("!!! Error: Wrong list type: " .. node.type(list.id))
    return color
  end
  for n in node.traverse(head) do
    local t = get_type(n)
    if t == LIST or t == LIST_DISC then
      color = traverse(n, color, dry)
    elseif t == LIST_LEADERS then
      local color_after = traverse(n.leader, color, DRY_TRUE)
      if color == color_after then
        traverse(n.leader, color, DRY_FALSE or dry)
      else
        traverse(n.leader, '', DRY_FALSE or dry)
        color = ''
      end
    elseif t == COLOR then
      local v = node.has_attribute(n, attribute)
      if v then
        local newColor = map[v]
        if newColor ~= color then
          color = newColor
          if dry == DRY_FALSE then
            local newNode
            if ifpdf then
              newNode = node.new(WHATSIT, PDFLITERAL)
              newNode.mode = mode
              newNode.data = color
            else
              newNode = node.new(WHATSIT, SPECIAL)
              newNode.data = prefix .. color
            end
            head = node.insert_before(head, n, newNode)
          end
        end
      end
    elseif t == NOCOLOR then
      color = ''
    end
  end
  if get_type(list) == LIST then
    list.head = head
  else
    list.replace = head
  end
  return color
end
function luacolor.process(box)
  local color = ""
  local list = tex.getbox(box)
  traverse(list, color, DRY_FALSE)
end

if luatexbase.callbacktypes.pre_shipout_filter then
  luatexbase.add_to_callback("pre_shipout_filter", function(list)
    traverse(list, "", DRY_FALSE)
    return true
  end, "luacolor.process")
end
if luaotfload.set_colorhandler then
  local set_attribute = node.direct.set_attribute
  luaotfload.set_colorhandler(function(head, n, color)
    set_attribute(n, attribute, luacolor.getvalue(color))
    return head, n
  end)
end

-- 
--  End of File `luacolor.lua'.
