diff options
author | Karl Berry <karl@freefriends.org> | 2023-01-02 21:31:04 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-01-02 21:31:04 +0000 |
commit | b9587c576db3679c338a1d395c182023ff4d711c (patch) | |
tree | d36ea573074a6c7d740f15e323b5ec7720e976bc /Master/texmf-dist/tex/luatex | |
parent | 7bde2bb3891ad0c87d05ad80fabb4258dc5b84fb (diff) |
blopentype (2jan23)
git-svn-id: svn://tug.org/texlive/trunk@65441 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-base.lua | 88 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-files.tex | 39 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-fonts.lua | 1213 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-fonts.tex | 308 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-lua.tex | 26 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot-sets.lua | 19 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/blopentype/blot.tex | 254 |
7 files changed, 1947 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-base.lua b/Master/texmf-dist/tex/luatex/blopentype/blot-base.lua new file mode 100644 index 00000000000..ef933ee0888 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-base.lua @@ -0,0 +1,88 @@ +require"gates.lua" + +pitex = gates.new("pitex") +pitex.misc = gates.new("pitex.misc") + +function pitex.log (message, ...) + texio.write_nl(string.format("\n" .. message .. "\n", ...)) +end +function pitex.error (...) + tex.error ("! PiTeX error: " .. string.format(...) .. ".") +end + +pitex.callback = gates.new("pitex.callback") + +-- Creates a gate with a callback's name and put it in that callback, if not +-- already there. Adds the subgate(s). +function pitex.callback.register (c, f) + if pitex.callback.type(c) == 2 then + pitex.callback.add(f, c) + else + pitex.callback.list{c} + pitex.callback.add(f, c) + callback.register(c, pitex.callback.execute[c]) + end +end + +-- Latin1 to UTF-8. +local char = unicode.utf8.char +local function convert_char (ch) +-- return char(string.byte(ch)) +end +function pitex.callback.convert (buf) + return string.gsub(buf,".",convert_char) +end + +pitex.callback.register("process_input_buffer", "convert") + +function remove_conversion () + pitex.callback.close("convert", "process_input_buffer") +end +function restore_conversion () + pitex.callback.open("convert", "process_input_buffer") +end + +--[[ + +require("nodeinspector") +new_inspection = nodeinspector.new_inspection + +local french_highmarks = { + string.byte("?"), + string.byte("!"), + string.byte(":"), + string.byte(";"), + } +local french_marks = { + string.byte("?"), + string.byte("!"), + string.byte(":"), + string.byte(";"), + string.byte(","), + string.byte("."), + string.byte("("), + string.byte("["), + string.byte("{"), + } + +local function french_punctuation (head, ...) + for _, glue in ipairs(arg) do + if glue.id == 10 then + head = node.remove(head, glue) + node.free(glue) + end + end + local kern = node.new(11, 1) + kern.kern = tex.sp(".15em") + node.insert_after(head, arg[1], kern) +end + +pitex.callback.french_punctuation = new_inspection( + french_punctuation, + {{id = 37, _char = french_marks}, {true, id = 37, char = french_highmarks}}, + {{id = 10, subtype = 0}, {id = 11, subtype = 0}}) + +pitex.callback.register("kerning", "french_punctuation") +pitex.callback.original_kerning = node.kerning +pitex.callback.register("kerning", "original_kerning") +--]]
\ No newline at end of file diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-files.tex b/Master/texmf-dist/tex/luatex/blopentype/blot-files.tex new file mode 100644 index 00000000000..212b05fc076 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-files.tex @@ -0,0 +1,39 @@ +\newread\ptx@temp_read +\def\iffile{% + \ifnext[ + {\ptx@iffile} + {\ptx@iffile[]}% + } +\def\ptx@iffile[#1]#2{% + \directlua{ + local f = kpse.find_file("\luaescapestring{#2}"\reverse\iffemptystring{#1}{, "#1"}) + local x = f and "firstoftwo" or "secondoftwo" + tex.print(\the\texcatcodes, "\noexpand\\" .. x) + }% + } +\long\def\ifffile{% + \ifnext[ + {\ptx@ifffile} + {\ptx@ifffile[]}% + } +\long\def\ptx@ifffile[#1]#2#3{% + \iffile[#1]{#2}{#3}{}% + } + +\long\def\inputfileor{% + \ifnext[ + {\ptx@inputfileor} + {\ptx@inputfileor[]}% + } +\long\def\ptx@inputfileor[#1]#2{% + \iffile[#1]{#2}{\input{#2}\relax}% + } + +\newwrite\ptx@auxfile +\def\ptx@write_toaux{% + \ifnext* + {\gobbleoneand{\write\ptx@auxfile}} + {\immediate\write\ptx@auxfile}% + } + +\let\writeout\ptx@write_toaux diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.lua b/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.lua new file mode 100644 index 00000000000..638f83e984e --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.lua @@ -0,0 +1,1213 @@ +-- *** UTILITY FUNCTIONS *** +local function get_locals (tab) + local tb = {} + for lib, keys in pairs(tab) do + keys = string.explode(keys) + for _, k in ipairs(keys) do + tb[k] = _G[lib][k] + end + end + return tb +end + +-- str +-- string manipulation +local str = get_locals {string = "explode gsub match format lower upper"} + +-- Removes space at the beginning and end and conflates multiple spaces. +function str.trim (s) + s = str.match(s, "^%s*(.-)%s*$") + s = str.gsub(s, "%s+", " ") + return s +end + +-- Extracts a pattern from a string, i.e. removes it and returns it. +-- If "full", then the entire pattern is removed, not only the captures. +function str.extract (s, pat, full) + local cap = str.match(s, pat) + if cap then + if full then + s = str.gsub(s, pat, "") + else + s = str.gsub(s, cap, "") + end + end + return cap, s +end +-- /str + + +-- lp +-- advanced string manipulation +lpeg.locale(lpeg) +local lp = get_locals {lpeg = "match P C S Ct V alnum"} +lp.space = lpeg.space^0 +-- /lp + + +-- tab +-- table manipulation +local tab = get_locals {table = "insert remove sort"} + +-- Adds val to tab, creating it if necessary. +function tab.update (tb, val) + tb = tb or {} + tab.insert(tb, val) + return tb +end + +-- Adds subtable (empty, or val) to tb at entry key, unless it already exists. +function tab.subtable (tb, key, val) + tb[key] = tb[key] or val or {} +end + +-- Writes a table to an extenal file. +local function write_key (key, ind) + return ind .. '["' .. key .. '"] = ' +end + +function tab.write (tb, f, ind) + for a, b in pairs (tb) do + if type(a) == "string" then + a = '"' .. a .. '"' + end + a = "[" .. a .. "]" + if type(b) == "table" then + f:write(ind, a, " = {") + tab.write(b, f, ind .. " ") + f:write(ind, "},") + else + if type(b) == "boolean" then + b = b and "true" or "false" + elseif type(b) == "string" then + b = '"' .. b .. '"' + end + f:write(ind, a, " = ", b, ",") + end + end +end + +-- Returns a full copy of a table. Not copying of metatables necessary for the +-- moment. +function tab.copy (tb) + local t = {} + for k, v in pairs (tb) do + if type(v) == "table" then + v = tab.copy(v) + end + t[k] = v + end + return t +end + +-- Sorts two tables containing modifiers (Italic, etc.). +function tab.sortmods (a, b) + local A, B = "", "" + for _, x in ipairs (a) do + A = A .. " " .. x + end + for _, x in ipairs (b) do + B = B .. " " .. x + end + return A < B +end + +-- Turns an array into a hash. +function tab.tohash(tb) + local t = {} + for _, k in ipairs(tb) do + t[k] = true + end + return t +end +-- /tab + +-- lfs +-- files etc. +local lfs = get_locals {lfs = "dir isdir isfile mkdir", kpse = "expand_var show_path find_file"} + +-- Returns anything after the last dot, i.e. an extension. +function lfs.extension (s) + return str.lower(str.match(s, "%.([^%.]*)$")) +end + +local extensions = { + otf = "opentype", + ttf = "truetype", + ttc = "truetype", +} +function lfs.type (s) + return extensions[lfs.extension(s)] +end + +local kpse_extensions = { + otf = "opentype fonts", + ttf = "truetype fonts", + ttc = "truetype fonts", +} +function lfs.kpse (s) + return kpse_extensions[lfs.extension(s)] +end + +-- Returns anything after the last slash, i.e. a pathless file. +function lfs.nopath (f) + return str.match(f, "[^/]*$") +end + +-- Creates a directory; the arguments are the successive subdirectories. +function lfs.ensure_dir (...) + local arg, path = {...} + for _, d in ipairs(arg) do + if path then + path = path .. "/" .. d + else + path = d + end + path = str.gsub(path, "//", "/") + if not lfs.isdir(path) then + lfs.mkdir(path) + end + end + return path +end + +-- Turns "foo/blahblah/../" into "foo/" (such going into and leaving +-- directories happens with kpse). Also puts everything to lowercase. +function lfs.smooth_file (f) + f = str.gsub(f, "/.-/%.%./", "/") + f = str.gsub(f, "^%a", str.lower) + return f +end +-- /lfs + + +-- wri +-- messages +local wri, write_nl = {}, texio.write_nl + +function wri.report (s, ...) +-- write_nl(str.format(s, unpack(arg))) +end + +function wri.error (s, ...) +-- tex.error(str.format(s, unpack(arg))) +end +-- /wri + + +-- various +-- the last one is, of course, not the least +local io = get_locals {io = "open lines"} +local os = get_locals {os = "date"} +local num = get_locals {math = "abs tan rad floor pi", tex = "sp"} +local fl = get_locals {fontloader = "open close to_table info", font = "read_tfm"} +-- /various + + +-- *** END OF UTILITY FUNCTIONS *** + + + +--- *** CREATING THE LIBRARY *** --- +local settings +if lfs.find_file"blot-sets.lua" then + settings = require"blot-sets.lua" +else + settings = {normal = {}, features = {}} +end +local font_families = {} +local normal_names = {} +for _, name in ipairs(settings.normal) do + normal_names[name] = true +end +local local_path = lfs.expand_var("$TEXMFHOME") +local foundry_path = lfs.ensure_dir (local_path, "tex", "luatex", "foundry") +-- local local_path = lfs.expand_var("$TEXMFHOME") +-- local foundry_path = lfs.ensure_dir (local_path, "fonts", "truetype", "public", "gfs") +local library_file = foundry_path .. "/" .. "readable.txt" +-- local library_file = "c:/texlive/texmf-local/tex/plain/pitex/readable.txt" +-- local library_file = "readable.txt" + +-- Analyze a font file and return a name and a table +-- with modifiers. +local function extract_font (file, names) + local fi, subname + -- Trying to open a font in ttc, using the names returned by fontloader.info + if names then + local name = names.fullname + if name then + fi = fl.open (file, name) + end + if not fi then + name = names.fontname + if name then + fi = fl.open + end + if not fi then + fl.error("Can't open %s", file) + return + end + end + subname = name + else + fi = fl.open(file) + end + -- Getting the most precise information. Not necessarily the best + -- solution, but since the user can modify the library, it's not so bad. + local fam, name = fi.names[1].names.preffamilyname or fi.names[1].names.family or fi.familyname, fi.fontname + local spec = fi.names[1].names.prefmodifiers or fi.names[1].names.subfamily or "" + local subfam, _spec + local t = { [0] = file } + -- Removing mods like Regular, Book, etc. + for name in pairs(normal_names) do + spec = str.gsub(spec, name, "") + end + if subname then + tab.insert(t, "[font = " .. subname .. "]") + end + if spec ~= "" then + spec = str.explode(spec) + for _, s in ipairs(spec) do + tab.insert(t, s) + end + end + fl.close(fi) + return fam, t +end + +-- Searches directories for font files, and pass them to +-- extract_font. The fonts are collected in a table. +-- The fonts_done table is updated when the library is read, +-- so when a font is missing and one needs to recheck files, +-- only those that arent in the libraries are considered. +local fonts_done = {} +local function check_fonts (rep, tb) + for f in lfs.dir (rep) do + if f ~= "." and f ~= ".." then + f = str.gsub(rep, "/$", "") .. "/" .. f + if lfs.isdir(f) then + check_fonts(f, tb) + elseif lfs.isfile(f) and not fonts_done[lfs.nopath(f)] then + local e = lfs.extension(f) + if e == "ttf" or e == "otf" then + local fam, file = extract_font(f) + if fam then + tab.subtable(tb, fam) + tab.insert(tb[fam], file) + end + elseif e == "ttc" then + local info = fl.info(f) + for _, i in ipairs(info) do + local fam, file = extract_font(f, i) + if fam then + tab.subtable(tb, fam) + tab.insert(tb[fam], file) + end + end + end + end + end + end +end + +-- Writes the library to an external file. +-- Type is "a" if what's going on is recheck_fonts. +local function write_lib (fams, file, type) + local read_table = {} + for fam, tb in pairs(fams) do + tab.insert(read_table, fam) + for _, ttb in ipairs(tb) do + tab.sort(ttb) + end + tab.sort(tb, tab.sortmods) + end + tab.sort(read_table) + local readable = io.open(file, type) + for n, fam in ipairs(read_table) do + local log + if type == "a" then + log = true + if n == 1 then + wri.report("\nAdding new font(s):") + readable:write("\n\n% Added automatically " .. os.date() .. "\n\n") + end + wri.report(fam) + end + readable:write(fam .. " :") + for n, f in ipairs(fams[fam]) do + log = log and " " + readable:write("\n ") + for _, t in ipairs(f) do + log = log and log .. " " .. t + readable:write(" " .. t) + end + log = log and log .. " " .. '"' .. f[0] .. '"' + readable:write(" " .. '"' .. lfs.nopath(f[0]) .. '",') + if log then wri.report(log) end + if n == #fams[fam] then + readable:write("\n\n") + end + end + end + readable:close() +end + + +-- If there is no library, we create it. +local font_paths = lfs.show_path("opentype fonts") +font_paths = str.gsub(font_paths, "\\", "/") +font_paths = str.gsub(font_paths, "/+", "/") +font_paths = str.gsub(font_paths, "!!", "") +font_paths = str.explode(font_paths, ";+") + +if not lfs.find_file(library_file) then + wri.report("I must create the library; please wait, that can take some time.") + for _, rep in ipairs(font_paths) do + check_fonts(rep, font_families) + end + write_lib(font_families, library_file, "w") +end + +-- Reads the library file, turning it into a table. +local explode_semicolon = lp.P{ + lp.Ct(lp.V"data"^1), + data = lp.C(((1 - lp.S";[") + (lp.S"[" * (1 - lp.S"]")^0 * lp.S"]" ))^1) / str.trim * (lp.S";" + -1), + } +local explode_comma = lp.P{ + lp.Ct(lp.V"data"^1), + data = lp.C(((1 - lp.S",[") + (lp.S"[" * (1 - lp.S"]")^0 * lp.S"]" ))^1) / str.trim * (lp.S"," + -1), + } + +local function load_library (lib) + local LIB = "" + local lib_file = lfs.find_file(lib) + if not lib_file then + wri.error("I can't find library %s.", lib) + return + end + + for l in io.lines(lib_file) do + if not str.match(l, "^%s*%%") then + if str.match(l, "^%s*$") then + LIB = LIB .. ";" + else + LIB = LIB .. " " .. l + end + end + end + LIB = str.gsub(LIB, ";%s*;", ";;") + LIB = str.gsub(LIB, ";+", ";") + LIB = str.gsub(LIB, "^;", "") + LIB = str.gsub(LIB, "%s+", " ") + + LIB = lp.match(explode_semicolon, LIB) + + local newlib = {} + for _, t in ipairs(LIB) do + local fam, files = str.match(t, "(.-):(.*)") + local current_mods + if files then + files = lp.match(explode_comma, files) + fam = str.explode(fam, ",") + local root + for n, f in ipairs (fam) do + f = str.trim(f) + if n == 1 then + root = f + if type(newlib[f]) == "string" then + wri.error("Name `%s' is already used as an alias for `%s'; it is now overwritten to denote a family", f, newlib[f]) + newlib[f] = {} + else + newlib[f] = newlib[f] or {} + end + else + if newlib[f] then + wri.error("The name `%s' is already used. I ignore it as an alias for `%s'", f, root) + else + newlib[f] = root + end + end + end + for _, f in ipairs(files) do + local reset + reset, f = str.extract(f, "^%.%.", true) + if reset then current_mods = nil end + local mods, file, feats = str.match(f, '([^"]*)"(.*)"') + if mods then + fonts_done[lfs.nopath(file)] = true + feats, mods = str.extract(mods, "%[([^%]]-)]", true) + mods = str.explode(mods) + if current_mods then + for _, t in ipairs(current_mods) do + tab.insert(mods, t) + end + if current_mods.feats then + feats = feats or "" + feats = current_mods.feats .. "," .. feats + end + end + local sizes, real_mods = {}, {} + for n, s in ipairs(mods) do + if tonumber(s) then + tab.insert(sizes, tonumber(s)) + else + tab.insert(real_mods, s) + end + end + sizes = #sizes > 0 and sizes or {0} + tab.sort(real_mods) + local T = newlib[root] + for _, t in ipairs(real_mods) do + t = str.trim(t) + if t ~= "" then + T[t] = T[t] or {} + T = T[t] + end + end + T.__files = T.__files or {} + for _, s in ipairs(sizes) do + T.__files[s] = {str.trim(file), feats} + end + else + feats, mods = str.extract(f, "%[([^%]]-)]", true) + if current_mods then + for _, mod in ipairs(str.explode(mods)) do + tab.insert(current_mods, mod) + end + if feats then + current_mods.feats = current_mods.feats and current_mods.feats .. "," .. feats or feats + end + else + current_mods = str.explode(mods) + current_mods.feats = feats + end + end + end + end + end + return newlib +end + +local library = {} +library.default = load_library(library_file) + +-- Same as above, but used when rechecking (if a font isn't found in libraries). +local function recheck_fonts () + local tb = {} + for _, rep in ipairs(font_paths) do + check_fonts(rep, tb) + end + write_lib(tb, library_file, "a") + library.default = load_library(library_file) +end + + +-- This is public. +function new_library (lib) + local l = load_library(lib) + if l then + tab.insert(library, l) + end +end + +--- *** END OF LIBRARY MANAGEMENT *** --- + + + +--- *** FONT CREATION *** --- + + +-- Creates a new substitution for trep. +local function add_sub (f, num, sub) + num, sub = f.map.map[num], f.map.map[sub] + if f.glyphs[num] and f.glyphs[sub] then + local x = f.glyphs[num] + tab.subtable(x, "lookups") + x.lookups.tex_trep = { { type = "substitution", specification = {variant = f.glyphs[sub].name} } } + end +end + +-- Creates a new ligature for tlig. +local function add_lig (f, lig, ...) + lig = f.map.map[lig] + if lig then + arg = {...} + local components + for _, c in ipairs(arg) do + c = f.map.map[c] + c = c and f.glyphs[c] + if c then + c = c.name + components = components and components .. " " .. c or c + else + components = nil + break + end + end + if components then + local x = f.glyphs[lig] + tab.subtable(x, "lookups") + tab.subtable(x.lookups, "tex_tlig") + tab.insert(x.lookups.tex_tlig, { type = "ligature", + specification = {char = x.name, components = components} }) + end + end +end + +-- Loops over all the constitutents of ligatures, creating intermediary +-- ligatures if necessary. E.g. "f f i" is broken into: +-- f + f = ff.lig +-- ff.lig + i = ffi.lig +-- Then when loading the font if the intermediary ligatures do not exist +-- (e.g. "1/" in "1 / 4") a phantom character is added to the font; which might +-- be dangerous (e.g. "1/" will create a node without character if no "4" follows). +-- The ".lig" suffix is arbitrary but all glyphs marked as ligatures are also registered +-- with such a name, so if there's an "f f" ligature in a font, no matter its name, "ff.lig" +-- will point to it. +local function ligature (comp, tb, phantoms) + local i = str.gsub(comp[1], "%.lig$", "") .. comp[2] .. ".lig" + phantoms[i] = true + tab.insert(tb.all_ligs, i) + tab.subtable(tb, comp[1]) + tb[comp[1]][comp[2]] = { char = i, type = 0 } -- The type could be something else. + tab.remove(comp, 1) + tab.remove(comp, 1) + if #comp > 0 then + tab.insert(comp, 1, i) + ligature(comp, tb, phantoms) + end +end + +local function get_lookups (t, lookup_table) + if t then + for _, tb in pairs(t) do + local _tb = { tags = {} } + if tb.features then + for _, feats in pairs(tb.features) do + local _tag = {} + if feats.scripts then + for _, scr in pairs(feats.scripts) do + _tag[scr.script] = {} + for _, lang in pairs(scr.langs) do + tab.insert (_tag[scr.script], str.trim(lang)) + end + end + end + for _, sub in pairs(tb.subtables) do + tab.insert(_tb, sub.name) + end + _tb.tags[feats.tag] = _tag + end + end + if tb.name then + local tp = tb.type or "no_type" + tab.subtable(lookup_table, tp) + lookup_table[tp][tb.name] = _tb + end + end + end +end + +function create_font (filename, extension, path, subfont, write) + + local data = fl.open(filename, subfont) + fontfile = fl.to_table(data) + fl.close(data) + + local lookups = {} + + local name_touni = { } + local max_char = 0 + for chr, gly in pairs(fontfile.map.map) do + max_char = chr > max_char and chr or max_char + -- Some glyphs have the same name in some fonts, + -- e.g. the several hyphens. + local name = fontfile.glyphs[gly].name + while name_touni[name] do + name = name .. "_" + end + name_touni[name] = chr + end + + if fontfile.gsub then + tab.insert(fontfile.gsub, + { type = "gsub_single", + name = "tex_trep", + subtables = { {name = "tex_trep"} }, + features = { { tag = "trep"} } }) + tab.insert(fontfile.gsub, + { type = "gsub_ligature", + name = "tex_tlig", + subtables = { {name = "tex_tlig"} }, + features = { { tag = "tlig"} } }) + for _, tb in ipairs(fontfile.gsub) do + for __, ttb in ipairs(tb.subtables) do + if tb.type == "gsub_contextchain" then + lookups[tb.name] = lookups[tb.name] or { type = tb.type } + tab.insert(lookups[tb.name], ttb.name) + end + lookups[ttb.name] = { type = tb.type } + lookups["-" .. ttb.name] = { type = tb.type } + end + end + end + + if fontfile.gpos then + for _, tb in ipairs(fontfile.gpos) do + for __, ttb in ipairs(tb.subtables) do + lookups[ttb.name] = { type = tb.type } + lookups["-" .. ttb.name] = { type = tb.type } + end + end + end + + if fontfile.kerns then + for _, class in ipairs(fontfile.kerns) do + local max = 0 + for a in pairs (class.seconds) do + max = max < a and a or max + end + if type(class.lookup) == "string" then + lookups[class.lookup] = { type = "gpos_pair", firsts = class.firsts, seconds = class.seconds, offsets = class.offsets, max = max} + else + for _, lk in ipairs(class.lookup) do + lookups[lk] = { type = "gpos_pair", firsts = class.firsts, seconds = class.seconds, offsets = class.offsets, max = max} + end + end + end + end + + add_sub(fontfile, 96, 8216) -- ` to quoteleft + add_sub(fontfile, 39, 8217) -- ' to apostrophe (quoteright) + + add_lig(fontfile, 8220, 8216, 8216) -- quoteleft + quoteleft to quotedblleft + add_lig(fontfile, 8221, 8217, 8217) -- quoteright + quoteright to quotedblright + add_lig(fontfile, 8211, 45, 45) -- -- to endash + add_lig(fontfile, 8212, 8211, 45) -- --- (i.e. endash + -) to emdash + add_lig(fontfile, 161, 63, 96) -- ?` to inverted question mark + add_lig(fontfile, 161, 63, 8216) -- The same, with `turned to quoteleft. + add_lig(fontfile, 191, 33, 96) -- !` to inverted exclamation mark + add_lig(fontfile, 191, 33, 8216) -- Idem. + + local characters, phantom_ligatures = {}, {} + for chr, gly in pairs(fontfile.map.map) do + local glyph, char = fontfile.glyphs[gly], {} + + char.index = gly + char.name = glyph.name + char.width = glyph.width + if glyph.boundingbox then + char.depth = -glyph.boundingbox[2] + char.height = glyph.boundingbox[4] + end + if glyph.italic_correction then + char.italic = glyph.italic_correction + elseif glyph.width and glyph.boundingbox then + char.italic = glyph.boundingbox[3] - glyph.width + end + tab.subtable(characters, chr) + characters[chr] = char + + if glyph.lookups then + for lk, tb in pairs(glyph.lookups) do + local _lk = "-" .. lk + if lookups[lk] and lookups[_lk] then + for _, l in ipairs(tb) do + if l.type == "substitution" then + + tab.subtable(lookups[lk], "pairs") + lookups[lk].pairs[glyph.name] = l.specification.variant + + tab.subtable(lookups[_lk], "pairs") + lookups[_lk].pairs[l.specification.variant] = glyph.name + + elseif l.type == "ligature" then + + local comp, lig = str.explode(l.specification.components), l.specification.char + local lig = "" + for _, c in ipairs(comp) do + lig = lig .. c + end + + tab.subtable(lookups, lk) + tab.subtable(lookups[lk], "ligs", {all_ligs = {}}) + ligature(comp, lookups[lk].ligs, phantom_ligatures) + name_touni[lig .. ".lig"] = chr + + end + end + end + end + end + + if glyph.kerns then + for _, kern in pairs(glyph.kerns) do + local lks = type(kern.lookup) == "table" and kern.lookup or {kern.lookup} + for _, lk in ipairs(lks) do + tab.subtable(lookups[lk], "kerns") + tab.subtable(lookups[lk].kerns, glyph.name) + lookups[lk].kerns[glyph.name][kern.char] = kern.off + end + end + end + + end + + for lig in pairs(phantom_ligatures) do + if not name_touni[lig] then + max_char = max_char + 1 + name_touni[lig] = max_char + characters[max_char] = {name = lig} + end + end + + local lookup_table = {} + get_lookups(fontfile.gsub, lookup_table) + get_lookups(fontfile.gpos, lookup_table) + get_lookups(fontfile.lookups, lookup_table, true) + + if fontfile.lookups then + for name, lk in pairs(fontfile.lookups) do + local tb, format = {}, lk.format + for _, rule in ipairs(lk.rules) do + local ttb = { lookups = rule.lookups } + for pos, seq in pairs(rule[format]) do + ttb[pos] = {} + for _, glyfs in ipairs(seq) do + glyfs = str.explode(glyfs) + glyfs = tab.tohash(glyfs) + tab.insert(ttb[pos], glyfs) + end + end + tab.insert(tb, ttb) + end + lookups[name] = tb + end + end + + local loaded_font = { + + direction = 0, + filename = filename, + format = extension, + fullname = fontfile.names[1].names.fullname, + name = fontfile.fontname, + psname = fontfile.fontname, + type = "real", + units_per_em = fontfile.units_per_em, + + auto_expand = true, + + cidinfo = fontfile.cidinfo, + + -- Used only to adjust absoluteslant. + italicangle = -fontfile.italicangle, + name_to_unicode = name_touni, + max_char = max_char, + lookups = lookups, + lookup_table = lookup_table, + characters = characters + } + + if write then + local f = io.open(path, "w") + f:write("return {") + tab.write(loaded_font, f, "\n") + f:write("}") + f:close() + end + + return loaded_font + +end + +-- GETTING A FONT + +-- Finds a font file, and returns the original +-- file and the Lua version. +local name_luafile, get_features +local function is_font (name, mods, size) + + local lib, library_filename + for l, t in ipairs(library) do + if t[name] then + library_filename = t[name] + lib = t + break + end + end + if not library_filename then + library_filename = library.default[name] + lib = library.default + end + + if library_filename then + if type(library_filename) == "string" then + library_filename = lib[library_filename] + end + tab.sort(mods) + local T = library_filename + for _, t in ipairs(mods) do + local found + for tag in pairs(T) do + if str.match(tag, "^" .. t) then + T = T[tag] + found = true + break + end + end + if not found then + T = nil + break + end + end + + if T and T.__files then + local file, feats + local diff = 10000 + for s, f in pairs(T.__files) do + if num.abs(s - size) < diff then + diff = num.abs(s - size) + file, feats = f[1], f[2] + end + end + file, _file = lfs.find_file(file, lfs.kpse(file)), file + if file then + file = str.gsub(file, "\\", "/") + else + return 1, _file + end + local features = {} + if feats then + get_features(feats, features) + end + local lua = name_luafile(file, features.font) + lua = lfs.isfile(lua) and lua + return file, lua, feats + end + end +end + +-- Returns the full path to the Lua version of the font. +-- "sub" is a font in ttc. +function name_luafile (file, sub) + local lua + sub = sub and "_" .. sub or "" + sub = str.gsub(sub, " ", "_") + if str.match(file, "/") then + lua = str.match(file, ".*/(.-)%....$") + else + lua = str.match(file, "(.-)%....$") + end + lua = lua .. sub + return foundry_path .. "/" .. lua .. ".lua" +end + +local function apply_size (font, size, letterspacing, parameters) + if (size < 0) then size = (- 655.36) * size end + local to_size = size / font.units_per_em + font.size = size + font.designsize = size + font.to_size = to_size + local italic = font.italicangle or 0 + local space, stretch, shrink, extra + if parameters == "mono" then -- Creates a monospaced font with space equal to the + -- width of an "m" and no stretch or shrink. + space = font.characters[109].width * to_size + stretch, shrink, extra = 0, 0, 0 + else + parameters = parameters and str.explode(parameters) or {} + space = (parameters[1] or 0.25) * size + stretch = (parameters[2] or 0.166666) * size + shrink = (parameters[3] or 0.111111) * size + extra = (parameters[4] or 0.111111) * size + end + font.parameters = { + slant = size * num.floor(num.tan(italic * num.pi/180)), -- \fontdimen 1 + space = space, -- \fontdimen 2 + space_stretch = stretch, -- \fontdimen 3 + space_shrink = shrink, -- \fontdimen 4 + x_height = size * 0.4, -- \fontdimen 5 + quad = size, -- \fontdimen 6 + extra_space = extra -- \fontdimen 7 + } + + letterspacing = letterspacing or 1 + for c, t in pairs(font.characters) do + if t.width then + t.width, t.height, t.depth = t.width * to_size * letterspacing, t.height * to_size, t.depth * to_size + t.expansion_factor = 1000 + if t.italic then + t.italic = t.italic * to_size + end + end + end + + return font +end + + +local get_mods = lp.Ct((lp.space * lp.S"/" * lp.C(lp.alnum^1))^0) +local get_feats = lp.Ct((lp.C((1 - lp.S",;")^1) * (lp.S",;" + -1))^1) +function get_features (features, tb) + features = lp.match(get_feats, features) or {} + for _, f in ipairs(features) do + if str.match(f, "=") then + local key, val = str.match(f, "%s*(.-)%s*=%s*(.*)") + val = str.trim(val) + if val == "false" then + tb[key] = nil + else + tb[key] = val + end + else + f = str.trim(f) + neg, f = str.extract(f, "^%-") + if neg then + tb[f] = nil + else + _, f = str.extract(f, "^%+") + tb[f] = true + end + end + end +end + +local lookup_functions = {} + +function lookup_functions.gsub_single (tb, f) + local name_touni = f.name_to_unicode + for a, b in pairs(tb.pairs) do + local _a, _b = name_touni[a], name_touni[b] + f.max_char = f.max_char + 1 + f.characters[f.max_char] = f.characters[_a] + f.characters[_a] = f.characters[_b] + name_touni[a], name_touni[b] = f.max_char, _a + end + return f +end + +function lookup_functions.gsub_ligature (tb, f) + local name_touni = f.name_to_unicode + tb.ligs.all_ligs = nil + for a, tb in pairs(tb.ligs) do + a = name_touni[a] + tab.subtable(f.characters[a], "ligatures") + for b, ttb in pairs(tb) do + b, c = name_touni[b], name_touni[ttb.char] + f.characters[a].ligatures[b] = {char = c, type = ttb.type} + end + end + return f +end + +local function kern_pairs (tb, firsts, seconds, offset) + for _, c1 in ipairs(str.explode(firsts)) do + for __, c2 in ipairs(str.explode(seconds)) do + tab.subtable(tb, c1) + tb[c1][c2] = offset + end + end +end + +local function kern_classes (firsts, seconds, offsets, max) + local kerns = {} + for f, F in pairs (firsts) do + for s, S in pairs (seconds) do + local off = offsets[(f-1) * max + s] + if off then + kern_pairs (kerns, F, S, off) + end + end + end + return kerns +end + +local function apply_kerns (f, kerns, to_size) + local name_touni = f.name_to_unicode + to_size = to_size or 1 + for c1, ttb in pairs(kerns) do + for c2, off in pairs(ttb) do + tab.subtable(f.characters[name_touni[c1]], "kerns") + f.characters[name_touni[c1]].kerns[name_touni[c2]] = off * to_size + end + end +end + +function lookup_functions.gpos_pair (tb, f) + -- These are the big kern classes. + if tb.offsets then + local name_touni = f.name_to_unicode + for n, off in pairs(tb.offsets) do + tb.offsets[n] = off * f.to_size + end + local kerns = kern_classes(tb.firsts, tb.seconds, tb.offsets, tb.max) + apply_kerns(f, kerns) + end + -- These are the ones retrieved from individual glyphs. + if tb.kerns then + apply_kerns(f, tb.kerns, f.to_size) + end + return f +end + +function lookup_functions.gsub_contextchain (tb, f) + local name_touni = f.name_to_unicode + local T = f.contextchain or {} + for _, llk in ipairs(tb) do + if fontfile.lookups then + local sub, Sub = fontfile.lookups[llk].rules[1].lookups + local chain = fontfile.lookups[llk].rules[1].coverage + local cur, current = str.explode(chain.current[1]), {} + local aft, after = chain.after and str.explode(chain.after[1]) or {}, {} + for _, c in ipairs(cur) do + c = name_touni[c] + if sub then + Sub = {} + for n, x in ipairs(sub) do + Sub[n] = name_touni[fontfile.glyphs[f.characters[c].index].lookups[x .. "_s"][1].specification.variant] + end + end + local t = { lookup = Sub} + tab.subtable(T, C) + for __, a in ipairs(aft) do + tab.subtable(t, "after") + t.after[name_touni[a]] = true + end + tab.insert(T[c], t) + end + end + end + f.contextchain = T + return f +end + +local function _isactive (tb, ft, sc, lg) + for t in pairs(tb.tags) do + if ft[t] then + if t[sc] then + for _, lang in pairs(tb[sc]) do + if lang == lg then + return true + end + end + else + return true + end + end + end +end + + +local lookup_types = { + "gsub_single", + "gsub_ligature", + "gpos_pair" + } + +local function activate_lookups (font, features, script, lang) + for _, type in ipairs(lookup_types) do + if font.lookup_table and font.lookup_table[type] then + for l, tb in pairs(font.lookup_table[type]) do + if _isactive(tb, features, script, lang) then + for _, lk in ipairs(tb) do + local lt = font.lookups[lk] + if lt then + font = lookup_functions[type](lt, font) + end + end + end + end + end + end + return font +end + +local function load_font (name, size, id, done) + local loaded_font = lfs.find_file(name, "tfm") + if loaded_font then + loaded_font = fl.read_tfm(loaded_font, size) + else + local original = str.trim(str.match(name, "[^:]*")) + local family, mods, feats + family, name = str.extract(name, "([^/:]*)") + family = str.trim(family) + mods, name = str.extract(name, "[^:]*") + mods = lp.match(get_mods, mods) or {} + feats = str.extract(name, ":(.*)") or "" + local features = tab.copy(settings.features) + get_features(feats, features) + + local at_size + if features.size then + at_size = features.size + else + at_size = size + at_size = at_size > 0 and at_size or at_size * - 655.36 + at_size = at_size / 65536 + end + local source, lua, add_feats = is_font(family, mods, at_size) + if add_feats then get_features(add_feats, features) end + + if type(source) == "string" then + local cache = features.cache or "yes" + if lua then + if cache == "no" or cache == "rewrite" then + loaded_font = create_font(source, lfs.type(source), lua, features.font, cache == "rewrite") + else + loaded_font = dofile(lua) + end + else + lua = name_luafile(source, features.font) + loaded_font = create_font(source, lfs.type(source), lua, features.font, cache ~= "no") + end + else + if not done then + if type(source) == "number" then + wri.error("The library says `%s' matches `%s', but I can't find that file anywhere. Clean up your library!", original, lua) + else + recheck_fonts() + return load_font(original, size, id, true) + end + else + wri.error("I can't find `%s'. I return a default font to avoid further errors.", original) + end + end + + if loaded_font then + + local expansion = features.expansion and str.explode(features.expansion) or {} + loaded_font.stretch = expansion[1] or 0 + loaded_font.shrink = expansion[2] or 0 + loaded_font.step = expansion[3] or 0 + + local extend = features.extend or 1 + loaded_font.extend = extend * 1000 + local slant + if features.absoluteslant then + local italic = loaded_font.italicangle or 0 + slant = features.absoluteslant - italic + else + slant = features.slant or 0 + end + loaded_font.slant = num.tan(num.rad(slant)) * 1000 + + loaded_font = apply_size(loaded_font, size, features.letterspacing, features.space) + loaded_font = activate_lookups(loaded_font, features, features.script, features.lang) + + loaded_font.name = loaded_font.name .. id + loaded_font.fullname = loaded_font.fullname .. id + local embedding = features.embedding or "subset" + if embedding ~= "no" and embedding ~= "subset" and embedding ~= "full" then + wri.error("Invalid value `%s' for the `embedding' feature. Value should be `no', `subset' or `full'.", embedding) + embedding = "subset" + end + loaded_font.embedding = embedding + else + loaded_font = fl.read_tfm(lfs.find_file("cmr10", "tfm"), size) + end + end + return loaded_font +end + +callback.register("define_font", load_font) diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.tex b/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.tex new file mode 100644 index 00000000000..adf4622fe58 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-fonts.tex @@ -0,0 +1,308 @@ +\inputltcfile blot-fonts.lua +\pdfadjustspacing=2 + +\def\currentfont{} +\def\currentsize{normal} +\def\currentstyle{rm} +\def\currentweight{rg} +\def\currentcase{lc} +\def\makecurrentfont{% + \csname\currentfont @\currentsize @\currentstyle @\currentweight @\currentcase\endcsname + } +\def\normalsize{% + \def\currentsize{normal}% + \makecurrentfont + } +\def\small{% + \def\currentsize{small}% + \makecurrentfont + } +\def\verysmall{% + \def\currentsize{verysmall}% + \makecurrentfont + } +\def\smaller{% + \passexpanded\ifstring\currentsize{normal}% + {\def\currentsize{small}} + {\def\currentsize{verysmall}} + \makecurrentfont + } +\def\big{% + \def\currentsize{big}% + \makecurrentfont + } +\def\verybig{% + \def\currentsize{verybig}% + \makecurrentfont + } +\def\bigger{% + \passexpanded\ifstring\currentsize{normal}% + {\def\currentsize{big}} + {\def\currentsize{verybig}} + \makecurrentfont + } +\def\it{% + \def\currentstyle{it}% + \makecurrentfont + } +\def\rm{% + \def\currentstyle{rm}% + \makecurrentfont + } +\def\rmstring{rm} +\def\emph{% + \ifx\currentstyle\rmstring + \expandafter\ital + \else + \expandafter\rom + \fi + } +\def\bf{% + \def\currentweight{bf}% + \makecurrentfont + } +%\def\normalweight{% +\def\rg{% + \def\currentweight{rg}% + \makecurrentfont + } +\def\sc{% + \def\currentcase{sc}% + \makecurrentfont + } +%\def\normalcase{% +\def\lc{% + \def\currentcase{lc}% + \makecurrentfont + } +\freedef\ital{{\it#1}} +\freedef\bold{{\bf#1}} +\freedef\scap{{\sc#1}} +\freedef\rom{{\rm#1}} + + +\restrictparameter font : + command % The command to be used to switch to that font. + name % Actually the part common to all files' names for that font. + size % Well, the size. + small % Smaller size. + verysmall % Smaller yet. + big % Bigger. + verybig % Insanely big. + bold % Modifier for bold font. + italic % Modifier for italic font. + math % If set to "true", then used for math font. + % small, verysmall and italic should be specified + % (which shows I don't use it very often). + features % Font features (e.g. +onum, etc.). + slant % A number representing an angle, loading an italic + % font if no real italic is a available. + slantsc % The same, for small caps. + +% The font parameter should disappear some day, it's clumsy. +\def\setfont#1:{% + \setparameter font : command = #1% + } + +\setparameter metafont : % No relation :) + size = 10pt + bold = Bold + italic = Italic + features = "+onum; +liga; +trep; +tlig; expansion=30 20 5;" + +\setparameter font : + meta = metafont + +\newdimen\ptx@fontsize +\luacode +ptx_fonts = {} +function ptx_getfont(Font, ...) + if ptx_fonts[Font] then + local tempfont = ptx_fonts[Font] + for _, style in ipairs(arg) do + if ptx_getstyle[style] then + tempfont = tempfont:gsub("(%w+)@(%w+)@(%w+)@(%w+)@(%w+)",ptx_getstyle[style]) + else + tempfont = nil + texio.write_nl("! PiTeX error: Unknown font style `style'.") + return Font + end + end + return font.id(tempfont) + else + texio.write_nl("! PiTeX error: " .. Font .. " is not a PiTeX font. It can't be changed.") + end +end +ptx_getstyle = { + normal = "%1@normal@%3@%4@%5", + small = "%1@small@%3@%4@%5", + verysmall = "%1@verysmall@%3@%4@%5", + big = "%1@big@%3@%4@%5", + verybig = "%1@verybig@%3@%4@%5", + rm = "%1@%2@rm@%4@%5", + it = "%1@%2@it@%4@%5", + rg = "%1@%2@%3@rg@%5", + bf = "%1@%2@%3@bf@%5", + lc = "%1@%2@%3@%4@lc", + sc = "%1@%2@%3@%4@sc" + } +\luacode/ + +\newstring{+} \newstring{-} +\def\ptx@dofont#1#2#3#4#5{% + \edef\ptx@temp{\passvaluenobraces\commandtoname font : command }% + \ifexpression{ -\ifstring{#4}{normal} & { \ifprefix-{#5} | \ifprefix+{#5} } } + {\def\ptx@dofont_size{\dimexpr\usevalue font : size + #5\relax}} + {\def\ptx@dofont_size{#5}}% + \ptx@dofont_load{\ptx@temp @#4@#1@#2@lc}{#3}{}{\ptx@dofont_size}% + \ifstring{#1}{rm} + {\ptx@dofont_load{\ptx@temp @#4@#1@#2@sc}{#3}{+smcp;}{\ptx@dofont_size}% + \ifattribute font : slant % Loading a slanted version of the font if no italic was given + {\ptx@dofont_load{\ptx@temp @#4@it@#2@lc}{#3}{slant=\usevalue font: slant ;}{\ptx@dofont_size} + \ifattribute font : slantsc {} + {\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;slant=\usevalue font: slant ;}{\ptx@dofont_size}}}{}% + \ifattribute font : slantsc + {\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;slant=\usevalue font: slantsc ;}{\ptx@dofont_size}}{}}% + {\ifattribute font : slantsc {}{\ptx@dofont_load{\ptx@temp @#4@it@#2@sc}{#3}{+smcp;}{\ptx@dofont_size}}} + } + +\def\ptx@dofont_load#1#2#3#4{% + \passcs\font{#1}="\usevalue font : name #2:#3\usevalue font : features " at #4\relax + \ptx@lua{ptx_fonts[font.id("#1")] = "#1"}% + } + + + +\def\dofont#1#2#3{% + \passvalue{\ptx@dofont{#1}{#2}{#3}{normal}} font : size + \passvalue{\ptx@dofont{#1}{#2}{#3}{small}} font : small + \passvalue{\ptx@dofont{#1}{#2}{#3}{verysmall}} font : verysmall + \passvalue{\ptx@dofont{#1}{#2}{#3}{big}} font : big + \passvalue{\ptx@dofont{#1}{#2}{#3}{verybig}} font : verybig +% + \ifvalue font : math = true + {\ifstring{#1#2}{rmrg} + {\passcs{\textfont0=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}% + \passcs{\scriptfont0=}{\passvalue\commandtoname font : command @small@#1@#2@lc}% + \passcs{\scriptscriptfont0=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc} + \passcs{\textfont2=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}% + \passcs{\scriptfont2=}{\passvalue\commandtoname font : command @small@#1@#2@lc}% + \passcs{\scriptscriptfont2=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}} + {\iffstring{#1#2}{itrg} + {\passcs{\textfont1=}{\passvalue\commandtoname font : command @normal@#1@#2@lc}% + \passcs{\scriptfont1=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}% + \passcs{\scriptscriptfont1=}{\passvalue\commandtoname font : command @verysmall@#1@#2@lc}}}% + }{}% + } + +\gates new \FontLoader {FontLoader} +\FontLoader list {fontloader} + [fl_command] + {% + \passvaluenobraces\edef font : command {% + \def\noexpand\currentfont{\passvalue\commandtoname font : command }% + \noexpand\makecurrentfont}} + (fl_load) + . ( fl_roman ) + . . [ fl_doromanregular ] + {\dofont{rm}{rg}{}} + . . [ fl_doromanbold ] ? {conditional = -\ifvalue font : bold = none } + {\dofont{rm}{bf}{/\usevalue font : bold }} + . ( fl_italic ) ? {conditional = -\ifvalue font : italic = none } + . . [ fl_doitalicregular ] + {\dofont{it}{rg}{/\usevalue font : italic }} + . . [ fl_doitalicbold ] ? {conditional = -\ifvalue font : bold = none } + {\dofont{it}{bf}{/\usevalue font : italic /\usevalue font : bold }} + [fl_use] ? {conditional = \ifvalue font : command = {\mainfont} } + {\mainfont} + (fl_post) + . [fl_delete] + {\deleteparameter font:} + . [fl_meta] + {\setattribute font : meta = metafont } + +\defactiveparameter font {% + \FontLoader execute {fontloader}% + } + + + + + + + +\long\def\color#1#2{% + \pdfcolorstack0 push {#1 rg #1 RG}% + #2% + \pdfcolorstack0 pop% + } + +\newattribute\ptx@underline_attribute +\luacode +local do_underline = function (head,order,ratio,sign) + local item, leader = head, false + while item do + leader = false + if node.has_attribute(item,\attributenumber\ptx@underline_attribute) + and not (item.id == 10 and (item.subtype == 8 or item.subtype == 9)) then + local item_line = node.new(2) + item_line.depth = tex.sp("1.4pt") + item_line.height = tex.sp("-1pt") + if node.has_field(item,"spec") then + item_line.width = item.spec.width + if order == 0 then + if sign == 1 then + item_line.width = item_line.width + ratio * item.spec.stretch + else + item_line.width = item_line.width - ratio * item.spec.shrink + end + else + if item.spec.stretch_order > 0 or item.spec.shrink_order > 0 then + lualog(item.spec.stretch_order) + item_line.width = 1 + item.subtype = 100 + item.leader = item_line + leader = true + end + end + elseif node.has_field(item,"width") then + item_line.width = item.width + elseif node.has_field(item,"kern") then + item_line.width = item.kern + end + if leader then + item = item.next + else + local item_kern = node.new(11) + item_kern.kern = -item_line.width + node.insert_after(head,item,item_line) + node.insert_after(head,item,item_kern) + item = item_line.next + end + else + item = item.next + end + end +end +pitex.misc.underline = function (head) + for line in node.traverse_id(0,head) do + do_underline(line.list,line.glue_order,line.glue_set,line.glue_sign) + end + return head +end +pitex.callback.register("post_linebreak_filter", "pitex.misc:underline") +pitex.callback.close("pitex.misc:underline", "post_linebreak_filter") +\luacode/ + +\freedef\underline{% + \ptx@lua{% + pitex.callback.ajar("pitex:underline", "post_linebreak_filter") + } +% local plf = callback.list_functions("post_linebreak_filter") +% if not plf or not plf["underline"] then +% callback.add_function(underline, "underline", "post_linebreak_filter") +% end}% + \quitvmode % Otherwise it might also underline the indentation box. + \ptx@underline_attribute=0\relax + #1\unsetattribute\ptx@underline_attribute + } diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-lua.tex b/Master/texmf-dist/tex/luatex/blopentype/blot-lua.tex new file mode 100644 index 00000000000..f00e58c9d41 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-lua.tex @@ -0,0 +1,26 @@ +\def\inputltcfile#1 {\directlua{dofile(kpse.find_file("#1"))}} + +\inputltcfile blot-base.lua + +\def\ptx@lua{\directlua name {Internal PiTeX chunk}} + +\newcatcodetable\luacatcodes{\#\%\^^M\~=12} +\newtoks\ptx@luacode_list +\newif\ifptx@luacode_store +% Mimicks a block (\newblock isn't defined yet +% and anyway it wouldn't be very useful). +\def\luacode{% + \begingroup + \catcodetable\luacatcodes + \ifnext[ + {\ptx@luacode_store} + {\ptx@luacode_store[]}} +\bgroup +\setcatcodes{\^^M=12}% +\long\gdef\ptx@luacode_store[#1]^^M#2\luacode/{% So line count is right. + \endgroup% + \ifemptystring{#1}% + {\ptx@lua{#2}}% + {\def#1{#2}}% + }% +\egroup diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot-sets.lua b/Master/texmf-dist/tex/luatex/blopentype/blot-sets.lua new file mode 100644 index 00000000000..5c24caa9378 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot-sets.lua @@ -0,0 +1,19 @@ +return { + + features = { + kern = true, + liga = true, + trep = true, + tlig = true, + script = "latn", + lang = "dflt", + --stretch = 30, + --shrink = 20, + --step = 10, + }, + + normal = { + "Normal", "Regular", "Book", + }, + +} diff --git a/Master/texmf-dist/tex/luatex/blopentype/blot.tex b/Master/texmf-dist/tex/luatex/blopentype/blot.tex new file mode 100644 index 00000000000..44a89e553ef --- /dev/null +++ b/Master/texmf-dist/tex/luatex/blopentype/blot.tex @@ -0,0 +1,254 @@ +% blopentype: a basic luatex open type loader +% +% some (most) pitex macros still in place.- 30.12.2022 +% +% User interface +% +\message{This is blopentype, v0.0.0 December 2022} + +\input luatex85.sty % deprecated 30.12.2022 +\input yax % which itself \input's texapi +\input gates + +\setcatcodes{\@\_=11} +\suppressoutererror=1 + +% MESSAGES +\def\ptx@error{\senderror{PiTeX}} +\def\ptx@log#1{% + \immediate\write17{^^J#1^^J}% + } +\def\ptx@warn#1{% + \ptx@log{PiTeX warning: #1}% + } + +% ATTRIBUTES +\newcount\ptx@attribute_count +\ptx@attribute_count=100 % The first 100 attributes are scratch. +\def\newattribute#1{% + \advance\ptx@attribute_count1 + \attributedef#1=\ptx@attribute_count + \xdefcs{ptx@attribute:\commandtoname#1}{\the\ptx@attribute_count}% + } +\def\unsetattribute#1{#1=-"7FFFFFFF\relax} +\def\attributenumber#1{\usecs{ptx@attribute:\commandtoname#1}} + +% FREEDEF +\def\freedef#1{% + \def#1{% + \ifnextnospace" + {\ptx@freedef_quote#1} + {\ifnextnospace/ + {\ptx@freedef_slash#1} + {\usecs{ptx@freedef_user:\commandtoname#1}}}% + }% + \defcs{ptx@freedef_user:\commandtoname#1}##1% + } +\def\ptx@freedef_quote#1"#2"{% + \usecs{ptx@freedef_user:\commandtoname#1}{#2}% + } +\def\ptx@freedef_slash#1/#2/{% + \usecs{ptx@freedef_user:\commandtoname#1}{#2}% + } + + +\newbox\ptx@box_temp + +\newif\ifmaintext +\maintexttrue + +% CATCODE TABLES +\newcount\ptx@catcodetable_count +\ptx@catcodetable_count=100 % First 100 are scratch. +\def\newcatcodetable#1#2{% + \global\advance\ptx@catcodetable_count1 + \chardef#1=\ptx@catcodetable_count + \begingroup + \setcatcodes{#2}% + \savecatcodetable#1% + \endgroup + } + +\newcatcodetable\texcatcodes{\@\_=12} + +\def\inputltmfile#1 {\input #1.tex } + +\inputltmfile blot-lua +\inputltmfile blot-files +\inputltmfile blot-fonts +\restorecatcodes +\endinput +% +% the remaining macros are leftovers from PiTeX, awaiting removal.- 30.12.2022 +% +% +\inputltmfile sections +\inputltmfile blocks +\inputltmfile references +\inputltmfile verbatim +\inputltmfile inserts +\inputltmfile output +\input navigator.tex + +% AUXILIARY FILE +\iffile{\jobname.aux}{% + \ptx@lua{% + remove_conversion() + tex.print("\luaescapestring{\noexpand\input\noexpand\jobname.aux}") + }% + \directlua{restore_conversion()}} +\immediate\openout\ptx@auxfile=\jobname.aux + +% PDF SETTINGS +\restrictparameter document : author title pdftitle date pdfdate subject keywords mode layout version\par +\restrictattribute document : mode outlines bookmarks thumbs thumbnails attachments files oc\par +\restrictattribute document : layout onepage onecolumn twopage twocolumn twopage* twocolumn*\par + +\suppressoutererror=1 +\let\ptx@bye\bye +\def\bye{% + \passvalueand{\setattribute navigator : title = } document : pdftitle { }{} + % The "date" attribute in the "document" parameter isn't supposed to hold a + % PDF-date, as navigator expects. + \deleteattribute document : date + \passvalueand{\setattribute navigator : date = } document : pdfdate { }{} + \finishpdffile\ptx@bye + } + +\setattribute navigator : meta = document + +% Turns a dimen into PostScript points, without the unit (as wanted by PDF). +\def\pdfpoint#1{% + \directlua{% + local d = "\the\dimexpr#1" + d = string.gsub(d, "pt", "") + tex.print(tostring(d * (72/72.27))) + }} + + + + +% TEX SETTINGS +\long\def\ptx@tex_set#1#2#3{% + \ifcs{#2} + {\usecs{#2}=#3\relax} + {\ptx@error{No TeX parameter `#2'}} + } + +\defactiveparameter tex {% + \parameterloop #1 : \ptx@tex_set + } + +\frenchspacing +\maxdepth=\maxdimen + +\def\antigobblespace{% + \ifcatnext a{ }{\iffnext({ }}% + } + +\def\strut#1#2{% + \vrule height#1 depth#2 width0pt + } + +\newdimen\extraboxspace +\newdimen\ptx@extraboxspace_top +\newdimen\ptx@extraboxspace_right +\newdimen\ptx@extraboxspace_bottom +\newdimen\ptx@extraboxspace_left + +\newfornoempty\ptx@colorbox_loop{1}#2,{% + \ifcase#1 + \ptx@extraboxspace_top =#2 + \ptx@extraboxspace_right =#2 + \ptx@extraboxspace_bottom =#2 + \ptx@extraboxspace_left =#2 + \or + \ptx@extraboxspace_right =#2 + \ptx@extraboxspace_left =#2 + \or + \ptx@extraboxspace_bottom =#2 + \or + \ptx@extraboxspace_left =#2 + \fi + \passarguments{\numexpr(#1+1)}% + } +\def\colorbox{% + \ifnextnospace[\ptx@colorbox_setborders + {\ptx@extraboxspace_top =\extraboxspace + \ptx@extraboxspace_right =\extraboxspace + \ptx@extraboxspace_bottom =\extraboxspace + \ptx@extraboxspace_left =\extraboxspace + \ptx@colorbox_do}% + } +\def\ptx@colorbox_setborders[#1]{% + \ptx@colorbox_loop{0}{#1,}% + \ptx@colorbox_do + } +{\setcatcodes{pt=12} +\gdef\noPT#1pt{#1 }} +\def\ptx@colorbox_do#1#2{% + \bgroup + \setbox\ptx@box_temp=\hbox{#2}% + \hbox{% + \pdfliteral{ + q #1 rg #1 RG + -\expandafter\noPT\the\ptx@extraboxspace_left + \expandafter\noPT\the\dimexpr(\ht\ptx@box_temp+\ptx@extraboxspace_top)\relax + \expandafter\noPT\the\dimexpr(\wd\ptx@box_temp+\ptx@extraboxspace_left+\ptx@extraboxspace_right)\relax + -\expandafter\noPT\the\dimexpr(\ht\ptx@box_temp+\ptx@extraboxspace_top+\dp\ptx@box_temp+\ptx@extraboxspace_bottom)\relax + re f Q}% + #2}% + \egroup + } + +\def\og{\char"00AB~} \def\fg{~\char"00BB\antigobblespace} + +\def\trace{\tracingcommands3 \tracingmacros2 } +\def\untrace{\tracingcommands0 \tracingmacros0 } + +\restorecatcodes + +\endinput +% +% These are leftovers from Isambert's code: they'll be removed as +% documentation improved.- 30.12.2022 +% +% This is piTeX, a set of macros I (Paul Isambert) use to +% typeset documentations for my packages (that's why it is +% archived on CTAN). +% +% Perhaps in the future, when this achieves some kind of +% format-like completude, it'll be publicly announced. In the +% meanwhile, a documentation exists (pitex-doc.pdf, also readable +% in a text editor as pitex-doc.txt). +% +% +% You can of course use those macros, but you are on your +% own, and the files will probably be modified without announcement. +% The file is supposed to be \input on plain TeX with LuaTeX, at least v.0.6. +% +% +% The files needed are: +% +% texapi.tex (an independent package for programming) +% yax.tex (an independent package for key=value interface) +% gates.tex and gates.lua (an independant package for overall architecture) +% navigator.tex (an independant package for PDF features) +% lua.ptx and base.ptxlua (Lua side) +% files.ptx (file management) +% fonts.ptx, fonts.ptxlua and foundry-settings.lua +% (fonts, should be independant some day; actually +% fonts.ptxlua can be used independantly, but there is +% no doc) +% sections.ptx (sectionning commands) +% blocks.ptx (text blocks) +% references.ptx (labels and references) +% verbatim.ptx (typesetting verbatim) +% inserts.ptx (footnotes and figures, a mess) +% output.ptx (output routine) +% +% The file i-pitex.lua is needed only to typeset the documentation with the +% Interpreter package. +% +% +% Date: November 2011. |