diff options
author | Philipp Gesang <phg@phi-gamma.net> | 2016-04-20 07:40:31 +0200 |
---|---|---|
committer | Philipp Gesang <phg@phi-gamma.net> | 2016-04-20 07:40:31 +0200 |
commit | 1c93f97f4bce1b399e90f65657e95ef13434128c (patch) | |
tree | c0bb9705e1276e548a19ef656749d890d78860f6 | |
parent | c35210aaaf992793bd111a0bd90e28630c7d2101 (diff) | |
parent | e14f3c50eedcd2652125177db0deacd8079cc048 (diff) | |
download | luaotfload-1c93f97f4bce1b399e90f65657e95ef13434128c.tar.gz |
Merge pull request #335 from phi-gamma/master
format and feature handling, fixes for 2.7
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | doc/luaotfload-main.tex | 88 | ||||
-rw-r--r-- | src/luaotfload-auxiliary.lua | 10 | ||||
-rw-r--r-- | src/luaotfload-features.lua | 172 | ||||
-rw-r--r-- | src/luaotfload-loaders.lua | 12 | ||||
-rw-r--r-- | src/luaotfload-main.lua | 2 |
6 files changed, 96 insertions, 191 deletions
@@ -6,7 +6,8 @@ Change History * Glyph fallbacks. * Latest fontloader code. * Adapt packaging to changed upstream file layout. - * Remove support for builtin Fontforge libraries. + * Remove support for builtin Fontforge libraries (this includes the PFA, + PFB, and feature file readers). 2015/12/09, luaotfload v2.6 * Add ``sign`` target to makefile for automated package signing. diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index fdca3c0..c418991 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -584,38 +584,6 @@ obviously, \inlinecode{random}. defaulting to \inlinecode{dflt}. \endaltitem - \beginaltitem {featurefile} - A comma-separated list of feature files to be applied to the - font. - % - Feature files contain a textual representation of - \OpenType tables and extend the features of a font - on fly. - % - After they are applied to a font, features defined in a - feature file can be enabled or disabled just like any - other font feature. - % - The syntax is documented in \identifier{Adobe}’s - \OpenType Feature File Specification.\footnote{% - Cf. \hyperlink {http://www.adobe.com/devnet/opentype/afdko/topic_feature_file_syntax.html}. - Feature file support is part of the engine which at the - time of this writing (2014) implements the spec only - partially. - See the - \hyperlink [\LUATEX tracker]{http://tracker.luatex.org/view.php?id=231} - for details. - } - - For a demonstration of how to set a \inlinecode{tkrn} feature consult - the file \inlinecode{tkrn.fea} that is part of \identifier{luaotfload}. - It can be read and applied as follows: - - \beginlisting - \font \test = Latin Modern Roman:featurefile=tkrn.fea;+tkrn - \endlisting - \endaltitem - \beginaltitem {color} A font color, defined as a triplet of two-digit hexadecimal \abbrev{rgb} values, with an optional fourth value for @@ -816,6 +784,8 @@ advance as well as a special \emphasis{request syntax}. Furthermore, this allows to define \emphasis{fallback fonts} to supplement fonts that may lack certain required glyphs. +\beginsubsection {Fallbacks} + For example, the \identifier{Latin Modern} family of fonts does, as indicated in the name, not provide Cyrillic glyphs. If Latin script dominates in the copy with interspersed Cyrillic, a fallback can be created from a similiar looking @@ -832,7 +802,59 @@ that it too derives from Knuth’s original \identifier{Computer Modern} series: \bye \endlisting -TODO +As simple as this may look on the first glance, this approach is entirely +inappropriate if more than a couple letters are required from a different font. +Because the combination pulls nothing except the glyph data, all of the +important other information that constitute a proper font -- kerning, styles, +features, and suchlike -- will be missing. + +\endsubsection %% Fallbacks + +\beginsubsection {Combinations} + +Generalizing the idea of a \emphasis{fallback font}, it is also possible to +pick definite sets of glyphs from multiple fonts. On a bad day, for instance, +it may be the sanest choice to start out with \identifier{EB Garamond} italics, +typeset all decimal digits in the bold italics of \identifier{GNU Freefont}, +and tone down the punctuation with extra thin glyphs from \identifier{Source +Sans}: + +\beginlisting + \def \feats {-tlig;-liga;mode=base;-kern} + \def \fileone {EBGaramond12-Italic.otf} + \def \filetwo {FreeMonoBoldOblique.otf} + \def \filethree {SourceSansPro-ExtraLight.otf} + + \input luaotfload.sty + + \font \one = file:\fileone :\feats + \font \two = file:\filetwo :\feats + \font \three = file:\filethree:\feats + + \font \onetwothree = "combo: 1 -> \fontid\one; + 2 -> \fontid\two, 0x30-0x39; + 3 -> \fontid\three, 0x21*0x3f; + + {\onetwothree \TeX—0123456789—?!} + \bye +\endlisting + +\noindent Despite the atrocious result, the example demonstrates well the +syntax that is used to specify ranges and fonts. Fonts are being referred to by +their internal index which can be obtained by passing the font command into the +\texmacro{fontid} macro, e. g. \inlinecode{\fontid\one}, after a font has been +defined. The first component of the combination is the base font which will be +extended by the others. It is specified by the index alone. + +All further fonts require either the literal \inlinecode{fallback} or a list of +codepoint definitions to be appended after a comma. The elements of this list +again denote either single codepoints like \inlinecode{0x21} (referring to the +exclamation point character) or ranges of codepoints (\inlinecode{0x30-0x39}). +Elements are separated by the \identifier{ASCII} asterisk character +(\inlinecode{*}). The characters referenced in the list will be imported from +the respective font, if available. + +\endsubsection %% Combinations \endsection diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index 35f8f2b..3d300e7 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -42,7 +42,15 @@ local luaotfload_callbacks = { } --- https://github.com/khaledhosny/luaotfload/issues/54 local rewrite_fontname = function (tfmdata, specification) - tfmdata.name = [["]] .. specification .. [["]] + local format = tfmdata.format or tfmdata.properties.format + if format ~= "type1" then + if stringfind (specification, " ") then + tfmdata.name = stringformat ("%q", specification) + else + --- other specs should parse just fine + tfmdata.name = specification + end + end end local rewriting = false diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 79f1416..5e9bf7b 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -1322,146 +1322,6 @@ local noflags = { false, false, false, false } local tohash = table.tohash -local function ancient_addfeature (data, feature, specifications) - local descriptions = data.descriptions - local resources = data.resources - local lookups = resources.lookups - local gsubfeatures = resources.features.gsub - if gsubfeatures and gsubfeatures[feature] then - -- already present - else - local sequences = resources.sequences - local fontfeatures = resources.features - local unicodes = resources.unicodes - local lookuptypes = resources.lookuptypes - local splitter = lpeg.splitter(" ",unicodes) - local done = 0 - local skip = 0 - if not specifications[1] then - -- so we accept a one entry specification - specifications = { specifications } - end - -- subtables are tables themselves but we also accept flattened singular subtables - for s=1,#specifications do - local specification = specifications[s] - local valid = specification.valid - if not valid or valid(data,specification,feature) then - local initialize = specification.initialize - if initialize then - -- when false is returned we initialize only once - specification.initialize = initialize(specification) and initialize or nil - end - local askedfeatures = specification.features or everywhere - local subtables = specification.subtables or { specification.data } or { } - local featuretype = types[specification.type or "substitution"] - local featureflags = specification.flags or noflags - local featureorder = specification.order or { feature } - local added = false - local featurename = stringformat("ctx_%s_%s",feature,s) - local st = { } - for t=1,#subtables do - local list = subtables[t] - local full = stringformat("%s_%s",featurename,t) - st[t] = full - if featuretype == "gsub_ligature" then - lookuptypes[full] = "ligature" - for code, ligature in next, list do - local unicode = tonumber(code) or unicodes[code] - local description = descriptions[unicode] - if description then - local slookups = description.slookups - if type(ligature) == "string" then - ligature = { lpegmatch(splitter,ligature) } - end - local present = true - for i=1,#ligature do - if not descriptions[ligature[i]] then - present = false - break - end - end - if present then - if slookups then - slookups[full] = ligature - else - description.slookups = { [full] = ligature } - end - done, added = done + 1, true - else - skip = skip + 1 - end - end - end - elseif featuretype == "gsub_single" then - lookuptypes[full] = "substitution" - for code, replacement in next, list do - local unicode = tonumber(code) or unicodes[code] - local description = descriptions[unicode] - if description then - local slookups = description.slookups - replacement = tonumber(replacement) or unicodes[replacement] - if descriptions[replacement] then - if slookups then - slookups[full] = replacement - else - description.slookups = { [full] = replacement } - end - done, added = done + 1, true - end - end - end - end - end - if added then - -- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... } - for k, v in next, askedfeatures do - if v[1] then - askedfeatures[k] = tabletohash(v) - end - end - local sequence = { - chain = 0, - features = { [feature] = askedfeatures }, - flags = featureflags, - name = featurename, - order = featureorder, - subtables = st, - type = featuretype, - } - if specification.prepend then - insert(sequences,1,sequence) - else - insert(sequences,sequence) - end - -- register in metadata (merge as there can be a few) - if not gsubfeatures then - gsubfeatures = { } - fontfeatures.gsub = gsubfeatures - end - local k = gsubfeatures[feature] - if not k then - k = { } - gsubfeatures[feature] = k - end - for script, languages in next, askedfeatures do - local kk = k[script] - if not kk then - kk = { } - k[script] = kk - end - for language, value in next, languages do - kk[language] = value - end - end - end - end - end - if trace_loading then - report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip) - end - end -end - local function current_addfeature(data,feature,specifications) local descriptions = data.descriptions local resources = data.resources @@ -1856,19 +1716,29 @@ end otf.addfeature = add_otf_feature local install_extra_features = function (data, filename, raw) + local metadata = data and data.metadata + if not metadata then + logreport ("both", 4, "features", + "no metadata received from font “%s”; not \z + installing extra features.", filename) + return + end + local format = data.format + if not format then + logreport ("both", 4, "features", + "no format info for font “%s”/“%s”; not \z + installing extra features.", + fontname, filename) + return + end for feature, specification in next, extrafeatures do - local fontname - local subfont - local metadata = data.metadata - if metadata then - fontname = tostring (data.metadata.fontname) - subfont = tonumber (metadata.subfontindex) - end if not fontname then fontname = "<unknown>" end if not subfont then subfont = -1 end + local fontname = tostring (data.metadata.fontname) or "<unknown>" + local subfont = tonumber (metadata.subfontindex) or -1 logreport ("both", 3, "features", "register synthetic feature “%s” for %s font “%s”(%d)", - feature, data.format, fontname, subfont) + feature, format, fontname, subfont) otf.features.register { name = feature, description = specification[2] } otf.enhancers.addfeature (data, feature, specification[1]) end @@ -1887,11 +1757,7 @@ return { end otf = fonts.handlers.otf - - --- hack for backwards compat with TL2014 loader - otf.enhancers.addfeature = otf.version < 2.8 and ancient_addfeature - or current_addfeature - + otf.enhancers.addfeature = current_addfeature otf.enhancers.register ("check extra features", install_extra_features) diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index fb01821..d3828aa 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -41,6 +41,14 @@ local eval_reader = function (specification) return eval () end +local unsupported_reader = function (format) + return function (specification) + logreport ("both", 0, "loaders", + "font format “%s” unsupported; cannot load %s.", + format, tostring (specification.name)) + end +end + local install_formats = function () local fonts = fonts if not fonts then return false end @@ -72,8 +80,8 @@ local install_formats = function () return aux ("evl", eval_reader) and aux ("lua", lua_reader) - and aux ("pfa", function (spec) return readers.opentype (spec, "pfa", "type1") end) - and aux ("pfb", function (spec) return readers.opentype (spec, "pfb", "type1") end) + and aux ("pfa", unsupported_reader "pfa") + and aux ("pfb", unsupported_reader "pfb") and aux ("ofm", readers.tfm) end diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 3f1f602..92c1ff1 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -13,7 +13,7 @@ local luaotfload = luaotfload luaotfload.log = luaotfload.log or { } luaotfload.version = "2.7" luaotfload.loaders = { } -luaotfload.min_luatex_version = 95 --- i. e. 0.80 +luaotfload.min_luatex_version = 95 --- i. e. 0.95 luaotfload.fontloader_package = "reference" --- default: from current Context local authors = "\z |