summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/attr-ini.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/attr-ini.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/attr-ini.lua1078
1 files changed, 374 insertions, 704 deletions
diff --git a/Master/texmf-dist/tex/context/base/attr-ini.lua b/Master/texmf-dist/tex/context/base/attr-ini.lua
index c339d467214..535488c35b1 100644
--- a/Master/texmf-dist/tex/context/base/attr-ini.lua
+++ b/Master/texmf-dist/tex/context/base/attr-ini.lua
@@ -6,505 +6,29 @@ if not modules then modules = { } end modules ['attr-ini'] = {
license = "see context related readme files"
}
--- todo: document this
-
--- nb: attributes: color etc is much slower than normal (marks + literals) but ...
--- nb. too many "0 g"s
-
---
--- nodes
---
-
-nodes = nodes or { }
-
-local format, concat = string.format, table.concat
-
--- This is not the most ideal place, but it will do. Maybe we need to move
--- attributes to node-att.lua.
-
-do
-
- -- just for testing
-
- local reserved = { }
-
- function nodes.register(n)
- reserved[#reserved+1] = n
- end
-
- function nodes.cleanup_reserved(nofboxes) -- todo
- local nr, free = #reserved, node.free
- for i=1,nr do
- free(reserved[i])
- end
- local nl, tb, flush = 0, tex.box, node.flush_list
- if nofboxes then
- for i=1,nofboxes do
- local l = tb[i]
- if l then
- -- flush(l)
- tb[i] = nil
- nl = nl + 1
- end
- end
- end
- reserved = { }
- return nr, nl, nofboxes
- end
-
-end
-
-do
-
- local pdfliteral = node.new("whatsit",8) pdfliteral.next, pdfliteral.prev = nil, nil pdfliteral.mode = 1
- local disc = node.new("disc") disc.next, disc.prev = nil, nil
- local kern = node.new("kern",1) kern.next, kern.prev = nil, nil
- local penalty = node.new("penalty") penalty.next, penalty.prev = nil, nil
- local glue = node.new("glue") glue.next, glue.prev = nil, nil
- local glue_spec = node.new("glue_spec") glue_spec.next, glue_spec.prev = nil, nil
- local glyph = node.new("glyph",0) glyph.next, glyph.prev = nil, nil
-
- nodes.register(pdfliteral)
- nodes.register(disc)
- nodes.register(kern)
- nodes.register(penalty)
- nodes.register(glue)
- nodes.register(glue_spec)
- nodes.register(glyph)
-
- local copy = node.copy
-
- function nodes.glyph(fnt,chr)
- local n = copy(glyph)
- if fnt then n.font = fnt end
- if chr then n.char = chr end
- return n
- end
- function nodes.penalty(p)
- local n = copy(penalty)
- n.penalty = p
- return n
- end
- function nodes.kern(k)
- local n = copy(kern)
- n.kern = k
- return n
- end
- function nodes.glue(width,stretch,shrink)
- local n = copy(glue)
- local s = copy(glue_spec)
- s.width, s.stretch, s.shrink = width, stretch, shrink
- n.spec = s
- return n
- end
- function nodes.glue_spec(width,stretch,shrink)
- local s = copy(glue_spec)
- s.width, s.stretch, s.shrink = width, stretch, shrink
- return s
- end
-
- function nodes.disc()
- return copy(disc)
- end
-
- function nodes.pdfliteral(str)
- local t = copy(pdfliteral)
- t.data = str
- return t
- end
-
-end
-
-function tex.node_mem_status()
- -- todo: lpeg
- local s = status.node_mem_usage
- local t = { }
- for n, tag in s:gmatch("(%d+) ([a-z_]+)") do
- t[tag] = n
- end
- return t
-end
+-- this module is being reconstructed
+-- we can also do the nsnone via a metatable and then also se index 0
---
--- attributes
---
+local type = type
+local format, gmatch = string.format, string.gmatch
+local concat = table.concat
+local texsprint = tex.sprint
-attributes = attributes or { }
+local ctxcatcodes = tex.ctxcatcodes
-attributes.names = attributes.names or { }
-attributes.numbers = attributes.numbers or { }
-attributes.list = attributes.list or { }
+-- todo: document this
-input.storage.register(false,"attributes/names", attributes.names, "attributes.names")
-input.storage.register(false,"attributes/numbers", attributes.numbers, "attributes.numbers")
-input.storage.register(false,"attributes/list", attributes.list, "attributes.list")
+-- nb: attributes: color etc is much slower than normal (marks + literals) but ...
+-- nb. too many "0 g"s
-function attributes.define(name,number)
- attributes.numbers[name], attributes.names[number], attributes.list[number] = number, name, { }
-end
+nodes = nodes or { }
+states = states or { }
+shipouts = shipouts or { }
-- We can distinguish between rules and glyphs but it's not worth the trouble. A
-- first implementation did that and while it saves a bit for glyphs and rules, it
-- costs more resourses for transparencies. So why bother.
--- namespace for all those features / plural becomes singular
-
--- i will do the resource stuff later, when we have an interface to pdf (ok, i can
--- fake it with tokens but it will take some coding
-
-function totokens(str)
- local t = { }
---~ for c in string.bytes(str) do
- for c in str:bytes() do
- t[#t+1] = { 12, c }
- end
- return t
-end
-
--- temp hack, will be proper driver stuff
-
-backends = backends or { }
-backends.pdf = backends.pdf or { }
-backend = backend or backends.pdf
-
-do
-
- local pdfliteral, register = nodes.pdfliteral, nodes.register
-
- function backends.pdf.literal(str)
- local t = pdfliteral(str)
- register(t)
- return t
- end
-
-end
-
--- shipouts
-
-shipouts = shipouts or { }
-shipouts.plugins = shipouts.plugins or { }
-
-do
-
- local pairs = pairs -- in theory faster
-
- local hlist, vlist = node.id('hlist'), node.id('vlist')
-
- local has_attribute = node.has_attribute
-
- nodes.trigger = nodes.trigger or false
- nodes.triggering = nodes.triggering or false
-
- -- we used to do the main processor loop here and call processor for each node
- -- but eventually this was too much a slow down (1 sec on 23 for 120 pages mk)
- -- so that we moved looping to the processor itself; this may lead to a bit of
- -- duplicate code once that we have more state handlers
-
- local starttiming, stoptiming = input.starttiming, input.stoptiming
-
- local function process_attributes(head,plugins)
- if head then -- is already tested
- starttiming(attributes)
- local done, used = false, { }
- local trigger, numbers = nodes.trigger, attributes.numbers
- for name, plugin in pairs(plugins) do
- local attribute = numbers[name]
- if attribute then
- local namespace = plugin.namespace
- if namespace.enabled then
- local initializer = plugin.initializer
- local processor = plugin.processor
- local finalizer = plugin.finalizer
- local resolver = plugin.resolver
- if initializer then
- initializer(namespace,attribute,head)
- end
- if processor then
- local inheritance = (resolver and resolver()) or -1
- local ok -- = false
- head, ok = processor(namespace,attribute,head,inheritance)
- done = done or ok
- end
- if finalizer then -- no need when not ok
- local ok -- = false
- head, ok, used[attribute] = finalizer(namespace,attribute,head)
- done = done or ok
- end
- end
- else
- texio.write_nl(format("undefined attribute %s",name))
- end
- end
- if done then
- for name, plugin in pairs(plugins) do
- local attribute = numbers[name]
- if used[attribute] then
- local namespace = plugin.namespace
- if namespace.enabled then
- local flusher = plugin.flusher
- if flusher then
- local h, d = flusher(namespace,attribute,head,used[attribute])
- head = h
- end
- end
- end
- end
- end
- stoptiming(attributes)
- return head, done
- else
- return head, false
- end
- end
-
- nodes.process_attributes = process_attributes
-
- --~ glyph = 746876
- --~ glue = 376096
- --~ hlist = 152284
- --~ disc = 47224
- --~ kern = 41504
- --~ penalty = 31964
- --~ whatsit = 29048
- --~ vlist = 20136
- --~ rule = 13292
- --~ mark = 4304
- --~ math = 1072
-
- local disc, mark, free = node.id('disc'), node.id('mark'), node.free
-
- local function cleanup_page(head) -- rough
- local prev, start = nil, head
- while start do
- local id, nx = start.id, start.next
- if id == disc or id == mark then
- if prev then
- prev.next = nx
- end
- if start == head then
- head = nx
- end
- local tmp = start
- start = nx
- free(tmp)
- elseif id == hlist or id == vlist then
- local sl = start.list
- if sl then
- start.list = cleanup_page(sl)
- end
- prev, start = start, nx
- else
- prev, start = start, nx
- end
- end
- return head
- end
-
- nodes.cleanup_page = cleanup_page
-
- nodes.cleanup_page_first = false
-
- function nodes.process_page(head)
- if nodes.cleanup_page_first then
- head = cleanup_page(head)
- end
- return process_attributes(head,shipouts.plugins)
- end
-
-end
-
---
--- generic handlers
---
-
-states = { }
-
-do
-
- local glyph, rule, whatsit, hlist, vlist = node.id('glyph'), node.id('rule'), node.id('whatsit'), node.id('hlist'), node.id('vlist')
-
- local has_attribute, copy = node.has_attribute, node.copy
-
- local current, used, done = 0, { }, false
-
- function states.initialize(what, attribute, stack)
- current, used, done = 0, { }, false
- end
-
- local function insert(n,stack,previous,head) -- there is a helper, we need previous because we are not slided
- if n then
- n = copy(n)
- n.next = stack
- if previous then
- previous.next = n
- else
- head = n
- end
- previous = n
- end
- return stack, head
- end
-
- function states.finalize(namespace,attribute,head) -- is this one ok?
- if current > 0 then
- local nn = namespace.none
- if nn then
- local id = head.id
- if id == hlist or id == vlist then
- local list = head.list
- if list then
- local _, h = insert(nn,list,nil,list)
- head.list = h
- end
- else
- stack, head = insert(nn,head,nil,head)
- end
- return head, true, true
- end
- end
- return head, false, false
- end
-
- local function process(namespace,attribute,head,inheritance,default) -- one attribute
- local trigger = namespace.triggering and nodes.triggering and nodes.trigger
- local stack, previous, done = head, nil, false
- local nsdata, nsreviver, nsnone = namespace.data, namespace.reviver, namespace.none
- while stack do
- local id = stack.id
- if id == glyph or id == whatsit or id == rule then -- or disc
- local c = has_attribute(stack,attribute)
- if c then
- if default and c == inheritance then
- if current ~= default then
- local data = nsdata[default] or nsreviver(default)
- stack, head = insert(data,stack,previous,head)
- current, done, used[default] = default, true, true
- end
- elseif current ~= c then
- local data = nsdata[c] or nsreviver(c)
- stack, head = insert(data,stack,previous,head)
- current, done, used[c] = c, true, true
- end
- elseif default and inheritance then
- if current ~= default then
- local data = nsdata[default] or nsreviver(default)
- stack, head = insert(data,stack,previous,head)
- current, done, used[default] = default, true, true
- end
- elseif current > 0 then
- stack, head = insert(nsnone,stack,previous,head)
- current, done, used[0] = 0, true, true
- end
- elseif id == hlist or id == vlist then
- local content = stack.list
- if content then
- local ok = false
- if trigger and has_attribute(stack,trigger) then
- local outer = has_attribute(stack,attribute)
- if outer ~= inheritance then
- stack.list, ok = process(namespace,attribute,content,inheritance,outer)
- else
- stack.list, ok = process(namespace,attribute,content,inheritance,default)
- end
- else
- stack.list, ok = process(namespace,attribute,content,inheritance,default)
- end
- done = done or ok
- end
- end
- previous = stack
- stack = stack.next
- end
- return head, done
- end
-
- states.process = process
-
- -- we can force a selector, e.g. document wide color spaces, saves a little
-
- local function selective(namespace,attribute,head,inheritance,default) -- two attributes
- local trigger = namespace.triggering and nodes.triggering and nodes.trigger
- local stack, previous, done = head, nil, false
- local nsselector, nsforced, nsselector = namespace.default, namespace.forced, namespace.selector
- local nsdata, nsreviver, nsnone = namespace.data, namespace.reviver, namespace.none
- while stack do
- local id = stack.id
- if id == glyph or id == whatsit or id == rule then -- or disc
- -- todo: maybe track two states, also selector
- local c = has_attribute(stack,attribute)
- if c then
- if default and c == inheritance then
- if current ~= default then
- local data = nsdata[default] or nsreviver(default)
- stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
- current, done, used[default] = default, true, true
- end
- elseif current ~= c then
- local data = nsdata[c] or nsreviver(c)
- stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
- current, done, used[c] = c, true, true
- end
- elseif default and inheritance then
- if current ~= default then
- local data = nsdata[default] or nsreviver(default)
- stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
- current, done, used[default] = default, true, true
- end
- elseif current > 0 then
- stack, head = insert(nsnone,stack,previous,head)
- current, done, used[0] = 0, true, true
- end
- elseif id == hlist or id == vlist then
- local content = stack.list
- if content then
- local ok = false
- if trigger and has_attribute(stack,trigger) then
- local outer = has_attribute(stack,attribute)
- if outer ~= inheritance then
- stack.list, ok = selective(namespace,attribute,content,inheritance,outer)
- else
- stack.list, ok = selective(namespace,attribute,content,inheritance,default)
- end
- else
- stack.list, ok = selective(namespace,attribute,content,inheritance,default)
- end
- done = done or ok
- end
- end
- previous = stack
- stack = stack.next
- end
- return head, done
- end
-
- states.selective = selective
-
-end
-
-states = states or { }
-states.collected = states.collected or { }
-
-input.storage.register(false,"states/collected", states.collected, "states.collected")
-
-function states.collect(str)
- local collected = states.collected
- collected[#collected+1] = str
-end
-
-function states.flush()
- local collected = states.collected
- if #collected > 0 then
- for i=1,#collected do
- tex.sprint(tex.ctxcatcodes,collected[i]) -- we're in context mode anyway
- end
- states.collected = { }
- end
-end
-
-function states.check()
- texio.write_nl(concat(states.collected,"\n"))
-end
-
--
-- colors
--
@@ -513,21 +37,9 @@ end
-- at the tex end add 0, 1, 2, but this is not faster and less
-- flexible (since sometimes we freeze color attribute values at
-- the lua end of the game
-
+--
-- we also need to store the colorvalues because we need then in mp
-
-colors = colors or { }
-colors.data = colors.data or { }
-colors.values = colors.values or { }
-colors.registered = colors.registered or { }
-colors.enabled = true
-colors.weightgray = true
-colors.attribute = 0
-colors.selector = 0
-colors.default = 1
-colors.main = nil
-colors.triggering = true
-
+--
-- This is a compromis between speed and simplicity. We used to store the
-- values and data in one array, which made in neccessary to store the
-- converters that need node constructor into strings and evaluate them
@@ -539,21 +51,34 @@ colors.triggering = true
-- colors.strings[color] = "return colors." .. colorspace .. "(" .. concat({...},",") .. ")"
-- end
--
--- input.storage.register(true,"colors/data", colors.strings, "colors.data") -- evaluated
+-- storage.register("colors/data", colors.strings, "colors.data") -- evaluated
--
-- We assume that only processcolors are defined in the format.
-input.storage.register(false,"colors/values", colors.values, "colors.values")
-input.storage.register(false,"colors/registered", colors.registered, "colors.registered")
+colors = colors or { }
+colors.data = colors.data or { }
+colors.values = colors.values or { }
+colors.registered = colors.registered or { }
-colors.stamps = {
+colors.enabled = true
+colors.weightgray = true
+colors.attribute = attributes.private('color')
+colors.selector = attributes.private('colormodel')
+colors.default = 1
+colors.main = nil
+colors.triggering = true
+
+storage.register("colors/values", colors.values, "colors.values")
+storage.register("colors/registered", colors.registered, "colors.registered")
+
+local templates = {
rgb = "r:%s:%s:%s",
cmyk = "c:%s:%s:%s:%s",
gray = "s:%s",
spot = "p:%s:%s:%s:%s"
}
-colors.models = {
+local models = {
all = 1,
gray = 2,
rgb = 3,
@@ -562,324 +87,469 @@ colors.models = {
colors.model = "all"
-do
+local data = colors.data
+local values = colors.values
+local registered = colors.registered
- local min = math.min
- local max = math.max
+local numbers = attributes.numbers
+local list = attributes.list
- local function rgbdata(r,g,b) -- dodo: backends.pdf.rgbdata
- return backends.pdf.literal(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b))
- end
+local min = math.min
+local max = math.max
- local function cmykdata(c,m,y,k)
- return backends.pdf.literal(format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k))
- end
+local nodeinjections = backends.nodeinjections
+local codeinjections = backends.codeinjections
+local registrations = backends.registrations
- local function graydata(s)
- return backends.pdf.literal(format("%s g %s G",s,s))
- end
+local function rgbtocmyk(r,g,b) -- we could reduce
+ return 1-r, 1-g, 1-b, 0
+end
- local function spotdata(n,f,d,p)
- if type(p) == "string" then
- p = p:gsub(","," ") -- brr misuse of spot
- end
- return backends.pdf.literal(format("/%s cs /%s CS %s SCN %s scn",n,n,p,p))
- end
+local function cmyktorgb(c,m,y,k)
+ return 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k)
+end
- local function rgbtocmyk(r,g,b) -- we could reduce
- return 1-r, 1-g, 1-b, 0
+local function rgbtogray(r,g,b)
+ if colors.weightgray then
+ return .30*r+.59*g+.11*b
+ else
+ return r/3+g/3+b/3
end
+end
- local function cmyktorgb(c,m,y,k)
- return 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k)
- end
+local function cmyktogray(c,m,y,k)
+ return rgbtogray(cmyktorgb(c,m,y,k))
+end
- local function rgbtogray(r,g,b)
- if colors.weightgray then
- return .30*r+.59*g+.11*b
- else
- return r/3+g/3+b/3
- end
- end
+colors.rgbtocmyk = rgbtocmyk
+colors.rgbtogray = rgbtogray
+colors.cmyktorgb = cmyktorgb
+colors.cmyktogray = cmyktogray
- local function cmyktogray(c,m,y,k)
- return rgbtogray(cmyktorgb(c,m,y,k))
- end
+-- we can share some *data by using s, rgb and cmyk hashes, but
+-- normally the amount of colors is not that large; storing the
+-- components costs a bit of extra runtime, but we expect to gain
+-- some back because we have them at hand; the number indicates the
+-- default color space
- colors.rgbtocmyk = rgbtocmyk
- colors.rgbtogray = rgbtogray
- colors.cmyktorgb = cmyktorgb
- colors.cmyktogray = cmyktogray
+function colors.gray(s)
+ return { 2, s, s, s, s, 0, 0, 0, 1-s }
+end
- -- we can share some *data by using s, rgb and cmyk hashes, but
- -- normally the amount of colors is not that large; storing the
- -- components costs a bit of extra runtime, but we expect to gain
- -- some back because we have them at hand; the number indicates the
- -- default color space
+function colors.rgb(r,g,b)
+ local s = rgbtogray(r,g,b)
+ local c, m, y, k = rgbtocmyk(r,g,b)
+ return { 3, s, r, g, b, c, m, y, k }
+end
- function colors.gray(s)
- return { 2, s, s, s, s, 0, 0, 0, 1-s }
- end
+function colors.cmyk(c,m,y,k)
+ local s = cmyktogray(c,m,y,k)
+ local r, g, b = cmyktorgb(c,m,y,k)
+ return { 4, s, r, g, b, c, m, y, k }
+end
- function colors.rgb(r,g,b)
- local s = rgbtogray(r,g,b)
- local c, m, y, k = rgbtocmyk(r,g,b)
- return { 3, s, r, g, b, c, m, y, k }
- end
+--~ function colors.spot(parent,f,d,p)
+--~ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+--~ end
- function colors.cmyk(c,m,y,k)
- local s = cmyktogray(c,m,y,k)
- local r, g, b = cmyktorgb(c,m,y,k)
- return { 4, s, r, g, b, c, m, y, k }
+function colors.spot(parent,f,d,p)
+ if type(p) == "number" then
+ local n = list[numbers.color][parent] -- hard coded ref to color number
+ if n then
+ local v = values[n]
+ if v then
+ -- the via cmyk hack is dirty, but it scales better
+ local c, m, y, k = p*v[6], p*v[7], p*v[8], p*v[8]
+ local r, g, b = cmyktorgb(c,m,y,k)
+ local s = cmyktogray(c,m,y,k)
+ return { 5, s, r, g, b, c, m, y, k, parent, f, d, p }
+ end
+ end
+ else
+ -- todo, multitone (maybe p should be a table)
end
+ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+end
- function colors.spot(parent,f,d,p)
---~ if type(p) == "string" and p:find(",") then
---~ -- use converted replacement (combination color)
---~ else
---~ -- todo: map gray, rgb, cmyk onto fraction*parent
---~ end
- return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
- end
+local function graycolor(...) graycolor = nodeinjections.graycolor return graycolor(...) end
+local function rgbcolor (...) rgbcolor = nodeinjections.rgbcolor return rgbcolor (...) end
+local function cmykcolor(...) cmykcolor = nodeinjections.cmykcolor return cmykcolor(...) end
+local function spotcolor(...) spotcolor = nodeinjections.spotcolor return spotcolor(...) end
- function colors.reviver(n)
- local d = colors.data[n]
- if not d then
- local v = colors.values[n]
- if not v then
- local gray = graydata(0)
- d = { gray, gray, gray, gray }
- logs.report("attributes",format("unable to revive color %s",n or "?"))
- else
- local kind, gray, rgb, cmyk = v[1], graydata(v[2]), rgbdata(v[3],v[4],v[5]), cmykdata(v[6],v[7],v[8],v[9])
- if kind == 2 then
- d = { gray, gray, gray, gray }
- elseif kind == 3 then
- d = { rgb, gray, rgb, cmyk }
- elseif kind == 4 then
- d = { cmyk, gray, rgb, cmyk }
- elseif kind == 5 then
- local spot = spotdata(v[10],v[11],v[12],v[13])
- d = { spot, gray, rgb, cmyk }
- end
- end
- colors.data[n] = d
- end
+local function extender(colors,key)
+ if key == "none" then
+ local d = graycolor(0)
+ colors.none = d
return d
end
+end
- function colors.filter(n)
- return concat(colors.data[n],":",5)
+local function reviver(data,n)
+ local v = values[n]
+ local d
+ if not v then
+ local gray = graycolor(0)
+ d = { gray, gray, gray, gray }
+ logs.report("attributes","unable to revive color %s",n or "?")
+ else
+ local kind, gray, rgb, cmyk = v[1], graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9])
+ if kind == 2 then
+ d = { gray, gray, gray, gray }
+ elseif kind == 3 then
+ d = { rgb, gray, rgb, cmyk }
+ elseif kind == 4 then
+ d = { cmyk, gray, rgb, cmyk }
+ elseif kind == 5 then
+ local spot = spotcolor(v[10],v[11],v[12],v[13])
+ d = { spot, gray, rgb, cmyk }
+ end
end
+ data[n] = d
+ return d
+end
- colors.none = graydata(0)
+setmetatable(colors, { __index = extender })
+setmetatable(colors.data, { __index = reviver })
+function colors.filter(n)
+ return concat(data[n],":",5)
end
-function colors.setmodel(attribute,name)
+function colors.setmodel(name,weightgray)
colors.model = name
- colors.selector = attributes.numbers[attribute]
- colors.default = colors.models[name] or 1
+ colors.default = models[name] or 1
+ colors.weightgray = weightgray ~= false
return colors.default
end
-function colors.register(attribute, name, colorspace, ...) -- passing 9 vars is faster
- local stamp = format(colors.stamps[colorspace], ...)
- local color = colors.registered[stamp]
+function colors.register(name, colorspace, ...) -- passing 9 vars is faster (but not called that often)
+ local stamp = format(templates[colorspace],...)
+ local color = registered[stamp]
if not color then
- color = #colors.values+1
- colors.values[color] = colors[colorspace](...)
- colors.registered[stamp] = color
- colors.reviver(color)
+ color = #values+1
+ values[color] = colors[colorspace](...)
+ registered[stamp] = color
+ -- colors.reviver(color)
end
if name then
- attributes.list[attributes.numbers[attribute]][name] = color -- not grouped, so only global colors
+ list[colors.attribute][name] = color -- not grouped, so only global colors
end
- return colors.registered[stamp]
+ return registered[stamp]
end
function colors.value(id)
- return colors.values[id]
+ return values[id]
end
-shipouts.plugins.color = {
+shipouts.handle_color = nodes.install_attribute_handler {
+ name = "color",
namespace = colors,
initializer = states.initialize,
finalizer = states.finalize,
processor = states.selective,
- resolver = function(...) return colors.main end,
+ resolver = function() return colors.main end,
}
-- transparencies
--- for the moment we manage transparencies in the pdf driver because
--- first we need a nice interface to some pdf things
-
transparencies = transparencies or { }
transparencies.registered = transparencies.registered or { }
transparencies.data = transparencies.data or { }
transparencies.values = transparencies.values or { }
transparencies.enabled = false
-transparencies.template = "%s:%s"
transparencies.triggering = true
+transparencies.attribute = attributes.private('transparency')
+
+storage.register("transparencies/registered", transparencies.registered, "transparencies.registered")
+storage.register("transparencies/values", transparencies.values, "transparencies.values")
-input.storage.register(false, "transparencies/registered", transparencies.registered, "transparencies.registered")
-input.storage.register(false, "transparencies/values", transparencies.values, "transparencies.values")
+local registered = transparencies.registered -- we could use a 2 dimensional table instead
+local data = transparencies.data
+local values = transparencies.values
+local template = "%s:%s"
+
+local function inject_transparency (...)
+ inject_transparency = nodeinjections.transparency
+ return inject_transparency(...)
+end
-function transparencies.reference(n)
- return backends.pdf.literal(format("/Tr%s gs",n))
+local function register_transparency(...)
+ register_transparency = registrations.transparency
+ return register_transparency(...)
end
-function transparencies.register(name,a,t)
- local stamp = format(transparencies.template,a,t)
- local n = transparencies.registered[stamp]
+function transparencies.register(name,a,t,force) -- name is irrelevant here (can even be nil)
+ -- Force needed here for metapost converter. We could always force
+ -- but then we'd end up with transparencies resources even if we
+ -- would not use transparencies (but define them only). This is
+ -- somewhat messy.
+ local stamp = format(template,a,t)
+ local n = registered[stamp]
if not n then
- n = #transparencies.data+1
- transparencies.data[n] = transparencies.reference(n)
- transparencies.values[n] = { a, t }
- transparencies.registered[stamp] = n
- states.collect(format("\\presetPDFtransparencybynumber{%s}{%s}{%s}",n,a,t)) -- too many, but experimental anyway
- end
- return transparencies.registered[stamp]
-end
-
-function transparencies.reviver(n)
- local d = transparencies.data[n]
- if not d then
- local v = transparencies.values[n]
- if not v then
- d = transparencies.reference(0)
- logs.report("attributes",format("unable to revive transparency %s",n or "?"))
- else
- d = transparencies.reference(n)
- states.collect(format("\\presetPDFtransparencybynumber{%s}{%s}{%s}",n,v[1],v[2]))
+ n = #values + 1
+ values[n] = { a, t }
+ registered[stamp] = n
+ if force then
+ register_transparency(n,a,t)
end
- transparencies.data[n] = d
+ elseif force and not data[n] then
+ register_transparency(n,a,t)
end
- return d
+ return registered[stamp]
end
--- check if there is an identity
+local function extender(transparencies,key)
+ if key == "none" then
+ local d = inject_transparency(0)
+ transparencies.none = d
+ return d
+ end
+end
---~ transparencies.none = transparencies.reference(transparencies.register(nil,1,1))
+local function reviver(data,n)
+ local v = values[n]
+ local d
+ if not v then
+ d = inject_transparency(0)
+ else
+ d = inject_transparency(n)
+ register_transparency(n,v[1],v[2])
+ end
+ data[n] = d
+ return d
+end
+
+setmetatable(transparencies, { __index = extender })
+setmetatable(transparencies.data, { __index = reviver }) -- register if used
-transparencies.none = transparencies.reference(0) -- for the moment the pdf backend does this
+-- check if there is an identity
function transparencies.value(id)
- return transparencies.values[id]
+ return values[id]
end
-shipouts.plugins.transparency = {
+shipouts.handle_transparency = nodes.install_attribute_handler {
+ name = "transparency",
namespace = transparencies,
initializer = states.initialize,
- finalizer = states.finalize ,
- processor = states.process ,
+ finalizer = states.finalize,
+ processor = states.process,
}
--- overprint / knockout
-overprints = overprints or { }
-overprints.data = overprints.data or { }
-overprints.enabled = false
-
-overprints.data[1] = backends.pdf.literal(format("/GSoverprint gs"))
-overprints.data[2] = backends.pdf.literal(format("/GSknockout gs"))
-
-overprints.none = overprints.data[1]
+overprints = overprints or { }
+overprints.data = overprints.data or { }
+overprints.enabled = false
+overprints.attribute = attributes.private('overprint')
overprints.registered = {
overprint = 1,
knockout = 2,
}
+local data, registered = overprints.data, overprints.registered
+
+local function extender(overprints,key)
+ if key == "none" then
+ local d = data[2]
+ overprints.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ if n == 1 then
+ local d = nodeinjections.overprint() -- called once
+ data[1] = d
+ return d
+ elseif n == 2 then
+ local d = nodeinjections.knockout() -- called once
+ data[2] = d
+ return d
+ end
+end
+
+setmetatable(overprints, { __index = extender })
+setmetatable(overprints.data, { __index = reviver })
+
function overprints.register(stamp)
--- states.collect(tex.sprint(tex.ctxcatcodes,"\\initializePDFoverprint")) -- to be testd
- return overprints.registered[stamp] or overprints.registered.overprint
+ return registered[stamp] or registered.overprint
end
-shipouts.plugins.overprint = {
+shipouts.handle_overprint = nodes.install_attribute_handler {
+ name = "overprint",
namespace = overprints,
initializer = states.initialize,
- finalizer = states.finalize ,
- processor = states.process ,
+ finalizer = states.finalize,
+ processor = states.process,
}
--- negative / positive
-negatives = netatives or { }
-negatives.data = negatives.data or { }
-negatives.enabled = false
-
-negatives.data[1] = backends.pdf.literal(format("/GSpositive gs"))
-negatives.data[2] = backends.pdf.literal(format("/GSnegative gs"))
-
-negatives.none = negatives.data[1]
+negatives = negatives or { }
+negatives.data = negatives.data or { }
+negatives.enabled = false
+negatives.attribute = attributes.private("negative")
negatives.registered = {
positive = 1,
negative = 2,
}
+local data, registered = negatives.data, negatives.registered
+
+local function extender(negatives,key)
+ if key == "none" then
+ local d = data[1]
+ negatives.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ if n == 1 then
+ local d = nodeinjections.positive() -- called once
+ data[1] = d
+ return d
+ elseif n == 2 then
+ local d = nodeinjections.negative() -- called once
+ data[2] = d
+ return d
+ end
+end
+
+setmetatable(negatives, { __index = extender })
+setmetatable(negatives.data, { __index = reviver })
+
function negatives.register(stamp)
--- states.collect(tex.sprint(tex.ctxcatcodes,"\\initializePDFnegative")) -- to be testd
- return negatives.registered[stamp] or negatives.registered.positive
+ return registered[stamp] or registered.positive
end
-shipouts.plugins.negative = {
+shipouts.handle_negative = nodes.install_attribute_handler {
+ name = "negative",
namespace = negatives,
initializer = states.initialize,
finalizer = states.finalize,
processor = states.process,
}
--- effects
+-- effects -- can be optimized (todo: metatables)
effects = effects or { }
effects.data = effects.data or { }
+effects.values = effects.values or { }
effects.registered = effects.registered or { }
effects.enabled = false
effects.stamp = "%s:%s:%s"
+effects.attribute = attributes.private("effect")
-input.storage.register(false, "effects/registered", effects.registered, "effects.registered")
-input.storage.register(false, "effects/data", effects.data, "effects.data")
+storage.register("effects/registered", effects.registered, "effects.registered")
+storage.register("effects/values", effects.values, "effects.values")
-function effects.register(effect,stretch,rulethickness)
- local stamp = format(effects.stamp,effect,stretch,rulethickness)
- local n = effects.registered[stamp]
- if not n then
- n = #effects.data+1
- effects.data[n] = effects.reference(effect,stretch,rulethickness)
- effects.registered[stamp] = n
- -- states.collect("") -- nothing
+local data, registered, values = effects.data, effects.registered, effects.values
+
+-- valid effects: normal inner outer both hidden (stretch,rulethickness,effect)
+
+local function effect(...) effect = nodeinjections.effect return effect(...) end
+
+local function extender(effects,key)
+ if key == "none" then
+ local d = effect(0,0,0)
+ effects.none = d
+ return d
end
- return effects.registered[stamp]
end
-backends.pdf.effects = {
- normal = 0,
- inner = 0,
- outer = 1,
- both = 2,
- hidden = 3,
-}
-
-function effects.reference(effect,stretch,rulethickness)
- -- always, no zero test (removed)
- rulethickness = number.dimenfactors["bp"]*rulethickness
- effect = backends.pdf.effects[effect] or backends.pdf.effects['normal']
- return backends.pdf.literal(format("%s Tc %s w %s Tr",stretch,rulethickness,effect)) -- watch order
+local function reviver(data,n)
+ local e = values[n] -- we could nil values[n] now but hardly needed
+ local d = effect(v[1],v[2],v[3])
+ data[n] = d
+ return d
end
-effects.none = effects.reference(0,0,0) -- faster: backends.pdf.literal("0 Tc 0 w 0 Tr")
+setmetatable(effects, { __index = extender })
+setmetatable(effects.data, { __index = reviver })
+
+function effects.register(effect,stretch,rulethickness)
+ local stamp = format(effects.stamp,effect,stretch,rulethickness)
+ local n = registered[stamp]
+ if not n then
+ n = #values + 1
+ values[n] = { effect, stretch, rulethickness }
+ registered[stamp] = n
+ end
+ return n
+end
-shipouts.plugins.effect = {
+shipouts.handle_effect = nodes.install_attribute_handler {
+ name = "effect",
namespace = effects,
initializer = states.initialize,
finalizer = states.finalize,
processor = states.process,
}
--- layers
+-- layers (ugly code, due to no grouping and such); currently we use exclusive layers
+-- but when we need it stacked layers might show up too; the next function based
+-- approach can be replaced by static (metatable driven) resolvers
+
+viewerlayers = viewerlayers or { }
+viewerlayers.data = viewerlayers.data or { }
+viewerlayers.registered = viewerlayers.registered or { }
+viewerlayers.values = viewerlayers.values or { }
+viewerlayers.listwise = viewerlayers.listwise or { }
+viewerlayers.enabled = false
+viewerlayers.attribute = attributes.private("viewerlayer")
+
+storage.register("viewerlayers/registered", viewerlayers.registered, "viewerlayers.registered")
+storage.register("viewerlayers/values", viewerlayers.values, "viewerlayers.values")
+
+local data = viewerlayers.data
+local values = viewerlayers.values
+local listwise = viewerlayers.listwise
+local registered = viewerlayers.registered
+local template = "%s"
+
+-- stacked
+
+local function extender(viewerlayers,key)
+ if key == "none" then
+ local d = nodeinjections.stoplayer()
+ viewerlayers.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ local d = nodeinjections.startlayer(values[n])
+ data[n] = d
+ return d
+end
---~ /OC /somename BDC
---~ EMC
+setmetatable(viewerlayers, { __index = extender })
+setmetatable(viewerlayers.data, { __index = reviver })
+
+local function initializer(...)
+ return states.initialize(...)
+end
+
+viewerlayers.register = function(name,lw) -- if not inimode redefine data[n] in first call
+ local stamp = format(template,name)
+ local n = registered[stamp]
+ if not n then
+ n = #values + 1
+ values[n] = name
+ registered[stamp] = n
+ listwise[n] = lw or false
+ end
+ return registered[stamp] -- == n
+end
+
+shipouts.handle_viewerlayer = nodes.install_attribute_handler {
+ name = "viewerlayer",
+ namespace = viewerlayers,
+ initializer = initializer,
+ finalizer = states.finalize,
+ processor = states.stacked,
+}