diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/attr-ini.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/attr-ini.lua | 690 |
1 files changed, 74 insertions, 616 deletions
diff --git a/Master/texmf-dist/tex/context/base/attr-ini.lua b/Master/texmf-dist/tex/context/base/attr-ini.lua index 81c2f4744ca..96d7c7228c7 100644 --- a/Master/texmf-dist/tex/context/base/attr-ini.lua +++ b/Master/texmf-dist/tex/context/base/attr-ini.lua @@ -6,643 +6,101 @@ if not modules then modules = { } end modules ['attr-ini'] = { license = "see context related readme files" } --- this module is being reconstructed --- we can also do the nsnone via a metatable and then also se index 0 +local next, type = next, type -local type = type -local format, gmatch = string.format, string.gmatch -local concat = table.concat -local texsprint = tex.sprint +--[[ldx-- +<p>We start with a registration system for atributes so that we can use the +symbolic names later on.</p> +--ldx]]-- -local ctxcatcodes = tex.ctxcatcodes -local unsetvalue = attributes.unsetvalue +attributes = attributes or { } --- todo: document this but first reimplement this as it reflects the early --- days of luatex / mkiv and we have better ways now +local attributes, nodes = attributes, nodes --- nb: attributes: color etc is much slower than normal (marks + literals) but ... --- nb. too many "0 g"s +-- todo: local and then gobals ... first loaded anyway -nodes = nodes or { } -states = states or { } -shipouts = shipouts or { } +attributes.names = attributes.names or { } +attributes.numbers = attributes.numbers or { } +attributes.list = attributes.list or { } +attributes.states = attributes.states or { } +attributes.handlers = attributes.handlers or { } +attributes.unsetvalue = -0x7FFFFFFF --- 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. +local names, numbers, list = attributes.names, attributes.numbers, attributes.list --- --- colors --- - --- we can also collapse the two attributes: n, n+1, n+2 and then --- 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 --- --- 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 --- at runtime (after reading from storage). Think of: --- --- colors.strings = colors.strings or { } --- --- if environment.initex then --- colors.strings[color] = "return colors." .. colorspace .. "(" .. concat({...},",") .. ")" --- end --- --- storage.register("colors/data", colors.strings, "colors.data") -- evaluated --- --- We assume that only processcolors are defined in the format. - -colors = colors or { } -colors.data = colors.data or { } -colors.values = colors.values or { } -colors.registered = colors.registered or { } - -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" -} - -local models = { - [interfaces.variables.none] = unsetvalue, - black = unsetvalue, - bw = unsetvalue, - all = 1, - gray = 2, - rgb = 3, - cmyk = 4, -} - -colors.model = "all" - -local data = colors.data -local values = colors.values -local registered = colors.registered - -local numbers = attributes.numbers -local list = attributes.list - -local min, max, floor = math.min, math.max, math.floor - -local nodeinjections = backends.nodeinjections -local codeinjections = backends.codeinjections -local registrations = backends.registrations - -local function rgbtocmyk(r,g,b) -- we could reduce - return 1-r, 1-g, 1-b, 0 -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 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 cmyktogray(c,m,y,k) - return rgbtogray(cmyktorgb(c,m,y,k)) -end - --- http://en.wikipedia.org/wiki/HSI_color_space --- http://nl.wikipedia.org/wiki/HSV_(kleurruimte) - - -local function hsvtorgb(h,s,v) - -- h = h % 360 - local hd = h/60 - local hf = floor(hd) - local hi = hf % 6 - -- local f = hd - hi - local f = hd - hf - local p = v * (1 - s) - local q = v * (1 - f * s) - local t = v * (1 - (1 - f) * s) - if hi == 0 then - return v, t, p - elseif hi == 1 then - return q, v, p - elseif hi == 2 then - return p, v, t - elseif hi == 3 then - return p, q, v - elseif hi == 4 then - return t, p, v - elseif hi == 5 then - return v, p, q - else - print("error in hsv -> rgb",hi,h,s,v) - end -end - -function rgbtohsv(r,g,b) - local offset, maximum, other_1, other_2 - if r >= g and r >= b then - offset, maximum, other_1, other_2 = 0, r, g, b - elseif g >= r and g >= b then - offset, maximum, other_1, other_2 = 2, g, b, r - else - offset, maximum, other_1, other_2 = 4, b, r, g - end - if maximum == 0 then - return 0, 0, 0 - end - local minimum = other_1 < other_2 and other_1 or other_2 - if maximum == minimum then - return 0, 0, maximum - end - local delta = maximum - minimum - return (offset + (other_1-other_2)/delta)*60, delta/maximum, maximum -end - -function graytorgb(s) -- unweighted - return 1-s, 1-s, 1-s -end +storage.register("attributes/names", names, "attributes.names") +storage.register("attributes/numbers", numbers, "attributes.numbers") +storage.register("attributes/list", list, "attributes.list") -function hsvtogray(h,s,v) - return rgb_to_gray(hsv_to_rgb(h,s,v)) -end - -function grayto_hsv(s) - return 0, 0, s -end - -colors.rgbtocmyk = rgbtocmyk -colors.rgbtogray = rgbtogray -colors.cmyktorgb = cmyktorgb -colors.cmyktogray = cmyktogray -colors.rgbtohsv = rgbtohsv -colors.hsvtorgb = hsvtorgb -colors.hsvtogray = hsvtogray -colors.graytohsv = graytohsv - --- 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.gray(s) - return { 2, s, s, s, s, 0, 0, 0, 1-s } -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.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.spot(parent,f,d,p) ---~ 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) == "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) +function attributes.define(name,number) -- at the tex end + if not numbers[name] then + numbers[name], names[number], list[number] = number, name, { } 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 +--[[ldx-- +<p>We can use the attributes in the range 127-255 (outside user space). These +are only used when no attribute is set at the \TEX\ end which normally +happens in <l n='context'/>.</p> +--ldx]]-- -local function extender(colors,key) - if key == "none" then - local d = graycolor(0) - colors.none = d - return d - end -end +storage.shared.attributes_last_private = storage.shared.attributes_last_private or 127 -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 = v[1] - if kind == 2 then - local gray= graycolor(v[2]) - d = { gray, gray, gray, gray } - elseif kind == 3 then - local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9]) - d = { rgb, gray, rgb, cmyk } - elseif kind == 4 then - local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9]) - 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 } - d = { spot, spot, spot, spot } +-- to be considered (so that we can use an array access): +-- +-- local private = { } attributes.private = private +-- +-- setmetatable(private, { +-- __index = function(t,name) +-- local number = storage.shared.attributes_last_private or 127 +-- if number < 1023 then -- tex.count.minallocatedattribute - 1 +-- number = number + 1 +-- storage.shared.attributes_last_private = number +-- end +-- numbers[name], names[number], list[number] = number, name, { } +-- private[name] = number +-- return number +-- end, +-- __call = function(t,name) +-- return t[name] +-- end +-- } ) + +function attributes.private(name) -- at the lua end (hidden from user) + local number = numbers[name] + if not number then + local last = storage.shared.attributes_last_private or 127 + if last < 1023 then -- tex.count.minallocatedattribute - 1 + last = last + 1 + storage.shared.attributes_last_private = last + else + report_attribute("no more room for private attributes") -- fatal + os.exit() end + number = last + numbers[name], names[number], list[number] = number, name, { } end - data[n] = d - return d -end - -setmetatable(colors, { __index = extender }) -setmetatable(colors.data, { __index = reviver }) - -function colors.filter(n) - return concat(data[n],":",5) -end - -function colors.setmodel(name,weightgray) - colors.model = name - colors.default = models[name] or 1 - colors.weightgray = weightgray ~= false - return colors.default -end - -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 = #values + 1 - values[color] = colors[colorspace](...) - registered[stamp] = color - -- colors.reviver(color) - end - if name then - list[colors.attribute][name] = color -- not grouped, so only global colors - end - return registered[stamp] + return number end -function colors.value(id) - return values[id] -end - -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, -} - -function colors.enable() - tasks.enableaction("shipouts","shipouts.handle_color") -end +-- new (actually a tracer) --- transparencies - -transparencies = transparencies or { } -transparencies.registered = transparencies.registered or { } -transparencies.data = transparencies.data or { } -transparencies.values = transparencies.values or { } -transparencies.triggering = true -transparencies.attribute = attributes.private('transparency') - -storage.register("transparencies/registered", transparencies.registered, "transparencies.registered") -storage.register("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 - -local function register_transparency(...) - register_transparency = registrations.transparency - return register_transparency(...) -end - -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 = #values + 1 - values[n] = { a, t } - registered[stamp] = n - if force then - register_transparency(n,a,t) +function attributes.ofnode(n) + local a = n.attr + if a then + a = a.next + while a do + local number, value = a.number, a.value + texio.write_nl(format("%s : attribute %3i, value %4i, name %s",tostring(n),number,value,names[number] or '?')) + a = a.next end - elseif force and not data[n] then - register_transparency(n,a,t) - end - return registered[stamp] -end - -local function extender(transparencies,key) - if key == "none" then - local d = inject_transparency(0) - transparencies.none = d - return d - end -end - -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 - --- check if there is an identity - -function transparencies.value(id) - return values[id] -end - -shipouts.handle_transparency = nodes.install_attribute_handler { - name = "transparency", - namespace = transparencies, - initializer = states.initialize, - finalizer = states.finalize, - processor = states.process, -} - -function transparencies.enable() - tasks.enableaction("shipouts","shipouts.handle_transparency") -end - ---- colorintents: overprint / knockout - -colorintents = colorintents or { } -colorintents.data = colorintents.data or { } -colorintents.attribute = attributes.private('colorintent') - -colorintents.registered = { - overprint = 1, - knockout = 2, -} - -local data, registered = colorintents.data, colorintents.registered - -local function extender(colorintents,key) - if key == "none" then - local d = data[2] - colorintents.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(colorintents, { __index = extender }) -setmetatable(colorintents.data, { __index = reviver }) - -function colorintents.register(stamp) - return registered[stamp] or registered.overprint -end - -shipouts.handle_colorintent = nodes.install_attribute_handler { - name = "colorintent", - namespace = colorintents, - initializer = states.initialize, - finalizer = states.finalize, - processor = states.process, -} - -function colorintents.enable() - tasks.enableaction("shipouts","shipouts.handle_colorintent") -end - ---- negative / positive - -negatives = negatives or { } -negatives.data = negatives.data or { } -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 end -setmetatable(negatives, { __index = extender }) -setmetatable(negatives.data, { __index = reviver }) +-- interface -function negatives.register(stamp) - return registered[stamp] or registered.positive -end - -shipouts.handle_negative = nodes.install_attribute_handler { - name = "negative", - namespace = negatives, - initializer = states.initialize, - finalizer = states.finalize, - processor = states.process, -} - -function negatives.enable() - tasks.enableaction("shipouts","shipouts.handle_negative") -end - --- 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.stamp = "%s:%s:%s" -effects.attribute = attributes.private("effect") - -storage.register("effects/registered", effects.registered, "effects.registered") -storage.register("effects/values", effects.values, "effects.values") - -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 -end - -local function reviver(data,n) - local e = values[n] -- we could nil values[n] now but hardly needed - local d = effect(e[1],e[2],e[3]) - data[n] = d - return d -end - -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.handle_effect = nodes.install_attribute_handler { - name = "effect", - namespace = effects, - initializer = states.initialize, - finalizer = states.finalize, - processor = states.process, -} - -function effects.enable() - tasks.enableaction("shipouts","shipouts.handle_effect") -end - --- 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.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 - -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, -} +commands.defineattribute = attributes.define -function viewerlayers.enable() - tasks.enableaction("shipouts","shipouts.handle_viewerlayer") +function commands.getprivateattribute(name) + context(attributes.private(name)) end |