From 76a913948ef596f93a548004f70e933523d13baf Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 24 Apr 2016 13:50:49 +0200 Subject: [aux] fix features table access (issue #338) Fix #338 Due to the new loader, certain tables were relocated inside the fontdata structure. This would cause a crash with certain kinds of fonts, most notably those for which TeX metrics exist. Many thanks to @aminophen and @u-fischer for their help in tracking this down. --- src/luaotfload-auxiliary.lua | 76 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 17 deletions(-) (limited to 'src/luaotfload-auxiliary.lua') diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index 3d300e7..c927471 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -317,6 +317,12 @@ aux.name_of_slot = name_of_slot ----------------------------------------------------------------------- --- lots of arrowcode ahead +local get_features = function (tfmdata) + local resources = tfmdata.resources if not resources then return false end + local features = resources.features if not features then return false end + return features +end + --[[doc-- This function, modeled after “check_script()” from fontspec, returns true if in the given font, the script “asked_script” is accounted for in at @@ -325,13 +331,23 @@ least one feature. --- int -> string -> bool local provides_script = function (font_id, asked_script) + if not font_id or type (font_id) ~= "number" + or not asked_script or type (asked_script) ~= "string" + then + logreport ("both", 0, "aux", + "invalid parameters to provides_language(%s, %s)", + tostring (font_id), tostring (asked_script)) + return false + end asked_script = stringlower(asked_script) if font_id and font_id > 0 then - local tfmdata = identifiers[font_id] if not tfmdata then return false end - local shared = tfmdata.shared if not shared then return false end - local fontdata = shared.rawdata if not fontdata then return false end - local fontname = fontdata.metadata.fontname - local features = fontdata.resources.features + local tfmdata = identifiers[font_id] + if not tfmdata then return false end + local features = get_features (tfmdata) + if features == false then + logreport ("log", 1, "aux", "font no %d lacks a features table", font_id) + return false + end for method, featuredata in next, features do --- where method: "gpos" | "gsub" for feature, data in next, featuredata do @@ -362,14 +378,27 @@ feature. --- int -> string -> string -> bool local provides_language = function (font_id, asked_script, asked_language) - asked_script = stringlower(asked_script) - asked_language = stringlower(asked_language) + if not font_id or type (font_id) ~= "number" + or not asked_script or type (asked_script) ~= "string" + or not asked_language or type (asked_language) ~= "string" + then + logreport ("both", 0, "aux", + "invalid parameters to provides_language(%s, %s, %s)", + tostring (font_id), + tostring (asked_script), + tostring (asked_language)) + return false + end + asked_script = stringlower(asked_script) + asked_language = stringlower(asked_language) if font_id and font_id > 0 then - local tfmdata = identifiers[font_id] if not tfmdata then return false end - local shared = tfmdata.shared if not shared then return false end - local fontdata = shared.rawdata if not fontdata then return false end - local fontname = fontdata.metadata.fontname - local features = fontdata.resources.features + local tfmdata = identifiers[font_id] + if not tfmdata then return false end + local features = get_features (tfmdata) + if features == false then + logreport ("log", 1, "aux", "font no %d lacks a features table", font_id) + return false + end for method, featuredata in next, features do --- where method: "gpos" | "gsub" for feature, data in next, featuredata do @@ -432,16 +461,29 @@ accounted for in the script with tag “asked_script” in feature --- int -> string -> string -> string -> bool local provides_feature = function (font_id, asked_script, asked_language, asked_feature) + if not font_id or type (font_id) ~= "number" + or not asked_script or type (asked_script) ~= "string" + or not asked_language or type (asked_language) ~= "string" + or not asked_feature or type (asked_feature) ~= "string" + then + logreport ("both", 0, "aux", + "invalid parameters to provides_language(%s, %s, %s, %s)", + tostring (font_id), tostring (asked_script), + tostring (asked_language), tostring (asked_feature)) + return false + end asked_script = stringlower(asked_script) asked_language = stringlower(asked_language) asked_feature = lpegmatch(strip_garbage, asked_feature) if font_id and font_id > 0 then - local tfmdata = identifiers[font_id] if not tfmdata then return false end - local shared = tfmdata.shared if not shared then return false end - local fontdata = shared.rawdata if not fontdata then return false end - local features = fontdata.resources.features - local fontname = fontdata.metadata.fontname + local tfmdata = identifiers[font_id] + if not tfmdata then return false end + local features = get_features (tfmdata) + if features == false then + logreport ("log", 1, "aux", "font no %d lacks a features table", font_id) + return false + end for method, featuredata in next, features do --- where method: "gpos" | "gsub" local feature = featuredata[asked_feature] -- cgit v1.2.3 From 8c3e40f3dc42ec1b5b6cce8f7ee5bbe7b66ddfd0 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 24 Apr 2016 14:06:06 +0200 Subject: [aux] make slot_of_name API more robust --- src/luaotfload-auxiliary.lua | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'src/luaotfload-auxiliary.lua') diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index c927471..fc2a191 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -263,20 +263,27 @@ end --- int -> string -> bool -> (int | false) local slot_of_name = function (font_id, glyphname, unsafe) - local fontdata = identifiers[font_id] - if fontdata then - local unicode = fontdata.resources.unicodes[glyphname] - if unicode then - if type(unicode) == "number" then - return unicode - else - return unicode[1] --- for multiple components - end --- else --- --- missing + if not font_id or type (font_id) ~= "number" + or not glyphname or type (glyphname) ~= "string" + then + logreport ("both", 0, "aux", + "invalid parameters to slot_of_name (%s, %s)", + tostring (font_id), tostring (glyphname)) + return false + end + + local tfmdata = identifiers [font_id] + if not tfmdata then return raw_slot_of_name (font_id, glyphname) end + local resources = tfmdata.resources if not resources then return false end + local unicodes = resources.unicodes if not unicodes then return false end + + local unicode = unicodes [glyphname] + if unicode then + if type (unicode) == "number" then + return unicode + else + return unicode [1] --- for multiple components end - elseif unsafe == true then -- for Robert - return raw_slot_of_name(font_id, glyphname) end return false end @@ -335,7 +342,7 @@ local provides_script = function (font_id, asked_script) or not asked_script or type (asked_script) ~= "string" then logreport ("both", 0, "aux", - "invalid parameters to provides_language(%s, %s)", + "invalid parameters to provides_script(%s, %s)", tostring (font_id), tostring (asked_script)) return false end @@ -467,7 +474,7 @@ local provides_feature = function (font_id, asked_script, or not asked_feature or type (asked_feature) ~= "string" then logreport ("both", 0, "aux", - "invalid parameters to provides_language(%s, %s, %s, %s)", + "invalid parameters to provides_feature(%s, %s, %s, %s)", tostring (font_id), tostring (asked_script), tostring (asked_language), tostring (asked_feature)) return false -- cgit v1.2.3 From 61fcc90e47c36c7c8c8bf4a5d46c649942886462 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 24 Apr 2016 14:12:28 +0200 Subject: [aux] make name_of_slot API more robust --- src/luaotfload-auxiliary.lua | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src/luaotfload-auxiliary.lua') diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index fc2a191..347d9f8 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -305,11 +305,23 @@ local indices --- int -> (string | false) local name_of_slot = function (codepoint) + if not codepoint or type (codepoint) ~= "number" then + logreport ("both", 0, "aux", + "invalid parameters to name_of_slot (%s)", + tostring (codepoint)) + return false + end + if not indices then --- this will load the glyph list local unicodes = encodings.agl.unicodes - indices = table.swapped(unicodes) + if not unicodes or not next (unicodes)then + logreport ("both", 0, "aux", + "name_of_slot: failed to load the AGL.") + end + indices = table.swapped (unicodes) end - local glyphname = indices[codepoint] + + local glyphname = indices [codepoint] if glyphname then return glyphname end -- cgit v1.2.3 From 5efcb3555bd11f7caf6bc28d5eae8b0d4ae83026 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 26 Apr 2016 00:22:34 +0200 Subject: [aux] fix \fontdimen8 hack Addresses #341 This cleans up the font patching code we inherited from Fontspec. In addition to treating the bitrot with an extra dose of fungicide, we also make the process in which the final values are chosen more transparent. --- src/luaotfload-auxiliary.lua | 94 +++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 31 deletions(-) (limited to 'src/luaotfload-auxiliary.lua') diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index 347d9f8..22f8201 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -177,40 +177,72 @@ Comment from fontspec: --doc]]-- +local capheight_reference_char = stringbyte "X" -- might be ‘M’, ‘Ж’, or ‘ξ’. + +local determine_capheight = function (fontdata) + local parameters = fontdata.parameters if not parameters then return false end + local characters = fontdata.characters if not characters then return false end + local refchar = characters [capheight_reference_char] + if refchar then + return refchar.height + end + return false +end + +local query_ascender = function (fontdata) + local parameters = fontdata.parameters if not parameters then return false end + local metadata = fontdata.metadata if not metadata then return false end + local ascender = metadata.ascender if not ascender then return false end + local units = metadata.units if units == 0 then return false end + local size = parameters.size if not size then return false end + return ascender * size / units +end + +local query_capheight = function (fontdata) + local parameters = fontdata.parameters if not parameters then return false end + local metadata = fontdata.metadata if not metadata then return false end + local capheight = metadata.capheight if not capheight then return false end + local units = metadata.units if units == 0 then return false end + local size = parameters.size if not size then return false end + return capheight * size / units +end + +local query_fontdimen8 = function (fontdata) + local parameters = fontdata.parameters if not parameters then return false end + local fontdimen8 = parameters [8] + if fontdimen8 then return fontdimen8 end + return false +end + +local caphtfmt = function (ref, ht) + if not ht then return "" end + if not ref then return tostring (ht) end + return stringformat ("%s(δ=%s)", ht, ht - ref) +end + local set_capheight = function (fontdata) - local shared = fontdata.shared - local parameters = fontdata.parameters - local capheight - if shared - and shared.rawdata.metadata - and shared.rawdata.metadata.pfminfo - then - local units_per_em = parameters.units - local size = parameters.size - local os2_capheight = shared.rawdata.metadata.pfminfo.os2_capheight - - if capheight and os2_capheight > 0 then - capheight = os2_capheight / units_per_em * size - else - local X8_str = stringbyte"X" - local X8_chr = fontdata.characters[X8_str] - if X8_chr then - capheight = X8_chr.height - else - capheight = parameters.ascender / units_per_em * size - end - end - else - local X8_str = stringbyte "X" - local X8_chr = fontdata.characters[X8_str] - if X8_chr then - capheight = X8_chr.height - end + if not fontdata then + logreport ("both", 0, "aux", + "error: set_capheight() received garbage") + return end + local capheight_dimen8 = query_fontdimen8 (fontdata) + local capheight_alleged = query_capheight (fontdata) + local capheight_ascender = query_ascender (fontdata) + local capheight_measured = determine_capheight (fontdata) + logreport ("term", 4, "aux", + "capht: param[8]=%s advertised=%s ascender=%s measured=%s", + tostring (capheight_dimen8), + caphtfmt (capheight_dimen8, capheight_alleged), + caphtfmt (capheight_dimen8, capheight_ascender), + caphtfmt (capheight_dimen8, capheight_measured)) + if capheight_dimen8 then --- nothing to do + return + end + + local capheight = capheight_alleged or capheight_ascender or capheight_measured if capheight then - --- is this legit? afaics there’s nothing else on the - --- array part of that table - fontdata.parameters[8] = capheight + fontdata.parameters [8] = capheight end end -- cgit v1.2.3 From 2a60462172f9e077e6df0887654a5e54fe4ce204 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 26 Apr 2016 00:36:52 +0200 Subject: [aux] probe multiple characters when guessing the capital height MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide fallbacks in case no ‘X’ character is available for capheight measurement. --- src/luaotfload-auxiliary.lua | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src/luaotfload-auxiliary.lua') diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index 22f8201..06821f6 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -177,14 +177,32 @@ Comment from fontspec: --doc]]-- -local capheight_reference_char = stringbyte "X" -- might be ‘M’, ‘Ж’, or ‘ξ’. +local capheight_reference_chars = { "X", "M", "Ж", "ξ", } +local capheight_reference_codepoints do + local utfbyte = unicode.utf8.byte + capheight_reference_codepoints = { } + for i = 1, #capheight_reference_chars do + local chr = capheight_reference_chars [i] + capheight_reference_codepoints [i] = utfbyte (chr) + end +end local determine_capheight = function (fontdata) local parameters = fontdata.parameters if not parameters then return false end local characters = fontdata.characters if not characters then return false end - local refchar = characters [capheight_reference_char] - if refchar then - return refchar.height + --- Pretty simplistic but it does return *some* value for most fonts; + --- we could also refine the approach to return some kind of average + --- of all capital letters or a user-provided subset. + for i = 1, #capheight_reference_codepoints do + local refcp = capheight_reference_codepoints [i] + local refchar = characters [refcp] + if refchar then + logreport ("both", 4, "aux", + "picked height of character ‘%s’ (U+%d) as \\fontdimen8 \z + candidate", + capheight_reference_chars [i], refcp) + return refchar.height + end end return false end -- cgit v1.2.3 From 73521a6f3d35b8cf0e4cfc5d57f32ee5b7d4d6d3 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 26 Apr 2016 08:15:07 +0200 Subject: [aux] actually pull capheight and ascender values from the correct table --- src/luaotfload-auxiliary.lua | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src/luaotfload-auxiliary.lua') diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index 06821f6..d6835a9 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -209,19 +209,24 @@ end local query_ascender = function (fontdata) local parameters = fontdata.parameters if not parameters then return false end - local metadata = fontdata.metadata if not metadata then return false end - local ascender = metadata.ascender if not ascender then return false end + local shared = fontdata.shared if not shared then return false end + local rawdata = shared.rawdata if not rawdata then return false end + local metadata = rawdata.metadata if not metadata then return false end + local ascender = parameters.ascender + or metadata.ascender if not ascender then return false end local units = metadata.units if units == 0 then return false end local size = parameters.size if not size then return false end return ascender * size / units end local query_capheight = function (fontdata) - local parameters = fontdata.parameters if not parameters then return false end - local metadata = fontdata.metadata if not metadata then return false end - local capheight = metadata.capheight if not capheight then return false end - local units = metadata.units if units == 0 then return false end - local size = parameters.size if not size then return false end + local parameters = fontdata.parameters if not parameters then return false end + local shared = fontdata.shared if not shared then return false end + local rawdata = shared.rawdata if not rawdata then return false end + local metadata = rawdata.metadata if not metadata then return false end + local capheight = metadata.capheight if not capheight then return false end + local units = metadata.units if units == 0 then return false end + local size = parameters.size if not size then return false end return capheight * size / units end -- cgit v1.2.3 From a62867edb4dc4b5d46fe2b8c34fa4f6dc7fddc5c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 26 Apr 2016 22:30:01 +0200 Subject: [aux] fix \fontdimen{10,114} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #341 Hironori Kitagawa pointed out that the patch for the other math parameters doesn’t work. Turns out Hans relocated the “mathconstants” table … --- src/luaotfload-auxiliary.lua | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'src/luaotfload-auxiliary.lua') diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index d6835a9..e544dd7 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -88,13 +88,12 @@ package. --doc]]-- local set_sscale_dimens = function (fontdata) - local mathconstants = fontdata.MathConstants - local parameters = fontdata.parameters - if mathconstants then - parameters[10] = mathconstants.ScriptPercentScaleDown or 70 - parameters[11] = mathconstants.ScriptScriptPercentScaleDown or 50 - end - return fontdata + local resources = fontdata.resources if not resources then return end + local mathconstants = resources.MathConstants if not mathconstants then return end + local parameters = fontdata.parameters if not parameters then return end + --- the default values below are complete crap + parameters [10] = mathconstants.ScriptPercentScaleDown or 70 + parameters [11] = mathconstants.ScriptScriptPercentScaleDown or 50 end luaotfload_callbacks [#luaotfload_callbacks + 1] = { @@ -104,8 +103,8 @@ luaotfload_callbacks [#luaotfload_callbacks + 1] = { --- fontobj -> int local lookup_units = function (fontdata) local metadata = fontdata.shared and fontdata.shared.rawdata.metadata - if metadata and metadata.units_per_em then - return metadata.units_per_em + if metadata and metadata.units then + return metadata.units elseif fontdata.parameters and fontdata.parameters.units then return fontdata.parameters.units elseif fontdata.units then --- v1.x @@ -122,9 +121,9 @@ local patch_cambria_domh = function (fontdata) local mathconstants = fontdata.MathConstants if mathconstants and fontdata.psname == "CambriaMath" then --- my test Cambria has 2048 - local units_per_em = fontdata.units_per_em or lookup_units(fontdata) - local sz = fontdata.parameters.size or fontdata.size - local mh = 2800 / units_per_em * sz + local units = fontdata.units or lookup_units(fontdata) + local sz = fontdata.parameters.size or fontdata.size + local mh = 2800 / units * sz if mathconstants.DisplayOperatorMinHeight < mh then mathconstants.DisplayOperatorMinHeight = mh end -- cgit v1.2.3