From 2ec3fd45d2e7b0c1b304e47ef01532a848acc73e Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 26 Jan 2014 19:17:23 +0100 Subject: [db] fall back to alternative bold-ish weights if a family lacks entries for bold Closing issue #177 This adds an extra pass to the family group builder. The lookup though stays the same as before. --- luaotfload-database.lua | 201 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 154 insertions(+), 47 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index c979acf..dcf5c86 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -2450,10 +2450,8 @@ local check_regular do local splitfontname = lpeg.splitat "-" - local choose_exact = function (field, weight) - local i = false - local b = false - + local choose_exact = function (field) + --- only clean matches, without guessing if italic_synonym [field] then return "i" end @@ -2466,36 +2464,39 @@ do return "bi" end - if weight == 700 then - --- matches only if weight is specified - return "b" - end - return false end pick_style = function (fontstyle_name, prefmodifiers, subfamily, - splitstyle, - weight) + splitstyle) local style if fontstyle_name then - style = choose_exact (fontstyle_name --[[ , weight ]]) + style = choose_exact (fontstyle_name) end if not style then if prefmodifiers then - style = choose_exact (prefmodifiers --[[ , weight ]]) + style = choose_exact (prefmodifiers) elseif subfamily then - style = choose_exact (subfamily, weight) + style = choose_exact (subfamily) end end --- if not style and splitstyle then --- style = choose_exact (splitstyle) --- end return style end + pick_fallback_style = function (italicangle, weight) + --- more aggressive, but only to determine bold faces + if weight > 500 then --- bold spectrum matches + if italicangle == 0 then + return tostring (weight) + else + return tostring (weight) .. "i" + end + end + return false + end + --- we use only exact matches here since there are constructs --- like “regularitalic” (Cabin, Bodoni Old Fashion) @@ -2573,28 +2574,25 @@ local add_family = function (name, subtable, modifier, entry) subtable [name] = familytable end - --- the style table is treated as an unordered list - local styletable = familytable [modifier] - if not styletable then - styletable = { } - familytable [modifier] = styletable - end + local size = entry.size - if not entry.prefmodifiers then --- default size for this style/family combo - styletable.default = entry.index - end + familytable [#familytable + 1] = { + index = entry.index, + size = size and { size [1], size [2], size [3] }, + modifier = modifier, + weight = entry.weight, + } +end - local size = entry.size --- dsnsize * high * low - if size then - styletable [#styletable + 1] = { - size [1], - size [2], - size [3], - entry.index, - } - else - styletable.default = entry.index +local get_subtable = function (families, entry) + local location = entry.location + local format = entry.format + local subtable = families [location] [format] + if not subtable then + subtable = { } + families [location] [format] = subtable end + return subtable end local collect_families = function (mappings) @@ -2615,14 +2613,7 @@ local collect_families = function (mappings) pull_values (entry) end - local location = entry.location - local format = entry.format - - local subtable = families [location] [format] - if not subtable then - subtable = { } - families [location] [format] = subtable - end + local subtable = get_subtable (families, entry) local familyname = entry.familyname local metafamily = entry.metafamily @@ -2637,8 +2628,7 @@ local collect_families = function (mappings) local modifier = pick_style (fontstyle_name, prefmodifiers, subfamily, - splitstyle, - weight) + splitstyle) if not modifier then --- regular, exact only modifier = check_regular (fontstyle_name, @@ -2674,6 +2664,11 @@ local collect_families = function (mappings) -- if metafamily and metafamily ~= familyname then -- add_family (metafamily, subtable, modifier, entry) -- end + elseif weight > 500 then -- in bold spectrum + modifier = pick_fallback_style (italicangle, weight) + if modifier then + add_family (familyname, subtable, modifier, entry) + end end end @@ -2681,6 +2676,116 @@ local collect_families = function (mappings) return families end +--[[doc-- + + add_bold_spectrum -- For not-quite-bold faces, determine whether + they can fill in for a missing bold face slot in a matching family. + + Some families like Lucida do not contain real bold / bold italic + members. Instead, they have semibold variants at weight 600 which + we must add in a separate pass. + +--doc]]-- + +local bold_spectrum_low = 501 --- 500 is medium, 900 heavy/black +local bold_weight = 700 +local style_categories = { "r", "b", "i", "bi" } +local bold_categories = { "b", "bi" } + +local group_modifiers = function (mappings, families) + report ("info", 2, "db", "Analyzing bold weight fallbacks.") + for location, location_data in next, families do + for format, format_data in next, location_data do + for familyname, collected in next, format_data do + local styledata = { } --- will replace the “collected” table + --- First, fill in the ordinary style data that + --- fits neatly into the four relevant modifier + --- categories. + for _, modifier in next, style_categories do + local entries + for key, info in next, collected do + if info.modifier == modifier then + if not entries then + entries = { } + end + local index = info.index + local entry = mappings [index] + local size = entry.size + if size then + entries [#entries + 1] = { + size [1], + size [2], + size [3], + index, + } + else + entries.default = index + end + collected [key] = nil + end + styledata [modifier] = entries + end + end + + --- At this point the family set may still lack + --- entries for bold or bold italic. We will fill + --- those in using the modifier with the numeric + --- weight that is closest to bold (700). + if next (collected) then --- there are uncategorized entries + for _, modifier in next, bold_categories do + if not styledata [modifier] then + local closest + local minimum = 2^51 + for key, info in next, collected do + local info_modifier = tonumber (info.modifier) and "b" or "bi" + if modifier == info_modifier then + local index = info.index + local entry = mappings [index] + local weight = entry.weight + local diff = weight < 700 and 700 - weight or weight - 700 + if diff < minimum then + minimum = diff + closest = weight + end + end + end + if closest then + --- We know there is a substitute face for the modifier. + --- Now we scan the list again to extract the size data + --- in case the shape is available at multiple sizes. + local entries = { } + for key, info in next, collected do + local info_modifier = tonumber (info.modifier) and "b" or "bi" + if modifier == info_modifier then + local index = info.index + local entry = mappings [index] + local size = entry.size + if entry.weight == closest then + if size then + entries [#entries + 1] = { + size [1], + size [2], + size [3], + index, + } + else + entries.default = index + end + end + end + end + styledata [modifier] = entries + end + end + end + end + format_data [familyname] = styledata + end + end + end + return families +end + local cmp_sizes = function (a, b) return a [1] < b [1] end @@ -2969,7 +3074,9 @@ update_names = function (currentnames, force, dry_run) targetnames.files = generate_filedata (targetnames.mappings) --- pass 4: build family lookup table - targetnames.families = collect_families (targetnames.mappings) + targetnames.families = collect_families (targetnames.mappings) + targetnames.families = group_modifiers (targetnames.mappings, + targetnames.families) --- pass 5: order design size tables targetnames.families = order_design_sizes (targetnames.families) -- cgit v1.2.3