summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-ogr.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/font-ogr.lua')
-rw-r--r--tex/context/base/mkiv/font-ogr.lua381
1 files changed, 381 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/font-ogr.lua b/tex/context/base/mkiv/font-ogr.lua
new file mode 100644
index 000000000..c441ddbf7
--- /dev/null
+++ b/tex/context/base/mkiv/font-ogr.lua
@@ -0,0 +1,381 @@
+if not modules then modules = { } end modules ['font-ogr'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Here we deal with graphic variants and for now also color support ends up here
+-- but that might change. It's lmtx only code.
+
+if not context then
+ return
+elseif CONTEXTLMTXMODE == 0 then
+ return
+end
+
+local tostring, tonumber, next = tostring, tonumber, next
+local round, max, mod, div = math.round, math.round, math.mod, math.div
+local concat, setmetatableindex = table.concat, table.setmetatableindex
+local formatters = string.formatters
+
+local otf = fonts.handlers.otf
+local otfregister = otf.features.register
+otf.svgenabled = true
+otf.pngenabled = true
+
+-- Just to remind me ... rewritten around the time this was posted on YT which
+-- was also around the 2019 ctx meeting:
+--
+-- Gavin Harrison - "Threatening War" by The Pineapple Thief
+-- https://www.youtube.com/watch?v=ENF9wth4kwM
+
+-- todo: svg color plugin
+-- todo: get rid of double cm in svg (tricky as also elsewhere)
+-- todo: png offsets (depth)
+-- todo: maybe collapse indices so that we have less files (harder to debug)
+-- todo: manage (read: assign) font id's in lua so we know in advance
+
+do
+
+ -- This is a prelude to something better but I'm still experimenting.
+
+ local dropins = { }
+ fonts.dropins = dropins
+ local droppedin = 0
+ local identifiers = fonts.hashes.identifiers
+
+ function dropins.nextid()
+ droppedin = droppedin - 1
+ return droppedin
+ end
+
+ function dropins.provide(method,clone,t_tfmdata,indexdata,...)
+ droppedin = dropins.nextid()
+ local t_characters = t_tfmdata.characters
+ local t_descriptions = t_tfmdata.descriptions
+ local t_properties = t_tfmdata.properties
+ local d_tfmdata = setmetatableindex({ },t_tfmdata)
+ local d_properties = setmetatableindex({ },t_properties)
+ d_tfmdata.properties = d_properties
+ if clone then
+ local d_characters = setmetatableindex({ },t_characters)
+ local d_descriptions = setmetatableindex({ },t_descriptions)
+ d_tfmdata.characters = d_characters
+ d_tfmdata.descriptions = d_descriptions
+ end
+ d_properties.instance = - droppedin -- will become an extra element in the hash
+ t_properties.virtualized = true
+ identifiers[droppedin] = d_tfmdata
+ local fonts = t_tfmdata.fonts or { }
+ t_tfmdata.fonts = fonts
+ d_properties.format = "type3"
+ d_properties.method = method
+ d_properties.indexdata = { indexdata, ... } -- can take quite some memory
+ local slot = #fonts + 1
+ fonts[slot] = { id = droppedin }
+ if not clone then
+ for k, v in next, t_characters do
+ local index = v.index
+ if index and indexdata[index] then
+ -- todo: use extender
+ v.commands = { { "slot", slot, k } }
+ end
+ end
+ else
+ -- make sure that the drop characters should get a copy with no commands
+ -- (false will do)
+ end
+ return slot, droppedin, d_tfmdata, d_properties
+ end
+
+end
+
+-- This sits here for historcal reasons so for now we keep it here.
+
+local startactualtext = nil
+local stopactualtext = nil
+
+function otf.getactualtext(s)
+ if not startactualtext then
+ startactualtext = backends.codeinjections.startunicodetoactualtextdirect
+ stopactualtext = backends.codeinjections.stopunicodetoactualtextdirect
+ end
+ return startactualtext(s), stopactualtext()
+end
+
+-- This is also somewhat specific.
+
+local sharedpalettes do
+
+ sharedpalettes = { }
+
+ local colors = attributes.list[attributes.private('color')] or { }
+ local transparencies = attributes.list[attributes.private('transparency')] or { }
+
+ function otf.registerpalette(name,values)
+ sharedpalettes[name] = values
+ local color = lpdf.color
+ local transparency = lpdf.transparency
+ local register = colors.register
+ for i=1,#values do
+ local v = values[i]
+ if v == "textcolor" then
+ values[i] = false
+ else
+ local c = nil
+ local t = nil
+ if type(v) == "table" then
+ c = register(name,"rgb",
+ max(round((v.r or 0)*255),255)/255,
+ max(round((v.g or 0)*255),255)/255,
+ max(round((v.b or 0)*255),255)/255
+ )
+ else
+ c = colors[v]
+ t = transparencies[v]
+ end
+ if c and t then
+ values[i] = color(1,c) .. " " .. transparency(t)
+ elseif c then
+ values[i] = color(1,c)
+ elseif t then
+ values[i] = color(1,t)
+ end
+ end
+ end
+ end
+
+end
+
+do
+
+ local f_color = formatters["%.3f %.3f %.3f rg"]
+ local f_gray = formatters["%.3f g"]
+
+ local hash = setmetatableindex(function(t,k)
+ local v = k
+ t[k] = v
+ return v
+ end)
+
+ local function convert(t,k)
+ local v = { }
+ for i=1,#k do
+ local p = k[i]
+ local r, g, b = p[1], p[2], p[3]
+ if r == g and g == b then
+ v[i] = hash[f_gray(r/255)]
+ else
+ v[i] = hash[f_color(r/255,g/255,b/255)]
+ end
+ end
+ t[k] = v
+ return v
+ end
+
+ local function initialize(tfmdata,kind,value) -- we really need the id ... todo
+ if value then
+ local resources = tfmdata.resources
+ local palettes = resources.colorpalettes
+ if palettes then
+ --
+ local converted = resources.converted
+ if not converted then
+ converted = setmetatableindex(convert)
+ resources.converted = converted
+ end
+ local colorvalues = sharedpalettes[value]
+ local default = false -- so the text color (bad for icon overloads)
+ if colorvalues then
+ default = colorvalues[#colorvalues]
+ else
+ colorvalues = converted[palettes[tonumber(value) or 1] or palettes[1]] or { }
+ end
+ local classes = #colorvalues
+ if classes == 0 then
+ return
+ end
+ --
+ -- todo: delay with lua function or plugin in vf handler, saves a lot of
+ -- overhead
+ --
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local droppedin, tfmdrop, dropchars, dropdescs, colrshapes
+ -- alternative 1:
+ -- local slots = { }
+ -- alternative 2:
+ local idx = 255
+ local slot = 0
+ --
+ for k, v in next, characters do
+ local index = v.index
+ if index then
+ local description = descriptions[k]
+ if description then
+ local colorlist = description.colors
+ if colorlist then
+ -- alternative 1:
+ -- local fnt = div(index,256)
+ -- local idx = mod(index,256)
+ -- local slt = slots[fnt]
+ -- if not slt then
+ -- colrshapes = { }
+ -- slot, droppedin, tfmdrop = fonts.dropins.provide("color",true,tfmdata,colrshapes,colorvalues)
+ -- slt = { slot, colrshapes, tfmdrop.characters, tfmdrop.descriptions }
+ -- slots[fnt] = slt
+ -- end
+ -- slot = slt[1]
+ -- colrshapes = slt[2]
+ -- dropchars = slt[3]
+ -- dropdescs = slt[4]
+ -- alternative 2:
+ if idx >= 255 then
+ idx = 1
+ colrshapes = { }
+ slot, droppedin, tfmdrop = fonts.dropins.provide("color",true,tfmdata,colrshapes,colorvalues)
+ dropchars = tfmdrop.characters
+ dropdescs = tfmdrop.descriptions
+ else
+ idx = idx + 1
+ end
+ --
+ colrshapes[idx] = description
+ -- todo: use extender
+ local u = { "use", 0 }
+ for i=1,#colorlist do
+ u[i+2] = colorlist[i].slot
+ end
+ v.commands = { u, { "slot", slot, idx } }
+ -- hack to prevent that type 3 also gets 'use' flags .. todo
+ local c = { commands = false, index = idx, dropin = tfmdata }
+ local d = { index = idx, dropin = tfmdata }
+ setmetatableindex(c,v)
+ setmetatableindex(d,description)
+ dropchars[idx] = c
+ dropdescs[idx] = d
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ fonts.handlers.otf.features.register {
+ name = "colr",
+ description = "color glyphs",
+ manipulators = {
+ base = initialize,
+ node = initialize,
+ }
+ }
+
+end
+
+do
+
+ local report_svg = logs.reporter("fonts","svg")
+
+ local cached = true directives.register("fonts.svg.cached", function(v) cached = v end)
+
+ local function initializesvg(tfmdata,kind,value) -- hm, always value
+ if value then
+ local properties = tfmdata.properties
+ local svg = properties.svg
+ local hash = svg and svg.hash
+ local timestamp = svg and svg.timestamp
+ if not hash then
+ return
+ end
+ if cached then
+ -- we need a different hash than for mkiv, so we append:
+ local pdfhash = hash .. "-svg"
+ local pdffile = containers.read(otf.pdfcache,pdfhash)
+ local pdfshapes = pdffile and pdffile.pdfshapes
+ local pdftarget = file.join(otf.pdfcache.writable,file.addsuffix(pdfhash,"pdf"))
+ if not pdfshapes or pdffile.timestamp ~= timestamp or not next(pdfshapes) or not lfs.isfile(pdftarget) then
+ local svgfile = containers.read(otf.svgcache,hash)
+ local svgshapes = svgfile and svgfile.svgshapes
+ pdfshapes = svgshapes and metapost.svgshapestopdf(svgshapes,pdftarget,report_svg) or { }
+ containers.write(otf.pdfcache, pdfhash, {
+ pdfshapes = pdfshapes,
+ timestamp = timestamp,
+ })
+ end
+ -- this can be delayed, no need to keep this in mem
+ fonts.dropins.provide("pdf",false,tfmdata,pdfshapes)
+ else
+ local mpsfile = containers.read(otf.mpscache,hash)
+ local mpsshapes = mpsfile and mpsfile.mpsshapes
+ if not mpsshapes or mpsfile.timestamp ~= timestamp or not next(mpsshapes) then
+ local svgfile = containers.read(otf.svgcache,hash)
+ local svgshapes = svgfile and svgfile.svgshapes
+ -- still suboptimal
+ mpsshapes = svgshapes and metapost.svgshapestomp(svgshapes,report_svg) or { }
+ containers.write(otf.mpscache, hash, {
+ mpsshapes = mpsshapes,
+ timestamp = timestamp,
+ })
+ end
+ fonts.dropins.provide("mps",false,tfmdata,mpsshapes)
+ end
+ end
+ end
+
+ otfregister {
+ name = "svg",
+ description = "svg glyphs",
+ manipulators = {
+ base = initializesvg,
+ node = initializesvg,
+ }
+ }
+
+end
+
+do
+
+ -- If this is really critical we can also use a pdf file as cache but I don't expect
+ -- png fonts to remain used.
+
+ local report_png = logs.reporter("fonts","png conversion")
+
+ local function initializepng(tfmdata,kind,value) -- hm, always value
+ if value then
+ local properties = tfmdata.properties
+ local png = properties.png
+ local hash = png and png.hash
+ local timestamp = png and png.timestamp
+ if not hash then
+ return
+ end
+ local pngfile = containers.read(otf.pngcache,hash)
+ local pngshapes = pngfile and pngfile.pngshapes
+ if pngshapes then
+ fonts.dropins.provide("png",false,tfmdata,pngshapes)
+ end
+ end
+ end
+
+ otfregister {
+ name = "sbix",
+ description = "sbix glyphs",
+ manipulators = {
+ base = initializepng,
+ node = initializepng,
+ }
+ }
+
+ otfregister {
+ name = "cblc",
+ description = "cblc glyphs",
+ manipulators = {
+ base = initializepng,
+ node = initializepng,
+ }
+ }
+
+end